Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 9 Jul 2012 20:34:34 +0000 (16:34 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 9 Jul 2012 20:34:34 +0000 (16:34 -0400)
Conflicts:
net/mac80211/mlme.c

380 files changed:
Documentation/feature-removal-schedule.txt
MAINTAINERS
drivers/bcma/scan.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/target.h
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/antenna.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h
drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9340_initvals.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/mci.h
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/channel.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/dvm/Makefile [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/agn.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/calib.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/calib.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/commands.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/debugfs.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/dev.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/devices.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/led.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/led.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/lib.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/mac80211.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/main.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/power.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/power.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/rs.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/rs.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/rx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/rxon.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/scan.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/sta.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/testmode.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/tt.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/tt.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/tx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/dvm/ucode.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-1000.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-2000.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-5000.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-6000.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-calib.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-calib.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-devices.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-lib.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-rs.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-rs.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-rx.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-sta.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-tt.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-tt.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-tx.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-cfg.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-commands.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.c
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-dev.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-eeprom-read.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-eeprom-read.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-eeprom.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-eeprom.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-led.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-mac80211.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-notif-wait.c
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-pci.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-power.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-power.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-scan.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-test.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-test.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-testmode.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-ucode.c [deleted file]
drivers/net/wireless/iwlwifi/pcie/1000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/2000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/5000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/6000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/cfg.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/drv.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/internal.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/rx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/trans.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/pcie/tx.c [new file with mode: 0644]
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/orinoco/cfg.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800pci.h
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtlwifi/cam.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/ti/Kconfig
drivers/net/wireless/ti/Makefile
drivers/net/wireless/ti/wl1251/cmd.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wl1251/wl1251.h
drivers/net/wireless/ti/wl12xx/Makefile
drivers/net/wireless/ti/wl12xx/acx.h
drivers/net/wireless/ti/wl12xx/cmd.c
drivers/net/wireless/ti/wl12xx/debugfs.c [new file with mode: 0644]
drivers/net/wireless/ti/wl12xx/debugfs.h [new file with mode: 0644]
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl12xx/wl12xx.h
drivers/net/wireless/ti/wl18xx/Kconfig [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/Makefile [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/acx.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/acx.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/conf.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/debugfs.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/debugfs.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/io.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/io.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/main.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/reg.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/tx.c [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/tx.h [new file with mode: 0644]
drivers/net/wireless/ti/wl18xx/wl18xx.h [new file with mode: 0644]
drivers/net/wireless/ti/wlcore/acx.c
drivers/net/wireless/ti/wlcore/acx.h
drivers/net/wireless/ti/wlcore/boot.c
drivers/net/wireless/ti/wlcore/boot.h
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/cmd.h
drivers/net/wireless/ti/wlcore/conf.h
drivers/net/wireless/ti/wlcore/debugfs.c
drivers/net/wireless/ti/wlcore/debugfs.h
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/hw_ops.h
drivers/net/wireless/ti/wlcore/ini.h
drivers/net/wireless/ti/wlcore/init.c
drivers/net/wireless/ti/wlcore/io.c
drivers/net/wireless/ti/wlcore/io.h
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/ps.c
drivers/net/wireless/ti/wlcore/rx.c
drivers/net/wireless/ti/wlcore/rx.h
drivers/net/wireless/ti/wlcore/scan.c
drivers/net/wireless/ti/wlcore/scan.h
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/wireless/ti/wlcore/testmode.c
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/tx.h
drivers/net/wireless/ti/wlcore/wl12xx.h [deleted file]
drivers/net/wireless/ti/wlcore/wlcore.h
drivers/net/wireless/ti/wlcore/wlcore_i.h [new file with mode: 0644]
drivers/nfc/pn533.c
drivers/nfc/pn544_hci.c
drivers/ssb/b43_pci_bridge.c
drivers/ssb/scan.c
include/linux/bcma/bcma.h
include/linux/ieee80211.h
include/linux/nfc.h
include/linux/nl80211.h
include/linux/ssb/ssb.h
include/net/bluetooth/a2mp.h [new file with mode: 0644]
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/hci.h
include/net/nfc/nfc.h
include/net/nfc/shdlc.h
net/bluetooth/Makefile
net/bluetooth/a2mp.c [new file with mode: 0644]
net/bluetooth/af_bluetooth.c
net/bluetooth/bnep/core.c
net/bluetooth/bnep/netdev.c
net/bluetooth/bnep/sock.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/hidp/sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/core/net-sysfs.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debug.h [new file with mode: 0644]
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.c [deleted file]
net/mac80211/driver-trace.h [deleted file]
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mesh_sync.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tkip.c
net/mac80211/trace.c [new file with mode: 0644]
net/mac80211/trace.h [new file with mode: 0644]
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/wme.h
net/mac80211/work.c [deleted file]
net/nfc/core.c
net/nfc/hci/core.c
net/nfc/hci/shdlc.c
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/nfc/llcp/llcp.h
net/nfc/llcp/sock.c
net/nfc/nci/core.c
net/nfc/netlink.c
net/nfc/nfc.h
net/rfkill/core.c
net/wireless/Kconfig
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c

index 56000b33340bbe33f0b141934c756470d32ecbbd..dec901554ef7d58d8ad9de35431017e51b22a2fa 100644 (file)
@@ -249,15 +249,6 @@ Who:       Ravikiran Thirumalai <kiran@scalex86.org>
 
 ---------------------------
 
-What:  Code that is now under CONFIG_WIRELESS_EXT_SYSFS
-       (in net/core/net-sysfs.c)
-When:  3.5
-Why:   Over 1K .text/.data size reduction, data is available in other
-       ways (ioctls)
-Who:   Johannes Berg <johannes@sipsolutions.net>
-
----------------------------
-
 What:  sysfs ui for changing p4-clockmod parameters
 When:  September 2009
 Why:   See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
@@ -449,6 +440,19 @@ Who:       Hans Verkuil <hans.verkuil@cisco.com>
 
 ----------------------------
 
+What:  CONFIG_CFG80211_WEXT
+When:  as soon as distributions ship new wireless tools, ie. wpa_supplicant 1.0
+       and NetworkManager/connman/etc. that are able to use nl80211
+Why:   Wireless extensions are deprecated, and userland tools are moving to
+       using nl80211. New drivers are no longer using wireless extensions,
+       and while there might still be old drivers, both new drivers and new
+       userland no longer needs them and they can't be used for an feature
+       developed in the past couple of years. As such, compatibility with
+       wireless extensions in new drivers will be removed.
+Who:   Johannes Berg <johannes@sipsolutions.net>
+
+----------------------------
+
 What:  g_file_storage driver
 When:  3.8
 Why:   This driver has been superseded by g_mass_storage.
index 03660de94cf7608edddbdfbd1bc71621bfcad9e0..fe6dd3d7d2c410ede875ec3c0e3f7c97355d7cdc 100644 (file)
@@ -329,7 +329,7 @@ F:  drivers/hwmon/adm1029.c
 
 ADM8211 WIRELESS DRIVER
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/
+W:     http://wireless.kernel.org/
 S:     Orphan
 F:     drivers/net/wireless/adm8211.*
 
@@ -1423,7 +1423,7 @@ B43 WIRELESS DRIVER
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 L:     linux-wireless@vger.kernel.org
 L:     b43-dev@lists.infradead.org
-W:     http://linuxwireless.org/en/users/Drivers/b43
+W:     http://wireless.kernel.org/en/users/Drivers/b43
 S:     Maintained
 F:     drivers/net/wireless/b43/
 
@@ -1432,7 +1432,7 @@ M:        Larry Finger <Larry.Finger@lwfinger.net>
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 L:     linux-wireless@vger.kernel.org
 L:     b43-dev@lists.infradead.org
-W:     http://linuxwireless.org/en/users/Drivers/b43
+W:     http://wireless.kernel.org/en/users/Drivers/b43
 S:     Maintained
 F:     drivers/net/wireless/b43legacy/
 
@@ -1595,6 +1595,7 @@ M:        Arend van Spriel <arend@broadcom.com>
 M:     Franky (Zhenhui) Lin <frankyl@broadcom.com>
 M:     Kan Yan <kanyan@broadcom.com>
 L:     linux-wireless@vger.kernel.org
+L:     brcm80211-dev-list@broadcom.com
 S:     Supported
 F:     drivers/net/wireless/brcm80211/
 
@@ -4342,7 +4343,7 @@ F:        arch/m68k/hp300/
 MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/
+W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:     Maintained
@@ -4354,7 +4355,7 @@ MAC80211 PID RATE CONTROL
 M:     Stefano Brivio <stefano.brivio@polimi.it>
 M:     Mattias Nissler <mattias.nissler@gmx.de>
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
+W:     http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:     Maintained
@@ -5032,7 +5033,7 @@ F:        fs/ocfs2/
 
 ORINOCO DRIVER
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/en/users/Drivers/orinoco
+W:     http://wireless.kernel.org/en/users/Drivers/orinoco
 W:     http://www.nongnu.org/orinoco/
 S:     Orphan
 F:     drivers/net/wireless/orinoco/
@@ -5737,7 +5738,7 @@ F:        net/rose/
 RTL8180 WIRELESS DRIVER
 M:     "John W. Linville" <linville@tuxdriver.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/
+W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
 F:     drivers/net/wireless/rtl818x/rtl8180/
@@ -5747,7 +5748,7 @@ M:        Herton Ronaldo Krzesinski <herton@canonical.com>
 M:     Hin-Tak Leung <htl10@users.sourceforge.net>
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/
+W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
 F:     drivers/net/wireless/rtl818x/rtl8187/
@@ -5756,7 +5757,7 @@ RTL8192CE WIRELESS DRIVER
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 M:     Chaoming Li <chaoming_li@realsil.com.cn>
 L:     linux-wireless@vger.kernel.org
-W:     http://linuxwireless.org/
+W:     http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
 F:     drivers/net/wireless/rtlwifi/
index 5ed0718fc66056a9ddb32976f6e5927fca8df573..a3420585d942e2ea9b953852528bcc54f8cc881a 100644 (file)
@@ -28,6 +28,12 @@ static const struct bcma_device_id_name bcma_arm_device_names[] = {
 
 static const struct bcma_device_id_name bcma_bcm_device_names[] = {
        { BCMA_CORE_OOB_ROUTER, "OOB Router" },
+       { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
+       { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
+       { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
+       { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
+       { BCMA_CORE_ALTA, "ALTA (I2S)" },
+       { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
        { BCMA_CORE_INVALID, "Invalid" },
        { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
        { BCMA_CORE_ILINE20, "ILine 20" },
index 1fcd92380356bb70571a573cb105778d06712237..585c88e018932fa9d9b6c46048be42678c535cec 100644 (file)
@@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
-               register unsigned int offset;
-               register unsigned char command;
-               register unsigned long ready_bit;
+               unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int offset;
+               unsigned char command;
+               unsigned long ready_bit;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index 609861a53c28445ef90670788e6a45b43c81949f..29caaed2d715bd6de4f8b355bc8bc11b9580a7b6 100644 (file)
@@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        hdev->flush    = bpa10x_flush;
        hdev->send     = bpa10x_send_frame;
 
-       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+       set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        err = hci_register_dev(hdev);
        if (err < 0) {
index 308c8599ab55ca480c364cab3b40bc6f41d94faf..b2b0fbbb43b5dd152878747b9befdf6fc27f5418 100644 (file)
@@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
                return;
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                if (!pcmcia_dev_present(info->p_dev))
                        break;
index 0cd61d9f07cdb1d1d70c8dfc0d2e52c239903402..cf7588edba0d2760a6778589f033953f3ad083fc 100644 (file)
@@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
        /* Marvell SD8787 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
                        .driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
+       /* Marvell SD8787 Bluetooth AMP device */
+       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
+                       .driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
        /* Marvell SD8797 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
                        .driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
index c4fc2f3fc32cad477afb98051100f4bc9d023b3f..65b8d996840c286ab69ac2434f699c6eff015b2e 100644 (file)
@@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index 83ebb241bfcc8bbd1f279875141f58325bbd09c3..e272214110365510fcfcbb6f6f3f75778f65ed46 100644 (file)
  *
  */
 
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/skbuff.h>
-
 #include <linux/usb.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -1028,7 +1020,7 @@ static int btusb_probe(struct usb_interface *intf,
        data->isoc = usb_ifnum_to_if(data->udev, 1);
 
        if (!reset)
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
                if (!disable_scofix)
@@ -1040,7 +1032,7 @@ static int btusb_probe(struct usb_interface *intf,
 
        if (id->driver_info & BTUSB_DIGIANSWER) {
                data->cmdreq_type = USB_TYPE_VENDOR;
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
        }
 
        if (id->driver_info & BTUSB_CSR) {
@@ -1048,7 +1040,7 @@ static int btusb_probe(struct usb_interface *intf,
 
                /* Old firmware would otherwise execute USB reset */
                if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
-                       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+                       set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
        }
 
        if (id->driver_info & BTUSB_SNIFFER) {
index 6e8d9618968443df06710d52666aaf5e5c2af3bd..b1b37ccd3cd489ad41117e2293040df4784eed31 100644 (file)
@@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
        }
 
        do {
-               register unsigned int iobase = info->p_dev->resource[0]->start;
+               unsigned int iobase = info->p_dev->resource[0]->start;
                register struct sk_buff *skb;
-               register int len;
+               int len;
 
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
index 661a8dc4d2f8b346e390053ee45d63cb7249346e..57e502e0608058ca9943b7cf5c14613339562729 100644 (file)
@@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp)
 static int bcsp_recv(struct hci_uart *hu, void *data, int count)
 {
        struct bcsp_struct *bcsp = hu->priv;
-       register unsigned char *ptr;
+       unsigned char *ptr;
 
        BT_DBG("hu %p count %d rx_state %d rx_count %ld", 
                hu, count, bcsp->rx_state, bcsp->rx_count);
index 748329468d26ca6432f6e04dc2d2ab92afd62e4f..c60623f206d4d255b59a29ea4de209a014e28421 100644 (file)
@@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
 {
-       register int room = skb_tailroom(h4->rx_skb);
+       int room = skb_tailroom(h4->rx_skb);
 
        BT_DBG("len %d room %d", len, room);
 
index e564579a6115989cb7857ca298eaee4ab43ca2ec..2f9b796e106e501ab0c2cbf243c2d52977ec6d0f 100644 (file)
@@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
                set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
        if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
-               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
 
        if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
                hdev->dev_type = HCI_AMP;
index b874c0efde247be90f38d0a2772813ea56fd6afa..ff6d589c34a5e900eff0eb498782f5597a6a8bee 100644 (file)
@@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 
 static inline int ll_check_data_len(struct ll_struct *ll, int len)
 {
-       register int room = skb_tailroom(ll->rx_skb);
+       int room = skb_tailroom(ll->rx_skb);
 
        BT_DBG("len %d room %d", len, room);
 
@@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len)
 static int ll_recv(struct hci_uart *hu, void *data, int count)
 {
        struct ll_struct *ll = hu->priv;
-       register char *ptr;
+       char *ptr;
        struct hci_event_hdr *eh;
        struct hci_acl_hdr   *ah;
        struct hci_sco_hdr   *sh;
-       register int len, type, dlen;
+       int len, type, dlen;
 
        BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
 
index b869a358ce4366276735f375b1d61366ac8631dc..fd7dbd4609df3c6da9595a7bf5239cd7932d57fd 100644 (file)
 
 #define DEFAULT_BG_SCAN_PERIOD 60
 
+struct ath6kl_cfg80211_match_probe_ssid {
+       struct cfg80211_ssid ssid;
+       u8 flag;
+};
+
 static struct ieee80211_rate ath6kl_rates[] = {
        RATETAB_ENT(10, 0x1, 0),
        RATETAB_ENT(20, 0x2, 0),
@@ -576,6 +581,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
        vif->nw_type = vif->next_mode;
 
+       /* enable enhanced bmiss detection if applicable */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, true);
+
        if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
                nw_subtype = SUBTYPE_P2PCLIENT;
 
@@ -852,20 +860,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                }
        }
 
-       /*
-        * Send a disconnect command to target when a disconnect event is
-        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
-        * request from host) to make the firmware stop trying to connect even
-        * after giving disconnect event. There will be one more disconnect
-        * event for this disconnect command with reason code DISCONNECT_CMD
-        * which will be notified to cfg80211.
-        */
-
-       if (reason != DISCONNECT_CMD) {
-               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
-               return;
-       }
-
        clear_bit(CONNECT_PEND, &vif->flags);
 
        if (vif->sme_state == SME_CONNECTING) {
@@ -875,32 +869,96 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
                                        GFP_KERNEL);
        } else if (vif->sme_state == SME_CONNECTED) {
-               cfg80211_disconnected(vif->ndev, reason,
+               cfg80211_disconnected(vif->ndev, proto_reason,
                                      NULL, 0, GFP_KERNEL);
        }
 
        vif->sme_state = SME_DISCONNECTED;
+
+       /*
+        * Send a disconnect command to target when a disconnect event is
+        * received with reason code other than 3 (DISCONNECT_CMD - disconnect
+        * request from host) to make the firmware stop trying to connect even
+        * after giving disconnect event. There will be one more disconnect
+        * event for this disconnect command with reason code DISCONNECT_CMD
+        * which won't be notified to cfg80211.
+        */
+       if (reason != DISCONNECT_CMD)
+               ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx);
 }
 
 static int ath6kl_set_probed_ssids(struct ath6kl *ar,
                                   struct ath6kl_vif *vif,
-                                  struct cfg80211_ssid *ssids, int n_ssids)
+                                  struct cfg80211_ssid *ssids, int n_ssids,
+                                  struct cfg80211_match_set *match_set,
+                                  int n_match_ssid)
 {
-       u8 i;
+       u8 i, j, index_to_add, ssid_found = false;
+       struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS];
 
-       if (n_ssids > MAX_PROBED_SSID_INDEX)
+       memset(ssid_list, 0, sizeof(ssid_list));
+
+       if (n_ssids > MAX_PROBED_SSIDS ||
+           n_match_ssid > MAX_PROBED_SSIDS)
                return -EINVAL;
 
        for (i = 0; i < n_ssids; i++) {
+               memcpy(ssid_list[i].ssid.ssid,
+                      ssids[i].ssid,
+                      ssids[i].ssid_len);
+               ssid_list[i].ssid.ssid_len = ssids[i].ssid_len;
+
+               if (ssids[i].ssid_len)
+                       ssid_list[i].flag = SPECIFIC_SSID_FLAG;
+               else
+                       ssid_list[i].flag = ANY_SSID_FLAG;
+
+               if (n_match_ssid == 0)
+                       ssid_list[i].flag |= MATCH_SSID_FLAG;
+       }
+
+       index_to_add = i;
+
+       for (i = 0; i < n_match_ssid; i++) {
+               ssid_found = false;
+
+               for (j = 0; j < n_ssids; j++) {
+                       if ((match_set[i].ssid.ssid_len ==
+                            ssid_list[j].ssid.ssid_len) &&
+                           (!memcmp(ssid_list[j].ssid.ssid,
+                                    match_set[i].ssid.ssid,
+                                    match_set[i].ssid.ssid_len))) {
+                               ssid_list[j].flag |= MATCH_SSID_FLAG;
+                               ssid_found = true;
+                               break;
+                       }
+               }
+
+               if (ssid_found)
+                       continue;
+
+               if (index_to_add >= MAX_PROBED_SSIDS)
+                       continue;
+
+               ssid_list[index_to_add].ssid.ssid_len =
+                       match_set[i].ssid.ssid_len;
+               memcpy(ssid_list[index_to_add].ssid.ssid,
+                      match_set[i].ssid.ssid,
+                      match_set[i].ssid.ssid_len);
+               ssid_list[index_to_add].flag |= MATCH_SSID_FLAG;
+               index_to_add++;
+       }
+
+       for (i = 0; i < index_to_add; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
-                                         ssids[i].ssid_len ?
-                                         SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
-                                         ssids[i].ssid_len,
-                                         ssids[i].ssid);
+                                         ssid_list[i].flag,
+                                         ssid_list[i].ssid.ssid_len,
+                                         ssid_list[i].ssid.ssid);
+
        }
 
        /* Make sure no old entries are left behind */
-       for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
+       for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) {
                ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
                                          DISABLE_SSID_FLAG, 0, NULL);
        }
@@ -934,7 +992,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids, NULL, 0);
        if (ret < 0)
                return ret;
 
@@ -943,7 +1001,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_err("failed to set Probe Request appie for scan");
+               ath6kl_err("failed to set Probe Request appie for scan\n");
                return ret;
        }
 
@@ -1512,6 +1570,9 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
                }
        }
 
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
+
 set_iface_type:
        switch (type) {
        case NL80211_IFTYPE_STATION:
@@ -2074,7 +2135,9 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
                return -EINVAL;
 
-       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                                vif->fw_vif_idx, false);
                if (ret)
@@ -2209,7 +2272,9 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
 
        ar->state = ATH6KL_STATE_ON;
 
-       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+       if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
+           test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
                                        vif->fw_vif_idx, true);
                if (ret)
@@ -2475,7 +2540,7 @@ void ath6kl_check_wow_status(struct ath6kl *ar)
 static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
                            bool ht_enable)
 {
-       struct ath6kl_htcap *htcap = &vif->htcap;
+       struct ath6kl_htcap *htcap = &vif->htcap[band];
 
        if (htcap->ht_enable == ht_enable)
                return 0;
@@ -2585,33 +2650,28 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
        return 0;
 }
 
-static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
-                             struct ieee80211_channel *chan,
-                             enum nl80211_channel_type channel_type)
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable)
 {
-       struct ath6kl_vif *vif;
+       int err;
 
-       /*
-        * 'dev' could be NULL if a channel change is required for the hardware
-        * device itself, instead of a particular VIF.
-        *
-        * FIXME: To be handled properly when monitor mode is supported.
-        */
-       if (!dev)
-               return -EBUSY;
+       if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag)))
+               return;
 
-       vif = netdev_priv(dev);
+       if (vif->nw_type != INFRA_NETWORK)
+               return;
 
-       if (!ath6kl_cfg80211_ready(vif))
-               return -EIO;
+       if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+                     vif->ar->fw_capabilities))
+               return;
 
-       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
-                  __func__, chan->center_freq, chan->hw_value);
-       vif->next_chan = chan->center_freq;
-       vif->next_ch_type = channel_type;
-       vif->next_ch_band = chan->band;
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n",
+                  enable ? "enable" : "disable");
 
-       return 0;
+       err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi,
+                                              vif->fw_vif_idx, enable);
+       if (err)
+               ath6kl_err("failed to %s enhanced bmiss detection: %d\n",
+                          enable ? "enable" : "disable", err);
 }
 
 static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
@@ -2694,9 +2754,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        /* TODO:
         * info->interval
-        * info->dtim_period
         */
 
+       ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx,
+                                        info->dtim_period);
+
+       /* ignore error, just print a warning and continue normally */
+       if (ret)
+               ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret);
+
        if (info->beacon.head == NULL)
                return -EINVAL;
        mgmt = (struct ieee80211_mgmt *) info->beacon.head;
@@ -2791,7 +2857,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        p.ssid_len = vif->ssid_len;
        memcpy(p.ssid, vif->ssid, vif->ssid_len);
        p.dot11_auth_mode = vif->dot11_auth_mode;
-       p.ch = cpu_to_le16(vif->next_chan);
+       p.ch = cpu_to_le16(info->channel->center_freq);
 
        /* Enable uAPSD support by default */
        res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2815,8 +2881,8 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
                        return res;
        }
 
-       if (ath6kl_set_htcap(vif, vif->next_ch_band,
-                            vif->next_ch_type != NL80211_CHAN_NO_HT))
+       if (ath6kl_set_htcap(vif, info->channel->band,
+                            info->channel_type != NL80211_CHAN_NO_HT))
                return -EIO;
 
        /*
@@ -3160,10 +3226,24 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        ath6kl_cfg80211_scan_complete_event(vif, true);
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids);
+                                     request->n_ssids,
+                                     request->match_sets,
+                                     request->n_match_sets);
        if (ret < 0)
                return ret;
 
+       if (!request->n_match_sets) {
+               ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                              ALL_BSS_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       } else {
+                ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+                                               MATCHED_SSID_FILTER, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* fw uses seconds, also make sure that it's >0 */
        interval = max_t(u16, 1, request->interval / 1000);
 
@@ -3185,7 +3265,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                                       WMI_FRAME_PROBE_REQ,
                                       request->ie, request->ie_len);
        if (ret) {
-               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d",
+               ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n",
                            ret);
                return ret;
        }
@@ -3217,6 +3297,18 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
        return 0;
 }
 
+static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      const u8 *addr,
+                                      const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+
+       return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx,
+                                          mask);
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
@@ -3271,7 +3363,6 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .suspend = __ath6kl_cfg80211_suspend,
        .resume = __ath6kl_cfg80211_resume,
 #endif
-       .set_channel = ath6kl_set_channel,
        .start_ap = ath6kl_start_ap,
        .change_beacon = ath6kl_change_beacon,
        .stop_ap = ath6kl_stop_ap,
@@ -3283,6 +3374,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .mgmt_frame_register = ath6kl_mgmt_frame_register,
        .sched_scan_start = ath6kl_cfg80211_sscan_start,
        .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
+       .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@@ -3410,7 +3502,8 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
        vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
        vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
        vif->bg_scan_period = 0;
-       vif->htcap.ht_enable = true;
+       vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true;
+       vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
 
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
        if (fw_vif_idx != 0)
@@ -3470,7 +3563,13 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        }
 
        /* max num of ssids that can be probed during scanning */
-       wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
+
+       /* max num of ssids that can be matched after scan */
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+                    ar->fw_capabilities))
+               wiphy->max_match_sets = MAX_PROBED_SSIDS;
+
        wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
        switch (ar->hw.cap) {
        case WMI_11AN_CAP:
@@ -3507,6 +3606,17 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                ath6kl_band_5ghz.ht_cap.cap = 0;
                ath6kl_band_5ghz.ht_cap.ht_supported = false;
        }
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
+       } else {
+               ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+               ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
+       }
+
        if (band_2gig)
                wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
        if (band_5gig)
@@ -3527,7 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        wiphy->wowlan.pattern_min_len = 1;
        wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
 
-       wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
+       wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
 
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME |
index 5ea8cbb79f43ac8dae52ab3f3f0a9b4aaa0104ee..b992046a1b0e83f4f37fc149dea2bbcee82b2f7d 100644 (file)
@@ -62,5 +62,7 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar);
 
 struct ath6kl *ath6kl_cfg80211_create(void);
 void ath6kl_cfg80211_destroy(struct ath6kl *ar);
+/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */
+void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable);
 
 #endif /* ATH6KL_CFG80211_H */
index 4d9c6f1426987aab4b9cb419dbb101438dee9027..d38a31de344ca4eaecde32642fc8c8bf0f41c2d3 100644 (file)
@@ -100,6 +100,21 @@ enum ath6kl_fw_capability {
        /* Firmware has support to override rsn cap of rsn ie */
        ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
 
+       /*
+        * Multicast support in WOW and host awake mode.
+        * Allow all multicast in host awake mode.
+        * Apply multicast filter in WOW mode.
+        */
+       ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+
+       /* Firmware supports enhanced bmiss detection */
+       ATH6KL_FW_CAPABILITY_BMISS_ENHANCE,
+
+       /*
+        * FW supports matching of ssid in schedule scan
+        */
+       ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
+
        /* this needs to be last */
        ATH6KL_FW_CAPABILITY_MAX,
 };
@@ -112,6 +127,10 @@ struct ath6kl_fw_ie {
        u8 data[0];
 };
 
+enum ath6kl_hw_flags {
+       ATH6KL_HW_FLAG_64BIT_RATES      = BIT(0),
+};
+
 #define ATH6KL_FW_API2_FILE "fw-2.bin"
 #define ATH6KL_FW_API3_FILE "fw-3.bin"
 
@@ -196,7 +215,7 @@ struct ath6kl_fw_ie {
 
 #define AGGR_NUM_OF_FREE_NETBUFS    16
 
-#define AGGR_RX_TIMEOUT     400        /* in ms */
+#define AGGR_RX_TIMEOUT     100        /* in ms */
 
 #define WMI_TIMEOUT (2 * HZ)
 
@@ -245,7 +264,6 @@ struct skb_hold_q {
 
 struct rxtid {
        bool aggr;
-       bool progress;
        bool timer_mon;
        u16 win_sz;
        u16 seq_next;
@@ -254,9 +272,15 @@ struct rxtid {
        struct sk_buff_head q;
 
        /*
-        * FIXME: No clue what this should protect. Apparently it should
-        * protect some of the fields above but they are also accessed
-        * without taking the lock.
+        * lock mainly protects seq_next and hold_q. Movement of seq_next
+        * needs to be protected between aggr_timeout() and
+        * aggr_process_recv_frm(). hold_q will be holding the pending
+        * reorder frames and it's access should also be protected.
+        * Some of the other fields like hold_q_sz, win_sz and aggr are
+        * initialized/reset when receiving addba/delba req, also while
+        * deleting aggr state all the pending buffers are flushed before
+        * resetting these fields, so there should not be any race in accessing
+        * these fields.
         */
        spinlock_t lock;
 };
@@ -541,7 +565,7 @@ struct ath6kl_vif {
        struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1];
        struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1];
        struct aggr_info *aggr_cntxt;
-       struct ath6kl_htcap htcap;
+       struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS];
 
        struct timer_list disconnect_timer;
        struct timer_list sched_scan_timer;
@@ -553,9 +577,6 @@ struct ath6kl_vif {
        u32 last_cancel_roc_id;
        u32 send_action_id;
        bool probe_req_report;
-       u16 next_chan;
-       enum nl80211_channel_type next_ch_type;
-       enum ieee80211_band next_ch_band;
        u16 assoc_bss_beacon_int;
        u16 listen_intvl_t;
        u16 bmiss_time_t;
@@ -687,6 +708,8 @@ struct ath6kl {
                u32 testscript_addr;
                enum wmi_phy_cap cap;
 
+               u32 flags;
+
                struct ath6kl_hw_fw {
                        const char *dir;
                        const char *otp;
index 2798624d3a9d28f9d3873cdbc8a52fa9bff68f44..cd0e1ba410d6ac3050fa5bb3fd35f99451492238 100644 (file)
@@ -1309,7 +1309,7 @@ static int ath6kl_htc_rx_packet(struct htc_target *target,
        }
 
        ath6kl_dbg(ATH6KL_DBG_HTC,
-                  "htc rx 0x%p hdr x%x len %d mbox 0x%x\n",
+                  "htc rx 0x%p hdr 0x%x len %d mbox 0x%x\n",
                   packet, packet->info.rx.exp_hdr,
                   padded_len, dev->ar->mbox_info.htc_addr);
 
index 7eb0515f458ab64528c16240358d5353b1f199c1..f90b5db741cf74c6784a9dc0a6a100d2b7a59f08 100644 (file)
@@ -42,6 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
                .reserved_ram_size              = 6912,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
+               .flags                          = 0,
 
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
@@ -67,6 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
                .testscript_addr                = 0x57ef74,
+               .flags                          = 0,
 
                .fw = {
                        .dir            = AR6003_HW_2_1_1_FW_DIR,
@@ -91,6 +93,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x433900,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_0_FW_DIR,
@@ -110,6 +113,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x43d400,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_1_FW_DIR,
@@ -129,6 +133,7 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x435c00,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
 
                .fw = {
                        .dir            = AR6004_HW_1_2_FW_DIR,
@@ -938,6 +943,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                }
 
                switch (ie_id) {
+               case ATH6KL_FW_IE_FW_VERSION:
+                       strlcpy(ar->wiphy->fw_version, data,
+                               sizeof(ar->wiphy->fw_version));
+
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found fw version %s\n",
+                                   ar->wiphy->fw_version);
+                       break;
                case ATH6KL_FW_IE_OTP_IMAGE:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n",
                                   ie_len);
@@ -991,9 +1004,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
-                       if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
-                               break;
-
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
                                   "found firmware capabilities ie (%zd B)\n",
                                   ie_len);
@@ -1002,6 +1012,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                                index = i / 8;
                                bit = i % 8;
 
+                               if (index == ie_len)
+                                       break;
+
                                if (data[index] & (1 << bit))
                                        __set_bit(i, ar->fw_capabilities);
                        }
@@ -1392,6 +1405,12 @@ static int ath6kl_init_upload(struct ath6kl *ar)
            ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
+               param = 0x28;
+               address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS;
+               status = ath6kl_bmi_reg_write(ar, address, param);
+               if (status)
+                       return status;
+
                param = 0x20;
 
                address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS;
@@ -1659,6 +1678,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
                cfg80211_scan_done(vif->scan_req, true);
                vif->scan_req = NULL;
        }
+
+       /* need to clean up enhanced bmiss detection fw state */
+       ath6kl_cfg80211_sta_bmiss_enhance(vif, false);
 }
 
 void ath6kl_stop_txrx(struct ath6kl *ar)
index e5524470529c9d8a77034855fec8d3e3fa9d6a86..c189e28e86a9bbfaebb7f81a32291801d51fa1f7 100644 (file)
@@ -554,20 +554,24 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
        struct ath6kl *ar = devt;
 
        memcpy(ar->mac_addr, datap, ETH_ALEN);
-       ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n",
-                  __func__, ar->mac_addr);
+
+       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                  "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n",
+                  ar->mac_addr, sw_ver, abi_ver, cap);
 
        ar->version.wlan_ver = sw_ver;
        ar->version.abi_ver = abi_ver;
        ar->hw.cap = cap;
 
-       snprintf(ar->wiphy->fw_version,
-                sizeof(ar->wiphy->fw_version),
-                "%u.%u.%u.%u",
-                (ar->version.wlan_ver & 0xf0000000) >> 28,
-                (ar->version.wlan_ver & 0x0f000000) >> 24,
-                (ar->version.wlan_ver & 0x00ff0000) >> 16,
-                (ar->version.wlan_ver & 0x0000ffff));
+       if (strlen(ar->wiphy->fw_version) == 0) {
+               snprintf(ar->wiphy->fw_version,
+                        sizeof(ar->wiphy->fw_version),
+                        "%u.%u.%u.%u",
+                        (ar->version.wlan_ver & 0xf0000000) >> 28,
+                        (ar->version.wlan_ver & 0x0f000000) >> 24,
+                        (ar->version.wlan_ver & 0x00ff0000) >> 16,
+                        (ar->version.wlan_ver & 0x0000ffff));
+       }
 
        /* indicate to the waiting thread that the ready event was received */
        set_bit(WMI_READY, &ar->flag);
@@ -598,7 +602,6 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 
        struct ath6kl *ar = vif->ar;
 
-       vif->next_chan = channel;
        vif->profile.ch = cpu_to_le16(channel);
 
        switch (vif->nw_type) {
@@ -1167,7 +1170,10 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
        else
                clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
 
-       mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
+                    vif->ar->fw_capabilities)) {
+               mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
+       }
 
        if (!(ndev->flags & IFF_MULTICAST)) {
                mc_all_on = false;
index 78e0ef4567a5287d4755f2812d7e41b97e1e6ccf..a98c12ba70c1dfa32aa0d3fbd25a76852d5df22b 100644 (file)
@@ -45,6 +45,7 @@
 #define LPO_CAL_ENABLE_S               20
 #define LPO_CAL_ENABLE                 0x00100000
 
+#define GPIO_PIN9_ADDRESS              0x0000004c
 #define GPIO_PIN10_ADDRESS             0x00000050
 #define GPIO_PIN11_ADDRESS             0x00000054
 #define GPIO_PIN12_ADDRESS             0x00000058
index 67206aedea6cabada2a933a870e81065181c749e..7dfa0fd86d7b111ea06cbd1c85d673ba65717cb6 100644 (file)
@@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        rxtid = &agg_conn->rx_tid[tid];
        stats = &agg_conn->stat[tid];
 
+       spin_lock_bh(&rxtid->lock);
        idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
 
        /*
@@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
        seq_end = seq_no ? seq_no : rxtid->seq_next;
        idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
 
-       spin_lock_bh(&rxtid->lock);
-
        do {
                node = &rxtid->hold_q[idx];
                if ((order == 1) && (!node->skb))
@@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
                    ((end > extended_end) && (cur > extended_end) &&
                     (cur < end))) {
                        aggr_deque_frms(agg_conn, tid, 0, 0);
+                       spin_lock_bh(&rxtid->lock);
                        if (cur >= rxtid->hold_q_sz - 1)
                                rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
                        else
                                rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
                                                  (rxtid->hold_q_sz - 2 - cur);
+                       spin_unlock_bh(&rxtid->lock);
                } else {
                        /*
                         * Dequeue only those frames that are outside the
@@ -1185,25 +1186,25 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
        aggr_deque_frms(agg_conn, tid, 0, 1);
 
        if (agg_conn->timer_scheduled)
-               rxtid->progress = true;
-       else
-               for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
-                       if (rxtid->hold_q[idx].skb) {
-                               /*
-                                * There is a frame in the queue and no
-                                * timer so start a timer to ensure that
-                                * the frame doesn't remain stuck
-                                * forever.
-                                */
-                               agg_conn->timer_scheduled = true;
-                               mod_timer(&agg_conn->timer,
-                                         (jiffies +
-                                          HZ * (AGGR_RX_TIMEOUT) / 1000));
-                               rxtid->progress = false;
-                               rxtid->timer_mon = true;
-                               break;
-                       }
+               return is_queued;
+
+       spin_lock_bh(&rxtid->lock);
+       for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
+               if (rxtid->hold_q[idx].skb) {
+                       /*
+                        * There is a frame in the queue and no
+                        * timer so start a timer to ensure that
+                        * the frame doesn't remain stuck
+                        * forever.
+                        */
+                       agg_conn->timer_scheduled = true;
+                       mod_timer(&agg_conn->timer,
+                                 (jiffies + (HZ * AGGR_RX_TIMEOUT) / 1000));
+                       rxtid->timer_mon = true;
+                       break;
                }
+       }
+       spin_unlock_bh(&rxtid->lock);
 
        return is_queued;
 }
@@ -1608,7 +1609,7 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
                stats = &aggr_conn->stat[i];
 
-               if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress)
+               if (!rxtid->aggr || !rxtid->timer_mon)
                        continue;
 
                stats->num_timeouts++;
@@ -1626,14 +1627,15 @@ static void aggr_timeout(unsigned long arg)
                rxtid = &aggr_conn->rx_tid[i];
 
                if (rxtid->aggr && rxtid->hold_q) {
+                       spin_lock_bh(&rxtid->lock);
                        for (j = 0; j < rxtid->hold_q_sz; j++) {
                                if (rxtid->hold_q[j].skb) {
                                        aggr_conn->timer_scheduled = true;
                                        rxtid->timer_mon = true;
-                                       rxtid->progress = false;
                                        break;
                                }
                        }
+                       spin_unlock_bh(&rxtid->lock);
 
                        if (j >= rxtid->hold_q_sz)
                                rxtid->timer_mon = false;
@@ -1660,7 +1662,6 @@ static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid)
                aggr_deque_frms(aggr_conn, tid, 0, 0);
 
        rxtid->aggr = false;
-       rxtid->progress = false;
        rxtid->timer_mon = false;
        rxtid->win_sz = 0;
        rxtid->seq_next = 0;
@@ -1739,7 +1740,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info,
        for (i = 0; i < NUM_OF_TIDS; i++) {
                rxtid = &aggr_conn->rx_tid[i];
                rxtid->aggr = false;
-               rxtid->progress = false;
                rxtid->timer_mon = false;
                skb_queue_head_init(&rxtid->q);
                spin_lock_init(&rxtid->lock);
index ee8ec2394c2cc453962178d4cdf78dfa866cd689..a6caa673e8ad944fc41bb2c3b45e48c47bcfbd7f 100644 (file)
@@ -743,7 +743,6 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        memcpy(cmd->info.bssid, bssid, ETH_ALEN);
        cmd->roam_ctrl = WMI_FORCE_ROAM;
@@ -753,6 +752,22 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
+{
+       struct sk_buff *skb;
+       struct set_dtim_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct set_dtim_cmd *) skb->data;
+
+       cmd->dtim_period = cpu_to_le32(dtim_period);
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                  WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
+}
+
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
 {
        struct sk_buff *skb;
@@ -763,7 +778,6 @@ int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
                return -ENOMEM;
 
        cmd = (struct roam_ctrl_cmd *) skb->data;
-       memset(cmd, 0, sizeof(*cmd));
 
        cmd->info.roam_mode = mode;
        cmd->roam_ctrl = WMI_SET_ROAM_MODE;
@@ -1995,7 +2009,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
        struct wmi_probed_ssid_cmd *cmd;
        int ret;
 
-       if (index > MAX_PROBED_SSID_INDEX)
+       if (index >= MAX_PROBED_SSIDS)
                return -EINVAL;
 
        if (ssid_len > sizeof(cmd->ssid))
@@ -2599,6 +2613,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
        spin_unlock_bh(&wmi->lock);
 }
 
+static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates64_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[1];
+               mcsrate <<= 8;
+               mcsrate |= mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 28;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       struct sk_buff *skb;
+       int ret, mode, band;
+       u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       struct wmi_set_tx_select_rates32_cmd *cmd;
+
+       memset(&ratemask, 0, sizeof(ratemask));
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               /* copy legacy rate mask */
+               ratemask[band] = mask->control[band].legacy;
+               if (band == IEEE80211_BAND_5GHZ)
+                       ratemask[band] =
+                               mask->control[band].legacy << 4;
+
+               /* copy mcs rate mask */
+               mcsrate = mask->control[band].mcs[0];
+               ratemask[band] |= mcsrate << 12;
+               ratemask[band] |= mcsrate << 20;
+       }
+
+       ath6kl_dbg(ATH6KL_DBG_WMI,
+                  "Ratemask 32 bit: 2.4:%x 5:%x\n",
+                  ratemask[0], ratemask[1]);
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
+       for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
+               /* A mode operate in 5GHZ band */
+               if (mode == WMI_RATES_MODE_11A ||
+                   mode == WMI_RATES_MODE_11A_HT20 ||
+                   mode == WMI_RATES_MODE_11A_HT40)
+                       band = IEEE80211_BAND_5GHZ;
+               else
+                       band = IEEE80211_BAND_2GHZ;
+               cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
+       }
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_SET_TX_SELECT_RATES_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath6kl *ar = wmi->parent_dev;
+
+       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
+               return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
+       else
+               return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
+}
+
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode)
 {
@@ -2997,6 +3120,25 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
+{
+       struct sk_buff *skb;
+       struct wmi_sta_bmiss_enhance_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
+       cmd->enable = enhance ? 1 : 0;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_STA_BMISS_ENHANCE_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
        if (rate_index == RATE_AUTO)
index 9076bec3a2ba29b430f42fc6607038420fcddbb0..43339aca585d96508cc9d2b7f87b4cf743cca3c9 100644 (file)
@@ -624,6 +624,10 @@ enum wmi_cmd_id {
        WMI_SEND_MGMT_CMDID,
        WMI_BEGIN_SCAN_CMDID,
 
+       WMI_SET_BLACK_LIST,
+       WMI_SET_MCASTRATE,
+
+       WMI_STA_BMISS_ENHANCE_CMDID,
 };
 
 enum wmi_mgmt_frame_type {
@@ -960,6 +964,9 @@ enum wmi_bss_filter {
        /* beacons matching probed ssid */
        PROBED_SSID_FILTER,
 
+       /* beacons matching matched ssid */
+       MATCHED_SSID_FILTER,
+
        /* marker only */
        LAST_BSS_FILTER,
 };
@@ -978,7 +985,7 @@ struct wmi_bss_filter_cmd {
 } __packed;
 
 /* WMI_SET_PROBED_SSID_CMDID */
-#define MAX_PROBED_SSID_INDEX   9
+#define MAX_PROBED_SSIDS   16
 
 enum wmi_ssid_flag {
        /* disables entry */
@@ -989,10 +996,13 @@ enum wmi_ssid_flag {
 
        /* probes for any ssid */
        ANY_SSID_FLAG = 0x02,
+
+       /* match for ssid */
+       MATCH_SSID_FLAG = 0x08,
 };
 
 struct wmi_probed_ssid_cmd {
-       /* 0 to MAX_PROBED_SSID_INDEX */
+       /* 0 to MAX_PROBED_SSIDS - 1 */
        u8 entry_index;
 
        /* see, enum wmi_ssid_flg */
@@ -1017,6 +1027,11 @@ struct wmi_bmiss_time_cmd {
        __le16 num_beacons;
 };
 
+/* WMI_STA_ENHANCE_BMISS_CMDID */
+struct wmi_sta_bmiss_enhance_cmd {
+       u8 enable;
+} __packed;
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
        REC_POWER = 0x01,
@@ -1048,6 +1063,36 @@ struct wmi_power_params_cmd {
        __le16 ps_fail_event_policy;
 } __packed;
 
+/*
+ * Ratemask for below modes should be passed
+ * to WMI_SET_TX_SELECT_RATES_CMDID.
+ * AR6003 has 32 bit mask for each modes.
+ * First 12 bits for legacy rates, 13 to 20
+ * bits for HT 20 rates and 21 to 28 bits for
+ * HT 40 rates
+ */
+enum wmi_mode_phy {
+       WMI_RATES_MODE_11A = 0,
+       WMI_RATES_MODE_11G,
+       WMI_RATES_MODE_11B,
+       WMI_RATES_MODE_11GONLY,
+       WMI_RATES_MODE_11A_HT20,
+       WMI_RATES_MODE_11G_HT20,
+       WMI_RATES_MODE_11A_HT40,
+       WMI_RATES_MODE_11G_HT40,
+       WMI_RATES_MODE_MAX
+};
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates32_cmd {
+       __le32 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
+/* WMI_SET_TX_SELECT_RATES_CMDID */
+struct wmi_set_tx_select_rates64_cmd {
+       __le64 ratemask[WMI_RATES_MODE_MAX];
+} __packed;
+
 /* WMI_SET_DISC_TIMEOUT_CMDID */
 struct wmi_disc_timeout_cmd {
        /* seconds */
@@ -1572,6 +1617,10 @@ struct roam_ctrl_cmd {
        u8 roam_ctrl;
 } __packed;
 
+struct set_dtim_cmd {
+       __le32 dtim_period;
+} __packed;
+
 /* BSS INFO HDR version 2.0 */
 struct wmi_bss_info_hdr2 {
        __le16 ch; /* frequency in MHz */
@@ -2532,6 +2581,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
                          __be32 ips0, __be32 ips1);
 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
                                       enum ath6kl_host_mode host_mode);
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
+                               const struct cfg80211_bitrate_mask *mask);
 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
                                enum ath6kl_wow_mode wow_mode,
                                u32 filter, u16 host_req_delay);
@@ -2542,11 +2593,14 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   u16 list_id, u16 filter_id);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
+int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
                                        u8 *filter, bool add_filter);
+int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
+
 /* AP mode uAPSD */
 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
 
index 3f0b847237895ca1840e0e4efa75186d7994ccfd..9c41232b0cd070593ceb7d98bf6b6ba22d688202 100644 (file)
@@ -3,7 +3,9 @@ ath9k-y +=      beacon.o \
                init.o \
                main.o \
                recv.o \
-               xmit.o
+               xmit.o \
+               link.o \
+               antenna.o
 
 ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
index 5e47ca6d16a826e71176c3dd5e7efa01586c4375..4a4e8a2b9d2c4cbefa6770e67f2b377ef07cc09e 100644 (file)
@@ -126,7 +126,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
        sc->irq = irq;
 
        /* Will be cleared in ath9k_start() */
-       sc->sc_flags |= SC_OP_INVALID;
+       set_bit(SC_OP_INVALID, &sc->sc_flags);
 
        ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
        if (ret) {
index b4c77f9d74701163c08e20ea4096a5acace22b64..ff007f500feba8176794ca200e2bfd0523d657ff 100644 (file)
@@ -104,11 +104,6 @@ static const struct ani_cck_level_entry cck_level_table[] = {
 #define ATH9K_ANI_CCK_DEF_LEVEL \
        2 /* default level - matches the INI settings */
 
-static bool use_new_ani(struct ath_hw *ah)
-{
-       return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
-}
-
 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
                                     struct ath9k_mib_stats *stats)
 {
@@ -122,8 +117,6 @@ 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);
-       u32 ofdm_base = 0, cck_base = 0;
 
        if (!DO_ANI(ah))
                return;
@@ -131,18 +124,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
        aniState = &ah->curchan->ani;
        aniState->listenTime = 0;
 
-       if (!use_new_ani(ah)) {
-               ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
-               cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
-       }
-
-       ath_dbg(common, ANI, "Writing ofdmbase=%u   cckbase=%u\n",
-               ofdm_base, cck_base);
-
        ENABLE_REGWRITE_BUFFER(ah);
 
-       REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
-       REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
+       REG_WRITE(ah, AR_PHY_ERR_1, 0);
+       REG_WRITE(ah, AR_PHY_ERR_2, 0);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
@@ -154,129 +139,23 @@ static void ath9k_ani_restart(struct ath_hw *ah)
        aniState->cckPhyErrCount = 0;
 }
 
-static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-       struct ar5416AniState *aniState;
-       int32_t rssi;
-
-       aniState = &ah->curchan->ani;
-
-       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                        aniState->noiseImmunityLevel + 1)) {
-                       return;
-               }
-       }
-
-       if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                        aniState->spurImmunityLevel + 1)) {
-                       return;
-               }
-       }
-
-       if (ah->opmode == NL80211_IFTYPE_AP) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               }
-               return;
-       }
-       rssi = BEACON_RSSI(ah);
-       if (rssi > aniState->rssiThrHigh) {
-               if (!aniState->ofdmWeakSigDetectOff) {
-                       if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                        false)) {
-                               ath9k_hw_ani_control(ah,
-                                       ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-                               return;
-                       }
-               }
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-                       return;
-               }
-       } else if (rssi > aniState->rssiThrLow) {
-               if (aniState->ofdmWeakSigDetectOff)
-                       ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    true);
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               return;
-       } else {
-               if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
-                   !conf_is_ht(conf)) {
-                       if (!aniState->ofdmWeakSigDetectOff)
-                               ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    false);
-                       if (aniState->firstepLevel > 0)
-                               ath9k_hw_ani_control(ah,
-                                            ATH9K_ANI_FIRSTEP_LEVEL, 0);
-                       return;
-               }
-       }
-}
-
-static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-       struct ar5416AniState *aniState;
-       int32_t rssi;
-
-       aniState = &ah->curchan->ani;
-       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                        aniState->noiseImmunityLevel + 1)) {
-                       return;
-               }
-       }
-       if (ah->opmode == NL80211_IFTYPE_AP) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               }
-               return;
-       }
-       rssi = BEACON_RSSI(ah);
-       if (rssi > aniState->rssiThrLow) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-       } else {
-               if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
-                   !conf_is_ht(conf)) {
-                       if (aniState->firstepLevel > 0)
-                               ath9k_hw_ani_control(ah,
-                                            ATH9K_ANI_FIRSTEP_LEVEL, 0);
-               }
-       }
-}
-
 /* Adjust the OFDM Noise Immunity Level */
-static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
+static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
+                                 bool scan)
 {
        struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
-
-       aniState->noiseFloor = BEACON_RSSI(ah);
+       bool weak_sig;
 
        ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
                aniState->ofdmNoiseImmunityLevel,
-               immunityLevel, aniState->noiseFloor,
+               immunityLevel, BEACON_RSSI(ah),
                aniState->rssiThrLow, aniState->rssiThrHigh);
 
-       if (aniState->update_ani)
-               aniState->ofdmNoiseImmunityLevel =
-                       (immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ?
-                       immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL;
+       if (!scan)
+               aniState->ofdmNoiseImmunityLevel = immunityLevel;
 
        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -292,12 +171,22 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
                                     ATH9K_ANI_FIRSTEP_LEVEL,
                                     entry_ofdm->fir_step_level);
 
-       if ((aniState->noiseFloor >= aniState->rssiThrHigh) &&
-           (!aniState->ofdmWeakSigDetectOff !=
-            entry_ofdm->ofdm_weak_signal_on)) {
+       weak_sig = entry_ofdm->ofdm_weak_signal_on;
+       if (ah->opmode == NL80211_IFTYPE_STATION &&
+           BEACON_RSSI(ah) <= aniState->rssiThrHigh)
+               weak_sig = true;
+
+       if (aniState->ofdmWeakSigDetect != weak_sig)
                        ath9k_hw_ani_control(ah,
                                ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
                                entry_ofdm->ofdm_weak_signal_on);
+
+       if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI;
+       } else {
+               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI;
+               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
        }
 }
 
@@ -308,43 +197,35 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
        if (!DO_ANI(ah))
                return;
 
-       if (!use_new_ani(ah)) {
-               ath9k_hw_ani_ofdm_err_trigger_old(ah);
-               return;
-       }
-
        aniState = &ah->curchan->ani;
 
        if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
-               ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
+               ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
 }
 
 /*
  * Set the ANI settings to match an CCK level.
  */
-static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
+static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
+                                bool scan)
 {
        struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
 
-       aniState->noiseFloor = BEACON_RSSI(ah);
        ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
                aniState->cckNoiseImmunityLevel, immunityLevel,
-               aniState->noiseFloor, aniState->rssiThrLow,
+               BEACON_RSSI(ah), aniState->rssiThrLow,
                aniState->rssiThrHigh);
 
-       if ((ah->opmode == NL80211_IFTYPE_STATION ||
-            ah->opmode == NL80211_IFTYPE_ADHOC) &&
-           aniState->noiseFloor <= aniState->rssiThrLow &&
+       if (ah->opmode == NL80211_IFTYPE_STATION &&
+           BEACON_RSSI(ah) <= aniState->rssiThrLow &&
            immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
                immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 
-       if (aniState->update_ani)
-               aniState->cckNoiseImmunityLevel =
-                       (immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ?
-                       immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL;
+       if (!scan)
+               aniState->cckNoiseImmunityLevel = immunityLevel;
 
        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -359,7 +240,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
        if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
                return;
 
-       if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
+       if (aniState->mrcCCK != entry_cck->mrc_cck_on)
                ath9k_hw_ani_control(ah,
                                     ATH9K_ANI_MRC_CCK,
                                     entry_cck->mrc_cck_on);
@@ -372,68 +253,11 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
        if (!DO_ANI(ah))
                return;
 
-       if (!use_new_ani(ah)) {
-               ath9k_hw_ani_cck_err_trigger_old(ah);
-               return;
-       }
-
        aniState = &ah->curchan->ani;
 
        if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
-               ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
-}
-
-static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
-{
-       struct ar5416AniState *aniState;
-       int32_t rssi;
-
-       aniState = &ah->curchan->ani;
-
-       if (ah->opmode == NL80211_IFTYPE_AP) {
-               if (aniState->firstepLevel > 0) {
-                       if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                                aniState->firstepLevel - 1))
-                               return;
-               }
-       } else {
-               rssi = BEACON_RSSI(ah);
-               if (rssi > aniState->rssiThrHigh) {
-                       /* XXX: Handle me */
-               } else if (rssi > aniState->rssiThrLow) {
-                       if (aniState->ofdmWeakSigDetectOff) {
-                               if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                        true))
-                                       return;
-                       }
-                       if (aniState->firstepLevel > 0) {
-                               if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_FIRSTEP_LEVEL,
-                                        aniState->firstepLevel - 1))
-                                       return;
-                       }
-               } else {
-                       if (aniState->firstepLevel > 0) {
-                               if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_FIRSTEP_LEVEL,
-                                        aniState->firstepLevel - 1))
-                                       return;
-                       }
-               }
-       }
-
-       if (aniState->spurImmunityLevel > 0) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                        aniState->spurImmunityLevel - 1))
-                       return;
-       }
-
-       if (aniState->noiseImmunityLevel > 0) {
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                    aniState->noiseImmunityLevel - 1);
-               return;
-       }
+               ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
+                                    false);
 }
 
 /*
@@ -446,87 +270,18 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 
        aniState = &ah->curchan->ani;
 
-       if (!use_new_ani(ah)) {
-               ath9k_hw_ani_lower_immunity_old(ah);
-               return;
-       }
-
        /* lower OFDM noise immunity */
        if (aniState->ofdmNoiseImmunityLevel > 0 &&
            (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
-               ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
+               ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1,
+                                     false);
                return;
        }
 
        /* lower CCK noise immunity */
        if (aniState->cckNoiseImmunityLevel > 0)
-               ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
-}
-
-static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
-{
-       struct ar5416AniState *aniState;
-       struct ath9k_channel *chan = ah->curchan;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = &ah->curchan->ani;
-
-       if (ah->opmode != NL80211_IFTYPE_STATION
-           && ah->opmode != NL80211_IFTYPE_ADHOC) {
-               ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode);
-               ah->stats.ast_ani_reset++;
-
-               if (ah->opmode == NL80211_IFTYPE_AP) {
-                       /*
-                        * ath9k_hw_ani_control() will only process items set on
-                        * ah->ani_function
-                        */
-                       if (IS_CHAN_2GHZ(chan))
-                               ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
-                                                   ATH9K_ANI_FIRSTEP_LEVEL);
-                       else
-                               ah->ani_function = 0;
-               }
-
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    !ATH9K_ANI_USE_OFDM_WEAK_SIG);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-                                    ATH9K_ANI_CCK_WEAK_SIG_THR);
-
-               ath9k_ani_restart(ah);
-               return;
-       }
-
-       if (aniState->noiseImmunityLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                    aniState->noiseImmunityLevel);
-       if (aniState->spurImmunityLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                    aniState->spurImmunityLevel);
-       if (aniState->ofdmWeakSigDetectOff)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    !aniState->ofdmWeakSigDetectOff);
-       if (aniState->cckWeakSigThreshold)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-                                    aniState->cckWeakSigThreshold);
-       if (aniState->firstepLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                    aniState->firstepLevel);
-
-       ath9k_ani_restart(ah);
-
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-       REGWRITE_BUFFER_FLUSH(ah);
+               ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1,
+                                    false);
 }
 
 /*
@@ -539,13 +294,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
        struct ar5416AniState *aniState = &ah->curchan->ani;
        struct ath9k_channel *chan = ah->curchan;
        struct ath_common *common = ath9k_hw_common(ah);
+       int ofdm_nil, cck_nil;
 
        if (!DO_ANI(ah))
                return;
 
-       if (!use_new_ani(ah))
-               return ath9k_ani_reset_old(ah, is_scanning);
-
        BUG_ON(aniState == NULL);
        ah->stats.ast_ani_reset++;
 
@@ -563,6 +316,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
        /* always allow mode (on/off) to be controlled */
        ah->ani_function |= ATH9K_ANI_MODE;
 
+       ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
+                        aniState->ofdmNoiseImmunityLevel);
+       cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
+                        aniState->cckNoiseImmunityLevel);
+
        if (is_scanning ||
            (ah->opmode != NL80211_IFTYPE_STATION &&
             ah->opmode != NL80211_IFTYPE_ADHOC)) {
@@ -585,9 +343,8 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                                aniState->ofdmNoiseImmunityLevel,
                                aniState->cckNoiseImmunityLevel);
 
-                       aniState->update_ani = false;
-                       ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
-                       ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
+                       ofdm_nil = ATH9K_ANI_OFDM_DEF_LEVEL;
+                       cck_nil = ATH9K_ANI_CCK_DEF_LEVEL;
                }
        } else {
                /*
@@ -601,13 +358,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                        is_scanning,
                        aniState->ofdmNoiseImmunityLevel,
                        aniState->cckNoiseImmunityLevel);
-
-                       aniState->update_ani = true;
-                       ath9k_hw_set_ofdm_nil(ah,
-                                             aniState->ofdmNoiseImmunityLevel);
-                       ath9k_hw_set_cck_nil(ah,
-                                            aniState->cckNoiseImmunityLevel);
        }
+       ath9k_hw_set_ofdm_nil(ah, ofdm_nil, is_scanning);
+       ath9k_hw_set_cck_nil(ah, cck_nil, is_scanning);
 
        /*
         * enable phy counters if hw supports or if not, enable phy
@@ -627,9 +380,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ar5416AniState *aniState = &ah->curchan->ani;
-       u32 ofdm_base = 0;
-       u32 cck_base = 0;
-       u32 ofdmPhyErrCnt, cckPhyErrCnt;
        u32 phyCnt1, phyCnt2;
        int32_t listenTime;
 
@@ -642,11 +392,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
                return false;
        }
 
-       if (!use_new_ani(ah)) {
-               ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
-               cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
-       }
-
        aniState->listenTime += listenTime;
 
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -654,35 +399,12 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 
-       if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
-               if (phyCnt1 < ofdm_base) {
-                       ath_dbg(common, ANI,
-                               "phyCnt1 0x%x, resetting counter value to 0x%x\n",
-                               phyCnt1, ofdm_base);
-                       REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
-                       REG_WRITE(ah, AR_PHY_ERR_MASK_1,
-                                 AR_PHY_ERR_OFDM_TIMING);
-               }
-               if (phyCnt2 < cck_base) {
-                       ath_dbg(common, ANI,
-                               "phyCnt2 0x%x, resetting counter value to 0x%x\n",
-                               phyCnt2, cck_base);
-                       REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
-                       REG_WRITE(ah, AR_PHY_ERR_MASK_2,
-                                 AR_PHY_ERR_CCK_TIMING);
-               }
-               return false;
-       }
+       ah->stats.ast_ani_ofdmerrs += phyCnt1 - aniState->ofdmPhyErrCount;
+       aniState->ofdmPhyErrCount = phyCnt1;
 
-       ofdmPhyErrCnt = phyCnt1 - ofdm_base;
-       ah->stats.ast_ani_ofdmerrs +=
-               ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-       aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+       ah->stats.ast_ani_cckerrs += phyCnt2 - aniState->cckPhyErrCount;
+       aniState->cckPhyErrCount = phyCnt2;
 
-       cckPhyErrCnt = phyCnt2 - cck_base;
-       ah->stats.ast_ani_cckerrs +=
-               cckPhyErrCnt - aniState->cckPhyErrCount;
-       aniState->cckPhyErrCount = cckPhyErrCnt;
        return true;
 }
 
@@ -716,21 +438,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 
        if (aniState->listenTime > ah->aniperiod) {
                if (cckPhyErrRate < ah->config.cck_trig_low &&
-                   ((ofdmPhyErrRate < ah->config.ofdm_trig_low &&
-                     aniState->ofdmNoiseImmunityLevel <
-                     ATH9K_ANI_OFDM_DEF_LEVEL) ||
-                    (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI &&
-                     aniState->ofdmNoiseImmunityLevel >=
-                     ATH9K_ANI_OFDM_DEF_LEVEL))) {
+                   ofdmPhyErrRate < ah->config.ofdm_trig_low) {
                        ath9k_hw_ani_lower_immunity(ah);
                        aniState->ofdmsTurn = !aniState->ofdmsTurn;
-               } else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high &&
-                           aniState->ofdmNoiseImmunityLevel >=
-                           ATH9K_ANI_OFDM_DEF_LEVEL) ||
-                          (ofdmPhyErrRate >
-                           ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI &&
-                           aniState->ofdmNoiseImmunityLevel <
-                           ATH9K_ANI_OFDM_DEF_LEVEL)) {
+               } else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
                        ath9k_hw_ani_ofdm_err_trigger(ah);
                        aniState->ofdmsTurn = false;
                } else if (cckPhyErrRate > ah->config.cck_trig_high) {
@@ -778,49 +489,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
-/*
- * Process a MIB interrupt.  We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-void ath9k_hw_proc_mib_event(struct ath_hw *ah)
-{
-       u32 phyCnt1, phyCnt2;
-
-       /* Reset these counters regardless */
-       REG_WRITE(ah, AR_FILT_OFDM, 0);
-       REG_WRITE(ah, AR_FILT_CCK, 0);
-       if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
-               REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
-
-       /* Clear the mib counters and save them in the stats */
-       ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
-       if (!DO_ANI(ah)) {
-               /*
-                * We must always clear the interrupt cause by
-                * resetting the phy error regs.
-                */
-               REG_WRITE(ah, AR_PHY_ERR_1, 0);
-               REG_WRITE(ah, AR_PHY_ERR_2, 0);
-               return;
-       }
-
-       /* NB: these are not reset-on-read */
-       phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-       phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-       if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-
-               if (!use_new_ani(ah))
-                       ath9k_hw_ani_read_counters(ah);
-
-               /* NB: always restart to insure the h/w counters are reset */
-               ath9k_ani_restart(ah);
-       }
-}
-EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
-
 void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
        int i;
@@ -845,66 +513,37 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
 
        ath_dbg(common, ANI, "Initialize ANI\n");
 
-       if (use_new_ani(ah)) {
-               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
-               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+       ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
+       ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
 
-               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
-               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
-       } else {
-               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
-               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
-
-               ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
-               ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
-       }
+       ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
+       ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
 
        for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
                struct ath9k_channel *chan = &ah->channels[i];
                struct ar5416AniState *ani = &chan->ani;
 
-               if (use_new_ani(ah)) {
-                       ani->spurImmunityLevel =
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+               ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
 
-                       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+               ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
 
-                       if (AR_SREV_9300_20_OR_LATER(ah))
-                               ani->mrcCCKOff =
-                                       !ATH9K_ANI_ENABLE_MRC_CCK;
-                       else
-                               ani->mrcCCKOff = true;
-
-                       ani->ofdmsTurn = true;
-               } else {
-                       ani->spurImmunityLevel =
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
-                       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
-
-                       ani->cckWeakSigThreshold =
-                               ATH9K_ANI_CCK_WEAK_SIG_THR;
-               }
+               ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
+
+               ani->ofdmsTurn = true;
 
                ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
                ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-               ani->ofdmWeakSigDetectOff =
-                       !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+               ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
                ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
                ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
-               ani->update_ani = false;
        }
 
        /*
         * since we expect some ongoing maintenance on the tables, let's sanity
         * check here default level should not modify INI setting.
         */
-       if (use_new_ani(ah)) {
-               ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
-               ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
-       } else {
-               ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
-               ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
-       }
+       ah->aniperiod = ATH9K_ANI_PERIOD;
+       ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
 
        if (ah->config.enable_ani)
                ah->proc_phyerr |= HAL_PROCESS_ANI;
index 72e2b874e179b663ee537165470d290b4361bdc5..1485bf5e3518851eab0e2f6531af8f5ed7118824 100644 (file)
 #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
 /* units are errors per second */
-#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD      500
-#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW      3500
+#define ATH9K_ANI_OFDM_TRIG_HIGH          3500
 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
 
 /* units are errors per second */
-#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
-#define ATH9K_ANI_OFDM_TRIG_LOW_NEW       400
+#define ATH9K_ANI_OFDM_TRIG_LOW           400
 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
 
 /* units are errors per second */
-#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
-#define ATH9K_ANI_CCK_TRIG_HIGH_NEW       600
+#define ATH9K_ANI_CCK_TRIG_HIGH           600
 
 /* units are errors per second */
-#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100
-#define ATH9K_ANI_CCK_TRIG_LOW_NEW        300
+#define ATH9K_ANI_CCK_TRIG_LOW            300
 
 #define ATH9K_ANI_NOISE_IMMUNE_LVL        4
 #define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
 #define ATH9K_ANI_CCK_WEAK_SIG_THR        false
 
-#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD     7
-#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW     3
+#define ATH9K_ANI_SPUR_IMMUNE_LVL         3
 
-#define ATH9K_ANI_FIRSTEP_LVL_OLD         0
-#define ATH9K_ANI_FIRSTEP_LVL_NEW         2
+#define ATH9K_ANI_FIRSTEP_LVL             2
 
 #define ATH9K_ANI_RSSI_THR_HIGH           40
 #define ATH9K_ANI_RSSI_THR_LOW            7
 
-#define ATH9K_ANI_PERIOD_OLD              100
-#define ATH9K_ANI_PERIOD_NEW              300
+#define ATH9K_ANI_PERIOD                  300
 
 /* in ms */
-#define ATH9K_ANI_POLLINTERVAL_OLD        100
-#define ATH9K_ANI_POLLINTERVAL_NEW        1000
+#define ATH9K_ANI_POLLINTERVAL            1000
 
 #define HAL_NOISE_IMMUNE_MAX              4
 #define HAL_SPUR_IMMUNE_MAX               7
@@ -70,8 +62,6 @@
 #define ATH9K_SIG_SPUR_IMM_SETTING_MIN    0
 #define ATH9K_SIG_SPUR_IMM_SETTING_MAX    22
 
-#define ATH9K_ANI_ENABLE_MRC_CCK          true
-
 /* values here are relative to the INI */
 
 enum ath9k_ani_cmd {
@@ -119,16 +109,14 @@ struct ar5416AniState {
        u8 ofdmNoiseImmunityLevel;
        u8 cckNoiseImmunityLevel;
        bool ofdmsTurn;
-       u8 mrcCCKOff;
+       u8 mrcCCK;
        u8 spurImmunityLevel;
        u8 firstepLevel;
-       u8 ofdmWeakSigDetectOff;
+       u8 ofdmWeakSigDetect;
        u8 cckWeakSigThreshold;
-       bool update_ani;
        u32 listenTime;
        int32_t rssiThrLow;
        int32_t rssiThrHigh;
-       u32 noiseFloor;
        u32 ofdmPhyErrCount;
        u32 cckPhyErrCount;
        int16_t pktRssi[2];
diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c
new file mode 100644 (file)
index 0000000..bbcfeb3
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, 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 "ath9k.h"
+
+static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
+                                              int mindelta, int main_rssi_avg,
+                                              int alt_rssi_avg, int pkt_count)
+{
+       return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+                (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
+               (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
+}
+
+static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+                                             int curr_main_set, int curr_alt_set,
+                                             int alt_rssi_avg, int main_rssi_avg)
+{
+       bool result = false;
+       switch (div_group) {
+       case 0:
+               if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+                       result = true;
+               break;
+       case 1:
+       case 2:
+               if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+                     (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+                     (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+                    ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+                     (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+                     (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+                   (alt_rssi_avg >= 4))
+                       result = true;
+               else
+                       result = false;
+               break;
+       }
+
+       return result;
+}
+
+static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
+                                     struct ath_hw_antcomb_conf ant_conf,
+                                     int main_rssi_avg)
+{
+       antcomb->quick_scan_cnt = 0;
+
+       if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+               antcomb->rssi_lna2 = main_rssi_avg;
+       else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
+               antcomb->rssi_lna1 = main_rssi_avg;
+
+       switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
+       case 0x10: /* LNA2 A-B */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+               break;
+       case 0x20: /* LNA1 A-B */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+               break;
+       case 0x21: /* LNA1 LNA2 */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->second_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               break;
+       case 0x12: /* LNA2 LNA1 */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->second_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               break;
+       case 0x13: /* LNA2 A+B */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
+               break;
+       case 0x23: /* LNA1 A+B */
+               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               antcomb->first_quick_scan_conf =
+                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
+               break;
+       default:
+               break;
+       }
+}
+
+static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
+                                      struct ath_hw_antcomb_conf *div_ant_conf,
+                                      int main_rssi_avg, int alt_rssi_avg,
+                                      int alt_ratio)
+{
+       /* alt_good */
+       switch (antcomb->quick_scan_cnt) {
+       case 0:
+               /* set alt to main, and alt to first conf */
+               div_ant_conf->main_lna_conf = antcomb->main_conf;
+               div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+               break;
+       case 1:
+               /* set alt to main, and alt to first conf */
+               div_ant_conf->main_lna_conf = antcomb->main_conf;
+               div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+               antcomb->rssi_first = main_rssi_avg;
+               antcomb->rssi_second = alt_rssi_avg;
+
+               if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+                       /* main is LNA1 */
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
+                               antcomb->first_ratio = true;
+                       else
+                               antcomb->first_ratio = false;
+               } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
+                               antcomb->first_ratio = true;
+                       else
+                               antcomb->first_ratio = false;
+               } else {
+                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+                             (alt_rssi_avg > main_rssi_avg +
+                              ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+                            (alt_rssi_avg > main_rssi_avg)) &&
+                           (antcomb->total_pkt_count > 50))
+                               antcomb->first_ratio = true;
+                       else
+                               antcomb->first_ratio = false;
+               }
+               break;
+       case 2:
+               antcomb->alt_good = false;
+               antcomb->scan_not_start = false;
+               antcomb->scan = false;
+               antcomb->rssi_first = main_rssi_avg;
+               antcomb->rssi_third = alt_rssi_avg;
+
+               if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
+                       antcomb->rssi_lna1 = alt_rssi_avg;
+               else if (antcomb->second_quick_scan_conf ==
+                        ATH_ANT_DIV_COMB_LNA2)
+                       antcomb->rssi_lna2 = alt_rssi_avg;
+               else if (antcomb->second_quick_scan_conf ==
+                        ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+                       if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+                               antcomb->rssi_lna2 = main_rssi_avg;
+                       else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+                               antcomb->rssi_lna1 = main_rssi_avg;
+               }
+
+               if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+                   ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               else
+                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+
+               if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
+                               antcomb->second_ratio = true;
+                       else
+                               antcomb->second_ratio = false;
+               } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
+                               antcomb->second_ratio = true;
+                       else
+                               antcomb->second_ratio = false;
+               } else {
+                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+                             (alt_rssi_avg > main_rssi_avg +
+                              ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+                            (alt_rssi_avg > main_rssi_avg)) &&
+                           (antcomb->total_pkt_count > 50))
+                               antcomb->second_ratio = true;
+                       else
+                               antcomb->second_ratio = false;
+               }
+
+               /* set alt to the conf with maximun ratio */
+               if (antcomb->first_ratio && antcomb->second_ratio) {
+                       if (antcomb->rssi_second > antcomb->rssi_third) {
+                               /* first alt*/
+                               if ((antcomb->first_quick_scan_conf ==
+                                   ATH_ANT_DIV_COMB_LNA1) ||
+                                   (antcomb->first_quick_scan_conf ==
+                                   ATH_ANT_DIV_COMB_LNA2))
+                                       /* Set alt LNA1 or LNA2*/
+                                       if (div_ant_conf->main_lna_conf ==
+                                           ATH_ANT_DIV_COMB_LNA2)
+                                               div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA1;
+                                       else
+                                               div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA2;
+                               else
+                                       /* Set alt to A+B or A-B */
+                                       div_ant_conf->alt_lna_conf =
+                                               antcomb->first_quick_scan_conf;
+                       } else if ((antcomb->second_quick_scan_conf ==
+                                  ATH_ANT_DIV_COMB_LNA1) ||
+                                  (antcomb->second_quick_scan_conf ==
+                                  ATH_ANT_DIV_COMB_LNA2)) {
+                               /* Set alt LNA1 or LNA2 */
+                               if (div_ant_conf->main_lna_conf ==
+                                   ATH_ANT_DIV_COMB_LNA2)
+                                       div_ant_conf->alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                               else
+                                       div_ant_conf->alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                       } else {
+                               /* Set alt to A+B or A-B */
+                               div_ant_conf->alt_lna_conf =
+                                       antcomb->second_quick_scan_conf;
+                       }
+               } else if (antcomb->first_ratio) {
+                       /* first alt */
+                       if ((antcomb->first_quick_scan_conf ==
+                           ATH_ANT_DIV_COMB_LNA1) ||
+                           (antcomb->first_quick_scan_conf ==
+                           ATH_ANT_DIV_COMB_LNA2))
+                                       /* Set alt LNA1 or LNA2 */
+                               if (div_ant_conf->main_lna_conf ==
+                                   ATH_ANT_DIV_COMB_LNA2)
+                                       div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA1;
+                               else
+                                       div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA2;
+                       else
+                               /* Set alt to A+B or A-B */
+                               div_ant_conf->alt_lna_conf =
+                                               antcomb->first_quick_scan_conf;
+               } else if (antcomb->second_ratio) {
+                               /* second alt */
+                       if ((antcomb->second_quick_scan_conf ==
+                           ATH_ANT_DIV_COMB_LNA1) ||
+                           (antcomb->second_quick_scan_conf ==
+                           ATH_ANT_DIV_COMB_LNA2))
+                               /* Set alt LNA1 or LNA2 */
+                               if (div_ant_conf->main_lna_conf ==
+                                   ATH_ANT_DIV_COMB_LNA2)
+                                       div_ant_conf->alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                               else
+                                       div_ant_conf->alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                       else
+                               /* Set alt to A+B or A-B */
+                               div_ant_conf->alt_lna_conf =
+                                               antcomb->second_quick_scan_conf;
+               } else {
+                       /* main is largest */
+                       if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                           (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+                               /* Set alt LNA1 or LNA2 */
+                               if (div_ant_conf->main_lna_conf ==
+                                   ATH_ANT_DIV_COMB_LNA2)
+                                       div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA1;
+                               else
+                                       div_ant_conf->alt_lna_conf =
+                                                       ATH_ANT_DIV_COMB_LNA2;
+                       else
+                               /* Set alt to A+B or A-B */
+                               div_ant_conf->alt_lna_conf = antcomb->main_conf;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
+                                         struct ath_ant_comb *antcomb,
+                                         int alt_ratio)
+{
+       if (ant_conf->div_group == 0) {
+               /* Adjust the fast_div_bias based on main and alt lna conf */
+               switch ((ant_conf->main_lna_conf << 4) |
+                               ant_conf->alt_lna_conf) {
+               case 0x01: /* A-B LNA2 */
+                       ant_conf->fast_div_bias = 0x3b;
+                       break;
+               case 0x02: /* A-B LNA1 */
+                       ant_conf->fast_div_bias = 0x3d;
+                       break;
+               case 0x03: /* A-B A+B */
+                       ant_conf->fast_div_bias = 0x1;
+                       break;
+               case 0x10: /* LNA2 A-B */
+                       ant_conf->fast_div_bias = 0x7;
+                       break;
+               case 0x12: /* LNA2 LNA1 */
+                       ant_conf->fast_div_bias = 0x2;
+                       break;
+               case 0x13: /* LNA2 A+B */
+                       ant_conf->fast_div_bias = 0x7;
+                       break;
+               case 0x20: /* LNA1 A-B */
+                       ant_conf->fast_div_bias = 0x6;
+                       break;
+               case 0x21: /* LNA1 LNA2 */
+                       ant_conf->fast_div_bias = 0x0;
+                       break;
+               case 0x23: /* LNA1 A+B */
+                       ant_conf->fast_div_bias = 0x6;
+                       break;
+               case 0x30: /* A+B A-B */
+                       ant_conf->fast_div_bias = 0x1;
+                       break;
+               case 0x31: /* A+B LNA2 */
+                       ant_conf->fast_div_bias = 0x3b;
+                       break;
+               case 0x32: /* A+B LNA1 */
+                       ant_conf->fast_div_bias = 0x3d;
+                       break;
+               default:
+                       break;
+               }
+       } else if (ant_conf->div_group == 1) {
+               /* Adjust the fast_div_bias based on main and alt_lna_conf */
+               switch ((ant_conf->main_lna_conf << 4) |
+                       ant_conf->alt_lna_conf) {
+               case 0x01: /* A-B LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x02: /* A-B LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x03: /* A-B A+B */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x10: /* LNA2 A-B */
+                       if (!(antcomb->scan) &&
+                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x3f;
+                       else
+                               ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x12: /* LNA2 LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x13: /* LNA2 A+B */
+                       if (!(antcomb->scan) &&
+                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x3f;
+                       else
+                               ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x20: /* LNA1 A-B */
+                       if (!(antcomb->scan) &&
+                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x3f;
+                       else
+                               ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x21: /* LNA1 LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x23: /* LNA1 A+B */
+                       if (!(antcomb->scan) &&
+                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x3f;
+                       else
+                               ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x30: /* A+B A-B */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x31: /* A+B LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x32: /* A+B LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               default:
+                       break;
+               }
+       } else if (ant_conf->div_group == 2) {
+               /* Adjust the fast_div_bias based on main and alt_lna_conf */
+               switch ((ant_conf->main_lna_conf << 4) |
+                               ant_conf->alt_lna_conf) {
+               case 0x01: /* A-B LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x02: /* A-B LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x03: /* A-B A+B */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x10: /* LNA2 A-B */
+                       if (!(antcomb->scan) &&
+                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x1;
+                       else
+                               ant_conf->fast_div_bias = 0x2;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x12: /* LNA2 LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x13: /* LNA2 A+B */
+                       if (!(antcomb->scan) &&
+                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x1;
+                       else
+                               ant_conf->fast_div_bias = 0x2;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x20: /* LNA1 A-B */
+                       if (!(antcomb->scan) &&
+                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x1;
+                       else
+                               ant_conf->fast_div_bias = 0x2;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x21: /* LNA1 LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x23: /* LNA1 A+B */
+                       if (!(antcomb->scan) &&
+                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+                               ant_conf->fast_div_bias = 0x1;
+                       else
+                               ant_conf->fast_div_bias = 0x2;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x30: /* A+B A-B */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x31: /* A+B LNA2 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               case 0x32: /* A+B LNA1 */
+                       ant_conf->fast_div_bias = 0x1;
+                       ant_conf->main_gaintb = 0;
+                       ant_conf->alt_gaintb = 0;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+{
+       struct ath_hw_antcomb_conf div_ant_conf;
+       struct ath_ant_comb *antcomb = &sc->ant_comb;
+       int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+       int curr_main_set;
+       int main_rssi = rs->rs_rssi_ctl0;
+       int alt_rssi = rs->rs_rssi_ctl1;
+       int rx_ant_conf,  main_ant_conf;
+       bool short_scan = false;
+
+       rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+                      ATH_ANT_RX_MASK;
+       main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+                        ATH_ANT_RX_MASK;
+
+       /* Record packet only when both main_rssi and  alt_rssi is positive */
+       if (main_rssi > 0 && alt_rssi > 0) {
+               antcomb->total_pkt_count++;
+               antcomb->main_total_rssi += main_rssi;
+               antcomb->alt_total_rssi  += alt_rssi;
+               if (main_ant_conf == rx_ant_conf)
+                       antcomb->main_recv_cnt++;
+               else
+                       antcomb->alt_recv_cnt++;
+       }
+
+       /* Short scan check */
+       if (antcomb->scan && antcomb->alt_good) {
+               if (time_after(jiffies, antcomb->scan_start_time +
+                   msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+                       short_scan = true;
+               else
+                       if (antcomb->total_pkt_count ==
+                           ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+                               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+                                           antcomb->total_pkt_count);
+                               if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+                                       short_scan = true;
+                       }
+       }
+
+       if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+           rs->rs_moreaggr) && !short_scan)
+               return;
+
+       if (antcomb->total_pkt_count) {
+               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+                            antcomb->total_pkt_count);
+               main_rssi_avg = (antcomb->main_total_rssi /
+                                antcomb->total_pkt_count);
+               alt_rssi_avg = (antcomb->alt_total_rssi /
+                                antcomb->total_pkt_count);
+       }
+
+
+       ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+       curr_alt_set = div_ant_conf.alt_lna_conf;
+       curr_main_set = div_ant_conf.main_lna_conf;
+
+       antcomb->count++;
+
+       if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+               if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+                       ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
+                                                 main_rssi_avg);
+                       antcomb->alt_good = true;
+               } else {
+                       antcomb->alt_good = false;
+               }
+
+               antcomb->count = 0;
+               antcomb->scan = true;
+               antcomb->scan_not_start = true;
+       }
+
+       if (!antcomb->scan) {
+               if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+                                       alt_ratio, curr_main_set, curr_alt_set,
+                                       alt_rssi_avg, main_rssi_avg)) {
+                       if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+                               /* Switch main and alt LNA */
+                               div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                               div_ant_conf.alt_lna_conf  =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                       } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+                               div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                               div_ant_conf.alt_lna_conf  =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                       }
+
+                       goto div_comb_done;
+               } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+                          (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+                       /* Set alt to another LNA */
+                       if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+                               div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                       else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+                               div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+
+                       goto div_comb_done;
+               }
+
+               if ((alt_rssi_avg < (main_rssi_avg +
+                                    div_ant_conf.lna1_lna2_delta)))
+                       goto div_comb_done;
+       }
+
+       if (!antcomb->scan_not_start) {
+               switch (curr_alt_set) {
+               case ATH_ANT_DIV_COMB_LNA2:
+                       antcomb->rssi_lna2 = alt_rssi_avg;
+                       antcomb->rssi_lna1 = main_rssi_avg;
+                       antcomb->scan = true;
+                       /* set to A+B */
+                       div_ant_conf.main_lna_conf =
+                               ATH_ANT_DIV_COMB_LNA1;
+                       div_ant_conf.alt_lna_conf  =
+                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                       break;
+               case ATH_ANT_DIV_COMB_LNA1:
+                       antcomb->rssi_lna1 = alt_rssi_avg;
+                       antcomb->rssi_lna2 = main_rssi_avg;
+                       antcomb->scan = true;
+                       /* set to A+B */
+                       div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                       div_ant_conf.alt_lna_conf  =
+                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                       break;
+               case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+                       antcomb->rssi_add = alt_rssi_avg;
+                       antcomb->scan = true;
+                       /* set to A-B */
+                       div_ant_conf.alt_lna_conf =
+                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+                       break;
+               case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+                       antcomb->rssi_sub = alt_rssi_avg;
+                       antcomb->scan = false;
+                       if (antcomb->rssi_lna2 >
+                           (antcomb->rssi_lna1 +
+                           ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+                               /* use LNA2 as main LNA */
+                               if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
+                                       /* set to A+B */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                                       div_ant_conf.alt_lna_conf  =
+                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                               } else if (antcomb->rssi_sub >
+                                          antcomb->rssi_lna1) {
+                                       /* set to A-B */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                                       div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+                               } else {
+                                       /* set to LNA1 */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                                       div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                               }
+                       } else {
+                               /* use LNA1 as main LNA */
+                               if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
+                                       /* set to A+B */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                                       div_ant_conf.alt_lna_conf  =
+                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                               } else if (antcomb->rssi_sub >
+                                          antcomb->rssi_lna1) {
+                                       /* set to A-B */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                                       div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+                               } else {
+                                       /* set to LNA2 */
+                                       div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                                       div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               if (!antcomb->alt_good) {
+                       antcomb->scan_not_start = false;
+                       /* Set alt to another LNA */
+                       if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+                               div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                               div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                       } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+                               div_ant_conf.main_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA1;
+                               div_ant_conf.alt_lna_conf =
+                                               ATH_ANT_DIV_COMB_LNA2;
+                       }
+                       goto div_comb_done;
+               }
+       }
+
+       ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+                                          main_rssi_avg, alt_rssi_avg,
+                                          alt_ratio);
+
+       antcomb->quick_scan_cnt++;
+
+div_comb_done:
+       ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
+       ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+       antcomb->scan_start_time = jiffies;
+       antcomb->total_pkt_count = 0;
+       antcomb->main_total_rssi = 0;
+       antcomb->alt_total_rssi = 0;
+       antcomb->main_recv_cnt = 0;
+       antcomb->alt_recv_cnt = 0;
+}
+
+void ath_ant_comb_update(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_hw_antcomb_conf div_ant_conf;
+       u8 lna_conf;
+
+       ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+
+       if (sc->ant_rx == 1)
+               lna_conf = ATH_ANT_DIV_COMB_LNA1;
+       else
+               lna_conf = ATH_ANT_DIV_COMB_LNA2;
+
+       div_ant_conf.main_lna_conf = lna_conf;
+       div_ant_conf.alt_lna_conf = lna_conf;
+
+       ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+}
index c7492c6a25193402f9817d4d04a0e2edfb78d9c4..874186bfda41d1fd93a3838725ab3e95d3210369 100644 (file)
@@ -995,141 +995,6 @@ static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah,
        return pll;
 }
 
-static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
-                                     enum ath9k_ani_cmd cmd,
-                                     int param)
-{
-       struct ar5416AniState *aniState = &ah->curchan->ani;
-       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)) {
-                       ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-                               level, ARRAY_SIZE(ah->totalSizeDesired));
-                       return false;
-               }
-
-               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-                             AR_PHY_DESIRED_SZ_TOT_DES,
-                             ah->totalSizeDesired[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_LOW,
-                             ah->coarse_low[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_HIGH,
-                             ah->coarse_high[level]);
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRPWR,
-                             ah->firpwr[level]);
-
-               if (level > aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_niup++;
-               else if (level < aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_nidown++;
-               aniState->noiseImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
-               u32 on = param ? 1 : 0;
-
-               if (on)
-                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-               else
-                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-               if (!on != aniState->ofdmWeakSigDetectOff) {
-                       if (on)
-                               ah->stats.ast_ani_ofdmon++;
-                       else
-                               ah->stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
-               }
-               break;
-       }
-       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-               static const int weakSigThrCck[] = { 8, 6 };
-               u32 high = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
-                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
-                             weakSigThrCck[high]);
-               if (high != aniState->cckWeakSigThreshold) {
-                       if (high)
-                               ah->stats.ast_ani_cckhigh++;
-                       else
-                               ah->stats.ast_ani_ccklow++;
-                       aniState->cckWeakSigThreshold = high;
-               }
-               break;
-       }
-       case ATH9K_ANI_FIRSTEP_LEVEL:{
-               static const int firstep[] = { 0, 4, 8 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(firstep)) {
-                       ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-                               level, ARRAY_SIZE(firstep));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRSTEP,
-                             firstep[level]);
-               if (level > aniState->firstepLevel)
-                       ah->stats.ast_ani_stepup++;
-               else if (level < aniState->firstepLevel)
-                       ah->stats.ast_ani_stepdown++;
-               aniState->firstepLevel = level;
-               break;
-       }
-       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-               static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(cycpwrThr1)) {
-                       ath_dbg(common, ANI, "level out of range (%u > %zu)\n",
-                               level, ARRAY_SIZE(cycpwrThr1));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
-                             AR_PHY_TIMING5_CYCPWR_THR1,
-                             cycpwrThr1[level]);
-               if (level > aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurup++;
-               else if (level < aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurdown++;
-               aniState->spurImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_PRESENT:
-               break;
-       default:
-               ath_dbg(common, ANI, "invalid cmd %u\n", cmd);
-               return false;
-       }
-
-       ath_dbg(common, ANI, "ANI parameters:\n");
-       ath_dbg(common, ANI,
-               "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
-               aniState->noiseImmunityLevel,
-               aniState->spurImmunityLevel,
-               !aniState->ofdmWeakSigDetectOff);
-       ath_dbg(common, ANI,
-               "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
-               aniState->cckWeakSigThreshold,
-               aniState->firstepLevel,
-               aniState->listenTime);
-       ath_dbg(common, ANI, "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-               aniState->ofdmPhyErrCount,
-               aniState->cckPhyErrCount);
-
-       return true;
-}
-
 static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                      enum ath9k_ani_cmd cmd,
                                      int param)
@@ -1206,18 +1071,18 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                        REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
                                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 
-               if (!on != aniState->ofdmWeakSigDetectOff) {
+               if (on != aniState->ofdmWeakSigDetect) {
                        ath_dbg(common, ANI,
                                "** ch %d: ofdm weak signal: %s=>%s\n",
                                chan->channel,
-                               !aniState->ofdmWeakSigDetectOff ?
+                               aniState->ofdmWeakSigDetect ?
                                "on" : "off",
                                on ? "on" : "off");
                        if (on)
                                ah->stats.ast_ani_ofdmon++;
                        else
                                ah->stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
+                       aniState->ofdmWeakSigDetect = on;
                }
                break;
        }
@@ -1236,7 +1101,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value = firstep_table[level] -
-                       firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+                       firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
                        aniState->iniDef.firstep;
                if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
                        value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -1251,7 +1116,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value2 = firstep_table[level] -
-                        firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+                        firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
                         aniState->iniDef.firstepLow;
                if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
                        value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -1267,7 +1132,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                chan->channel,
                                aniState->firstepLevel,
                                level,
-                               ATH9K_ANI_FIRSTEP_LVL_NEW,
+                               ATH9K_ANI_FIRSTEP_LVL,
                                value,
                                aniState->iniDef.firstep);
                        ath_dbg(common, ANI,
@@ -1275,7 +1140,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                chan->channel,
                                aniState->firstepLevel,
                                level,
-                               ATH9K_ANI_FIRSTEP_LVL_NEW,
+                               ATH9K_ANI_FIRSTEP_LVL,
                                value2,
                                aniState->iniDef.firstepLow);
                        if (level > aniState->firstepLevel)
@@ -1300,7 +1165,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value = cycpwrThr1_table[level] -
-                       cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+                       cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
                        aniState->iniDef.cycpwrThr1;
                if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
                        value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -1316,7 +1181,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value2 = cycpwrThr1_table[level] -
-                        cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+                        cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
                         aniState->iniDef.cycpwrThr1Ext;
                if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
                        value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -1331,7 +1196,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                chan->channel,
                                aniState->spurImmunityLevel,
                                level,
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+                               ATH9K_ANI_SPUR_IMMUNE_LVL,
                                value,
                                aniState->iniDef.cycpwrThr1);
                        ath_dbg(common, ANI,
@@ -1339,7 +1204,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
                                chan->channel,
                                aniState->spurImmunityLevel,
                                level,
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+                               ATH9K_ANI_SPUR_IMMUNE_LVL,
                                value2,
                                aniState->iniDef.cycpwrThr1Ext);
                        if (level > aniState->spurImmunityLevel)
@@ -1367,9 +1232,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
        ath_dbg(common, ANI,
                "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
                aniState->spurImmunityLevel,
-               !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+               aniState->ofdmWeakSigDetect ? "on" : "off",
                aniState->firstepLevel,
-               !aniState->mrcCCKOff ? "on" : "off",
+               aniState->mrcCCK ? "on" : "off",
                aniState->listenTime,
                aniState->ofdmPhyErrCount,
                aniState->cckPhyErrCount);
@@ -1454,10 +1319,10 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
                                               AR_PHY_EXT_TIMING5_CYCPWR_THR1);
 
        /* these levels just got reset to defaults by the INI */
-       aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
-       aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
-       aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
-       aniState->mrcCCKOff = true; /* not available on pre AR9003 */
+       aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+       aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+       aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+       aniState->mrcCCK = false; /* not available on pre AR9003 */
 }
 
 static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
@@ -1545,11 +1410,8 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
        priv_ops->do_getnf = ar5008_hw_do_getnf;
        priv_ops->set_radar_params = ar5008_hw_set_radar_params;
 
-       if (modparam_force_new_ani) {
-               priv_ops->ani_control = ar5008_hw_ani_control_new;
-               priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
-       } else
-               priv_ops->ani_control = ar5008_hw_ani_control_old;
+       priv_ops->ani_control = ar5008_hw_ani_control_new;
+       priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
 
        if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
                priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
index d9a69fc470cde856591140317c3f3a7121faaf42..edf21ea4fe930ee19fe508d7c01d58dc153c3892 100644 (file)
 #include "ar9002_initvals.h"
 #include "ar9002_phy.h"
 
-int modparam_force_new_ani;
-module_param_named(force_new_ani, modparam_force_new_ani, int, 0444);
-MODULE_PARM_DESC(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002");
-
 /* General hardware code for the A5008/AR9001/AR9002 hadware families */
 
 static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
index 952cb2b4656ba2a3149bb3eb2bd1d773399f28f3..89bf94d4d8a1e1799715eacf684bdd6892e419c9 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
index 9fdd70fcaf5b551375f69fe4f294790b318bf9d5..d7deb8c9f29952c295fa094d0274953d6368d352 100644 (file)
@@ -653,7 +653,6 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
 }
 
 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
-                                                u8 num_chains,
                                                 struct coeff *coeff,
                                                 bool is_reusable)
 {
@@ -677,7 +676,9 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
        }
 
        /* Load the average of 2 passes */
-       for (i = 0; i < num_chains; i++) {
+       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+               if (!(ah->txchainmask & (1 << i)))
+                       continue;
                nmeasurement = REG_READ_FIELD(ah,
                                AR_PHY_TX_IQCAL_STATUS_B0,
                                AR_PHY_CALIBRATED_GAINS_0);
@@ -767,16 +768,13 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
        };
        struct coeff coeff;
        s32 iq_res[6];
-       u8 num_chains = 0;
        int i, im, j;
        int nmeasurement;
 
        for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-               if (ah->txchainmask & (1 << i))
-                       num_chains++;
-       }
+               if (!(ah->txchainmask & (1 << i)))
+                       continue;
 
-       for (i = 0; i < num_chains; i++) {
                nmeasurement = REG_READ_FIELD(ah,
                                AR_PHY_TX_IQCAL_STATUS_B0,
                                AR_PHY_CALIBRATED_GAINS_0);
@@ -839,8 +837,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
                                coeff.phs_coeff[i][im] -= 128;
                }
        }
-       ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
-                                            &coeff, is_reusable);
+       ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
 
        return;
 
@@ -901,7 +898,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        bool is_reusable = true, status = true;
        bool run_rtt_cal = false, run_agc_cal;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
-       bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -970,7 +966,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        } else if (caldata && !caldata->done_txiqcal_once)
                run_agc_cal = true;
 
-       if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+       if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
                ar9003_mci_init_cal_req(ah, &is_reusable);
 
        if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
@@ -993,7 +989,7 @@ skip_tx_iqcal:
                                       0, AH_WAIT_TIMEOUT);
        }
 
-       if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
+       if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
                ar9003_mci_init_cal_done(ah);
 
        if (rtt && !run_rtt_cal) {
index dfb0441f406c24e59c10fac636007d7337cd4b65..2cdf82bdb11d112424f930cb523412fc01bbd254 100644 (file)
@@ -3412,11 +3412,11 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        if (!dump_base_hdr) {
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "2GHz modal Header");
-               len += ar9003_dump_modal_eeprom(buf, len, size,
+               len = ar9003_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader2G);
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "5GHz modal Header");
-               len += ar9003_dump_modal_eeprom(buf, len, size,
+               len = ar9003_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader5G);
                goto out;
        }
@@ -3613,6 +3613,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
                value = ar9003_switch_com_spdt_get(ah, is2ghz);
                REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
                                AR_SWITCH_TABLE_COM_SPDT_ALL, value);
+               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_SPDT_ENABLE);
        }
 
        value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
index d9e0824af0933ffc3d008eff856e504c508b5b2b..78816b8b2173cf8e238d56e1fcf981bf027ff009 100644 (file)
@@ -181,11 +181,14 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
        u32 mask2 = 0;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 sync_cause = 0, async_cause;
+       u32 sync_cause = 0, async_cause, async_mask = AR_INTR_MAC_IRQ;
+
+       if (ath9k_hw_mci_is_enabled(ah))
+               async_mask |= AR_INTR_ASYNC_MASK_MCI;
 
        async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
 
-       if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) {
+       if (async_cause & async_mask) {
                if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
                                == AR_RTC_STATUS_ON)
                        isr = REG_READ(ah, AR_ISR);
index ffbb180f91e166db56106cd345d3e55553381723..61558375bfbfcb08cb7fee3eb3e1a19808a3ebcc 100644 (file)
@@ -35,31 +35,30 @@ static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
        struct ath_common *common = ath9k_hw_common(ah);
 
        while (time_out) {
-               if (REG_READ(ah, address) & bit_position) {
-                       REG_WRITE(ah, address, bit_position);
-
-                       if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
-                               if (bit_position &
-                                   AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
-                                       ar9003_mci_reset_req_wakeup(ah);
-
-                               if (bit_position &
-                                   (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
-                                    AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
-                                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-                                       AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
-
-                               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-                                         AR_MCI_INTERRUPT_RX_MSG);
-                       }
-                       break;
-               }
+               if (!(REG_READ(ah, address) & bit_position)) {
+                       udelay(10);
+                       time_out -= 10;
 
-               udelay(10);
-               time_out -= 10;
+                       if (time_out < 0)
+                               break;
+                       else
+                               continue;
+               }
+               REG_WRITE(ah, address, bit_position);
 
-               if (time_out < 0)
+               if (address != AR_MCI_INTERRUPT_RX_MSG_RAW)
                        break;
+
+               if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
+                       ar9003_mci_reset_req_wakeup(ah);
+
+               if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
+                                   AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
+                       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
+                                 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
+
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG);
+               break;
        }
 
        if (time_out <= 0) {
@@ -127,14 +126,13 @@ static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
-       if (!mci->bt_version_known &&
-           (mci->bt_state != MCI_BT_SLEEP)) {
-               MCI_GPM_SET_TYPE_OPCODE(payload,
-                                       MCI_GPM_COEX_AGENT,
-                                       MCI_GPM_COEX_VERSION_QUERY);
-               ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-                                       wait_done, true);
-       }
+       if (mci->bt_version_known ||
+           (mci->bt_state == MCI_BT_SLEEP))
+               return;
+
+       MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                               MCI_GPM_COEX_VERSION_QUERY);
+       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
 }
 
 static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
@@ -158,15 +156,14 @@ static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 *payload = &mci->wlan_channels[0];
 
-       if ((mci->wlan_channels_update == true) &&
-           (mci->bt_state != MCI_BT_SLEEP)) {
-               MCI_GPM_SET_TYPE_OPCODE(payload,
-                                       MCI_GPM_COEX_AGENT,
-                                       MCI_GPM_COEX_WLAN_CHANNELS);
-               ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-                                       wait_done, true);
-               MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
-       }
+       if (!mci->wlan_channels_update ||
+           (mci->bt_state == MCI_BT_SLEEP))
+               return;
+
+       MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                               MCI_GPM_COEX_WLAN_CHANNELS);
+       ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
+       MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
 }
 
 static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
@@ -174,29 +171,30 @@ static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
-       bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
-                                            MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+       bool query_btinfo;
 
-       if (mci->bt_state != MCI_BT_SLEEP) {
-
-               MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
-                                       MCI_GPM_COEX_STATUS_QUERY);
+       if (mci->bt_state == MCI_BT_SLEEP)
+               return;
 
-               *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
+       query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
+                                       MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
+       MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
+                               MCI_GPM_COEX_STATUS_QUERY);
 
-               /*
-                * If bt_status_query message is  not sent successfully,
-                * then need_flush_btinfo should be set again.
-                */
-               if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
-                                            wait_done, true)) {
-                       if (query_btinfo)
-                               mci->need_flush_btinfo = true;
-               }
+       *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
 
+       /*
+        * If bt_status_query message is  not sent successfully,
+        * then need_flush_btinfo should be set again.
+        */
+       if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
+                               wait_done, true)) {
                if (query_btinfo)
-                       mci->query_bt = false;
+                       mci->need_flush_btinfo = true;
        }
+
+       if (query_btinfo)
+               mci->query_bt = false;
 }
 
 static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
@@ -241,73 +239,73 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah)
        ar9003_mci_remote_reset(ah, true);
        ar9003_mci_send_req_wake(ah, true);
 
-       if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                                 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
+       if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500))
+               goto clear_redunt;
 
-               mci->bt_state = MCI_BT_AWAKE;
+       mci->bt_state = MCI_BT_AWAKE;
 
-               /*
-                * we don't need to send more remote_reset at this moment.
-                * If BT receive first remote_reset, then BT HW will
-                * be cleaned up and will be able to receive req_wake
-                * and BT HW will respond sys_waking.
-                * In this case, WLAN will receive BT's HW sys_waking.
-                * Otherwise, if BT SW missed initial remote_reset,
-                * that remote_reset will still clean up BT MCI RX,
-                * and the req_wake will wake BT up,
-                * and BT SW will respond this req_wake with a remote_reset and
-                * sys_waking. In this case, WLAN will receive BT's SW
-                * sys_waking. In either case, BT's RX is cleaned up. So we
-                * don't need to reply BT's remote_reset now, if any.
-                * Similarly, if in any case, WLAN can receive BT's sys_waking,
-                * that means WLAN's RX is also fine.
-                */
-               ar9003_mci_send_sys_waking(ah, true);
-               udelay(10);
+       /*
+        * we don't need to send more remote_reset at this moment.
+        * If BT receive first remote_reset, then BT HW will
+        * be cleaned up and will be able to receive req_wake
+        * and BT HW will respond sys_waking.
+        * In this case, WLAN will receive BT's HW sys_waking.
+        * Otherwise, if BT SW missed initial remote_reset,
+        * that remote_reset will still clean up BT MCI RX,
+        * and the req_wake will wake BT up,
+        * and BT SW will respond this req_wake with a remote_reset and
+        * sys_waking. In this case, WLAN will receive BT's SW
+        * sys_waking. In either case, BT's RX is cleaned up. So we
+        * don't need to reply BT's remote_reset now, if any.
+        * Similarly, if in any case, WLAN can receive BT's sys_waking,
+        * that means WLAN's RX is also fine.
+        */
+       ar9003_mci_send_sys_waking(ah, true);
+       udelay(10);
 
-               /*
-                * Set BT priority interrupt value to be 0xff to
-                * avoid having too many BT PRIORITY interrupts.
-                */
-               REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
-               REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
-               REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
-               REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
-               REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
+       /*
+        * Set BT priority interrupt value to be 0xff to
+        * avoid having too many BT PRIORITY interrupts.
+        */
+       REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
 
-               /*
-                * A contention reset will be received after send out
-                * sys_waking. Also BT priority interrupt bits will be set.
-                * Clear those bits before the next step.
-                */
+       /*
+        * A contention reset will be received after send out
+        * sys_waking. Also BT priority interrupt bits will be set.
+        * Clear those bits before the next step.
+        */
 
-               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                         AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
-               REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
-                         AR_MCI_INTERRUPT_BT_PRI);
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                 AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI);
 
-               if (mci->is_2g) {
-                       ar9003_mci_send_lna_transfer(ah, true);
-                       udelay(5);
-               }
+       if (mci->is_2g) {
+               ar9003_mci_send_lna_transfer(ah, true);
+               udelay(5);
+       }
 
-               if ((mci->is_2g && !mci->update_2g5g)) {
-                       if (ar9003_mci_wait_for_interrupt(ah,
-                                         AR_MCI_INTERRUPT_RX_MSG_RAW,
-                                         AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
-                                         mci_timeout))
-                               ath_dbg(common, MCI,
-                                       "MCI WLAN has control over the LNA & BT obeys it\n");
-                       else
-                               ath_dbg(common, MCI,
-                                       "MCI BT didn't respond to LNA_TRANS\n");
-               }
+       if ((mci->is_2g && !mci->update_2g5g)) {
+               if (ar9003_mci_wait_for_interrupt(ah,
+                                       AR_MCI_INTERRUPT_RX_MSG_RAW,
+                                       AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
+                                       mci_timeout))
+                       ath_dbg(common, MCI,
+                               "MCI WLAN has control over the LNA & BT obeys it\n");
+               else
+                       ath_dbg(common, MCI,
+                               "MCI BT didn't respond to LNA_TRANS\n");
        }
 
+clear_redunt:
        /* Clear the extra redundant SYS_WAKING from BT */
        if ((mci->bt_state == MCI_BT_AWAKE) &&
-               (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                               AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
+           (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                           AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
            (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
                            AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
                REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
@@ -323,14 +321,13 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE) &&
            (mci->bt_state != MCI_BT_SLEEP) &&
            !mci->halted_bt_gpm) {
                ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
        }
 
        mci->ready = false;
-       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 }
 
 static void ar9003_mci_disable_interrupt(struct ath_hw *ah)
@@ -487,7 +484,7 @@ static void ar9003_mci_sync_bt_state(struct ath_hw *ah)
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 cur_bt_state;
 
-       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
+       cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP);
 
        if (mci->bt_state != cur_bt_state)
                mci->bt_state = cur_bt_state;
@@ -596,8 +593,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
                if (!time_out)
                        break;
 
-               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                         &more_data);
+               offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
 
                if (offset == MCI_GPM_INVALID)
                        continue;
@@ -615,9 +611,9 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
                                }
                                break;
                        }
-               } else if ((recv_type == gpm_type) && (recv_opcode == gpm_opcode)) {
+               } else if ((recv_type == gpm_type) &&
+                          (recv_opcode == gpm_opcode))
                        break;
-               }
 
                /*
                 * check if it's cal_grant
@@ -661,8 +657,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
                time_out = 0;
 
        while (more_data == MCI_GPM_MORE) {
-               offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                         &more_data);
+               offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data);
                if (offset == MCI_GPM_INVALID)
                        break;
 
@@ -731,38 +726,38 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
                goto exit;
 
-       if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
-           ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
+       if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) &&
+           !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE))
+               goto exit;
 
-               /*
-                * BT is sleeping. Check if BT wakes up during
-                * WLAN calibration. If BT wakes up during
-                * WLAN calibration, need to go through all
-                * message exchanges again and recal.
-                */
-               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                         AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
-                         AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
+       /*
+        * BT is sleeping. Check if BT wakes up during
+        * WLAN calibration. If BT wakes up during
+        * WLAN calibration, need to go through all
+        * message exchanges again and recal.
+        */
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                 (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
+                  AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE));
 
-               ar9003_mci_remote_reset(ah, true);
-               ar9003_mci_send_sys_waking(ah, true);
-               udelay(1);
+       ar9003_mci_remote_reset(ah, true);
+       ar9003_mci_send_sys_waking(ah, true);
+       udelay(1);
 
-               if (IS_CHAN_2GHZ(chan))
-                       ar9003_mci_send_lna_transfer(ah, true);
+       if (IS_CHAN_2GHZ(chan))
+               ar9003_mci_send_lna_transfer(ah, true);
 
-               mci_hw->bt_state = MCI_BT_AWAKE;
+       mci_hw->bt_state = MCI_BT_AWAKE;
 
-               if (caldata) {
-                       caldata->done_txiqcal_once = false;
-                       caldata->done_txclcal_once = false;
-                       caldata->rtt_done = false;
-               }
+       if (caldata) {
+               caldata->done_txiqcal_once = false;
+               caldata->done_txclcal_once = false;
+               caldata->rtt_done = false;
+       }
 
-               if (!ath9k_hw_init_cal(ah, chan))
-                       return -EIO;
+       if (!ath9k_hw_init_cal(ah, chan))
+               return -EIO;
 
-       }
 exit:
        ar9003_mci_enable_interrupt(ah);
        return 0;
@@ -772,10 +767,6 @@ static void ar9003_mci_mute_bt(struct ath_hw *ah)
 {
        /* disable all MCI messages */
        REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
-       REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
        REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
 
        /* wait pending HW messages to flush out */
@@ -798,29 +789,27 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable)
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 thresh;
 
-       if (enable) {
-               REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-                             AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
-               REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
-                             AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
-
-               if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
-                       thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
-                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-                                     AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
-                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-                                     AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
-               } else {
-                       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-                                     AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
-               }
-
-               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
-                             AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
-       } else {
+       if (!enable) {
                REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
                            AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+               return;
        }
+       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
+       REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
+                     AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
+
+       if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
+               thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                             AR_BTCOEX_CTRL_AGGR_THRESH, thresh);
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                             AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1);
+       } else
+               REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                             AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0);
+
+       REG_RMW_FIELD(ah, AR_BTCOEX_CTRL,
+                     AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1);
 }
 
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
@@ -898,13 +887,16 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                udelay(100);
        }
 
+       /* Check pending GPM msg before MCI Reset Rx */
+       ar9003_mci_check_gpm_offset(ah);
+
        regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
        REG_WRITE(ah, AR_MCI_COMMAND2, regval);
        udelay(1);
        regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
        REG_WRITE(ah, AR_MCI_COMMAND2, regval);
 
-       ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+       ar9003_mci_get_next_gpm_offset(ah, true, NULL);
 
        REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
                  (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
@@ -943,26 +935,27 @@ static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        u32 new_flags, to_set, to_clear;
 
-       if (mci->update_2g5g && (mci->bt_state != MCI_BT_SLEEP)) {
-               if (mci->is_2g) {
-                       new_flags = MCI_2G_FLAGS;
-                       to_clear = MCI_2G_FLAGS_CLEAR_MASK;
-                       to_set = MCI_2G_FLAGS_SET_MASK;
-               } else {
-                       new_flags = MCI_5G_FLAGS;
-                       to_clear = MCI_5G_FLAGS_CLEAR_MASK;
-                       to_set = MCI_5G_FLAGS_SET_MASK;
-               }
+       if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP))
+               return;
+
+       if (mci->is_2g) {
+               new_flags = MCI_2G_FLAGS;
+               to_clear = MCI_2G_FLAGS_CLEAR_MASK;
+               to_set = MCI_2G_FLAGS_SET_MASK;
+       } else {
+               new_flags = MCI_5G_FLAGS;
+               to_clear = MCI_5G_FLAGS_CLEAR_MASK;
+               to_set = MCI_5G_FLAGS_SET_MASK;
+       }
 
-               if (to_clear)
-                       ar9003_mci_send_coex_bt_flags(ah, wait_done,
+       if (to_clear)
+               ar9003_mci_send_coex_bt_flags(ah, wait_done,
                                              MCI_GPM_COEX_BT_FLAGS_CLEAR,
                                              to_clear);
-               if (to_set)
-                       ar9003_mci_send_coex_bt_flags(ah, wait_done,
+       if (to_set)
+               ar9003_mci_send_coex_bt_flags(ah, wait_done,
                                              MCI_GPM_COEX_BT_FLAGS_SET,
                                              to_set);
-       }
 }
 
 static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
@@ -1014,38 +1007,42 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
        }
 }
 
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
 {
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
 
-       if (mci->update_2g5g) {
-               if (mci->is_2g) {
+       if (!mci->update_2g5g && !force)
+               return;
+
+       if (mci->is_2g) {
+               if (!force) {
                        ar9003_mci_send_2g5g_status(ah, true);
+
                        ar9003_mci_send_lna_transfer(ah, true);
                        udelay(5);
+               }
 
-                       REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
-                                   AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-                       REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
-                                   AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+               REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+                           AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+               REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
+                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
-                       if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
-                               REG_SET_BIT(ah, AR_BTCOEX_CTRL,
-                                           AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
-                       }
-               } else {
+               if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
+                       ar9003_mci_osla_setup(ah, true);
+       } else {
+               if (!force) {
                        ar9003_mci_send_lna_take(ah, true);
                        udelay(5);
+               }
 
-                       REG_SET_BIT(ah, AR_MCI_TX_CTRL,
-                                   AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
-                       REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
-                                   AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
-                       REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
-                                   AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+               REG_SET_BIT(ah, AR_MCI_TX_CTRL,
+                           AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
+               REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
+                           AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
 
+               ar9003_mci_osla_setup(ah, false);
+               if (!force)
                        ar9003_mci_send_2g5g_status(ah, true);
-               }
        }
 }
 
@@ -1132,7 +1129,7 @@ void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
        if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
                ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n");
        } else {
-               is_reusable = false;
+               *is_reusable = false;
                ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n");
        }
 }
@@ -1173,11 +1170,10 @@ void ar9003_mci_cleanup(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ar9003_mci_cleanup);
 
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
-       u32 value = 0, more_gpm = 0, gpm_ptr;
+       u32 value = 0;
        u8 query_type;
 
        switch (state_type) {
@@ -1190,81 +1186,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                }
                value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
                break;
-       case MCI_STATE_INIT_GPM_OFFSET:
-               value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-               mci->gpm_idx = value;
-               break;
-       case MCI_STATE_NEXT_GPM_OFFSET:
-       case MCI_STATE_LAST_GPM_OFFSET:
-               /*
-               * This could be useful to avoid new GPM message interrupt which
-               * may lead to spurious interrupt after power sleep, or multiple
-               * entry of ath_mci_intr().
-               * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
-               * alleviate this effect, but clearing GPM RX interrupt bit is
-               * safe, because whether this is called from hw or driver code
-               * there must be an interrupt bit set/triggered initially
-               */
-               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
-                         AR_MCI_INTERRUPT_RX_MSG_GPM);
-
-               gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
-               value = gpm_ptr;
-
-               if (value == 0)
-                       value = mci->gpm_len - 1;
-               else if (value >= mci->gpm_len) {
-                       if (value != 0xFFFF)
-                               value = 0;
-               } else {
-                       value--;
-               }
-
-               if (value == 0xFFFF) {
-                       value = MCI_GPM_INVALID;
-                       more_gpm = MCI_GPM_NOMORE;
-               } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
-                       if (gpm_ptr == mci->gpm_idx) {
-                               value = MCI_GPM_INVALID;
-                               more_gpm = MCI_GPM_NOMORE;
-                       } else {
-                               for (;;) {
-                                       u32 temp_index;
-
-                                       /* skip reserved GPM if any */
-
-                                       if (value != mci->gpm_idx)
-                                               more_gpm = MCI_GPM_MORE;
-                                       else
-                                               more_gpm = MCI_GPM_NOMORE;
-
-                                       temp_index = mci->gpm_idx;
-                                       mci->gpm_idx++;
-
-                                       if (mci->gpm_idx >=
-                                           mci->gpm_len)
-                                               mci->gpm_idx = 0;
-
-                                       if (ar9003_mci_is_gpm_valid(ah,
-                                                                   temp_index)) {
-                                               value = temp_index;
-                                               break;
-                                       }
-
-                                       if (more_gpm == MCI_GPM_NOMORE) {
-                                               value = MCI_GPM_INVALID;
-                                               break;
-                                       }
-                               }
-                       }
-                       if (p_data)
-                               *p_data = more_gpm;
-                       }
-
-                       if (value != MCI_GPM_INVALID)
-                               value <<= 4;
-
-                       break;
        case MCI_STATE_LAST_SCHD_MSG_OFFSET:
                value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
                                    AR_MCI_RX_LAST_SCHD_MSG_INDEX);
@@ -1276,21 +1197,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                           AR_MCI_RX_REMOTE_SLEEP) ?
                        MCI_BT_SLEEP : MCI_BT_AWAKE;
                break;
-       case MCI_STATE_CONT_RSSI_POWER:
-               value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
-               break;
-       case MCI_STATE_CONT_PRIORITY:
-               value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
-               break;
-       case MCI_STATE_CONT_TXRX:
-               value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
-               break;
-       case MCI_STATE_BT:
-               value = mci->bt_state;
-               break;
-       case MCI_STATE_SET_BT_SLEEP:
-               mci->bt_state = MCI_BT_SLEEP;
-               break;
        case MCI_STATE_SET_BT_AWAKE:
                mci->bt_state = MCI_BT_AWAKE;
                ar9003_mci_send_coex_version_query(ah, true);
@@ -1299,7 +1205,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                if (mci->unhalt_bt_gpm)
                        ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
 
-               ar9003_mci_2g5g_switch(ah, true);
+               ar9003_mci_2g5g_switch(ah, false);
                break;
        case MCI_STATE_SET_BT_CAL_START:
                mci->bt_state = MCI_BT_CAL_START;
@@ -1323,34 +1229,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
        case MCI_STATE_SEND_WLAN_COEX_VERSION:
                ar9003_mci_send_coex_version_response(ah, true);
                break;
-       case MCI_STATE_SET_BT_COEX_VERSION:
-               if (!p_data)
-                       ath_dbg(common, MCI,
-                               "MCI Set BT Coex version with NULL data!!\n");
-               else {
-                       mci->bt_ver_major = (*p_data >> 8) & 0xff;
-                       mci->bt_ver_minor = (*p_data) & 0xff;
-                       mci->bt_version_known = true;
-                       ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
-                               mci->bt_ver_major, mci->bt_ver_minor);
-               }
-               break;
-       case MCI_STATE_SEND_WLAN_CHANNELS:
-               if (p_data) {
-                       if (((mci->wlan_channels[1] & 0xffff0000) ==
-                            (*(p_data + 1) & 0xffff0000)) &&
-                           (mci->wlan_channels[2] == *(p_data + 2)) &&
-                           (mci->wlan_channels[3] == *(p_data + 3)))
-                               break;
-
-                       mci->wlan_channels[0] = *p_data++;
-                       mci->wlan_channels[1] = *p_data++;
-                       mci->wlan_channels[2] = *p_data++;
-                       mci->wlan_channels[3] = *p_data++;
-               }
-               mci->wlan_channels_update = true;
-               ar9003_mci_send_coex_wlan_channels(ah, true);
-               break;
        case MCI_STATE_SEND_VERSION_QUERY:
                ar9003_mci_send_coex_version_query(ah, true);
                break;
@@ -1358,38 +1236,16 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
                ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
                break;
-       case MCI_STATE_NEED_FLUSH_BT_INFO:
-                       /*
-                        * btcoex_hw.mci.unhalt_bt_gpm means whether it's
-                        * needed to send UNHALT message. It's set whenever
-                        * there's a request to send HALT message.
-                        * mci_halted_bt_gpm means whether HALT message is sent
-                        * out successfully.
-                        *
-                        * Checking (mci_unhalt_bt_gpm == false) instead of
-                        * checking (ah->mci_halted_bt_gpm == false) will make
-                        * sure currently is in UNHALT-ed mode and BT can
-                        * respond to status query.
-                        */
-                       value = (!mci->unhalt_bt_gpm &&
-                                mci->need_flush_btinfo) ? 1 : 0;
-                       if (p_data)
-                               mci->need_flush_btinfo =
-                                       (*p_data != 0) ? true : false;
-                       break;
        case MCI_STATE_RECOVER_RX:
                ar9003_mci_prep_interface(ah);
                mci->query_bt = true;
                mci->need_flush_btinfo = true;
                ar9003_mci_send_coex_wlan_channels(ah, true);
-               ar9003_mci_2g5g_switch(ah, true);
+               ar9003_mci_2g5g_switch(ah, false);
                break;
        case MCI_STATE_NEED_FTP_STOMP:
                value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
                break;
-       case MCI_STATE_NEED_TUNING:
-               value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
-               break;
        default:
                break;
        }
@@ -1397,3 +1253,173 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
        return value;
 }
 EXPORT_SYMBOL(ar9003_mci_state);
+
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n");
+
+       ar9003_mci_send_lna_take(ah, true);
+       udelay(50);
+
+       REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
+       mci->is_2g = false;
+       mci->update_2g5g = true;
+       ar9003_mci_send_2g5g_status(ah, true);
+
+       /* Force another 2g5g update at next scanning */
+       mci->update_2g5g = true;
+}
+
+void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+       u32 btcoex_ctrl2, diag_sw;
+       int i;
+       u8 lna_ctrl, bt_sleep;
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
+               if (btcoex_ctrl2 != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
+
+       for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+               diag_sw = REG_READ(ah, AR_DIAG_SW);
+               if (diag_sw != 0xdeadbeef)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+       REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
+       lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
+       bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
+
+       REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
+       REG_WRITE(ah, AR_DIAG_SW, diag_sw);
+
+       if (bt_sleep && (lna_ctrl == 2)) {
+               REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
+               REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
+               udelay(50);
+       }
+}
+
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 offset;
+
+       /*
+        * This should only be called before "MAC Warm Reset" or "MCI Reset Rx".
+        */
+       offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+       if (mci->gpm_idx == offset)
+               return;
+       ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n",
+               mci->gpm_idx, offset);
+       mci->query_bt = true;
+       mci->need_flush_btinfo = true;
+       mci->gpm_idx = 0;
+}
+
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       u32 offset, more_gpm = 0, gpm_ptr;
+
+       if (first) {
+               gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+               mci->gpm_idx = gpm_ptr;
+               return gpm_ptr;
+       }
+
+       /*
+        * This could be useful to avoid new GPM message interrupt which
+        * may lead to spurious interrupt after power sleep, or multiple
+        * entry of ath_mci_intr().
+        * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
+        * alleviate this effect, but clearing GPM RX interrupt bit is
+        * safe, because whether this is called from hw or driver code
+        * there must be an interrupt bit set/triggered initially
+        */
+       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
+                       AR_MCI_INTERRUPT_RX_MSG_GPM);
+
+       gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+       offset = gpm_ptr;
+
+       if (!offset)
+               offset = mci->gpm_len - 1;
+       else if (offset >= mci->gpm_len) {
+               if (offset != 0xFFFF)
+                       offset = 0;
+       } else {
+               offset--;
+       }
+
+       if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) {
+               offset = MCI_GPM_INVALID;
+               more_gpm = MCI_GPM_NOMORE;
+               goto out;
+       }
+       for (;;) {
+               u32 temp_index;
+
+               /* skip reserved GPM if any */
+
+               if (offset != mci->gpm_idx)
+                       more_gpm = MCI_GPM_MORE;
+               else
+                       more_gpm = MCI_GPM_NOMORE;
+
+               temp_index = mci->gpm_idx;
+               mci->gpm_idx++;
+
+               if (mci->gpm_idx >= mci->gpm_len)
+                       mci->gpm_idx = 0;
+
+               if (ar9003_mci_is_gpm_valid(ah, temp_index)) {
+                       offset = temp_index;
+                       break;
+               }
+
+               if (more_gpm == MCI_GPM_NOMORE) {
+                       offset = MCI_GPM_INVALID;
+                       break;
+               }
+       }
+
+       if (offset != MCI_GPM_INVALID)
+               offset <<= 4;
+out:
+       if (more)
+               *more = more_gpm;
+
+       return offset;
+}
+EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset);
+
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       mci->bt_ver_major = major;
+       mci->bt_ver_minor = minor;
+       mci->bt_version_known = true;
+       ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n",
+               mci->bt_ver_major, mci->bt_ver_minor);
+}
+EXPORT_SYMBOL(ar9003_mci_set_bt_version);
+
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah)
+{
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+
+       mci->wlan_channels_update = true;
+       ar9003_mci_send_coex_wlan_channels(ah, true);
+}
+EXPORT_SYMBOL(ar9003_mci_send_wlan_channels);
index 4842f6c06b8c3bc1640b17c7d90d606997a8b840..d33b8e1288554dd502dc290d68c8c45684d2e1a8 100644 (file)
@@ -189,30 +189,18 @@ enum mci_bt_state {
 /* Type of state query */
 enum mci_state_type {
        MCI_STATE_ENABLE,
-       MCI_STATE_INIT_GPM_OFFSET,
-       MCI_STATE_NEXT_GPM_OFFSET,
-       MCI_STATE_LAST_GPM_OFFSET,
-       MCI_STATE_BT,
-       MCI_STATE_SET_BT_SLEEP,
        MCI_STATE_SET_BT_AWAKE,
        MCI_STATE_SET_BT_CAL_START,
        MCI_STATE_SET_BT_CAL,
        MCI_STATE_LAST_SCHD_MSG_OFFSET,
        MCI_STATE_REMOTE_SLEEP,
-       MCI_STATE_CONT_RSSI_POWER,
-       MCI_STATE_CONT_PRIORITY,
-       MCI_STATE_CONT_TXRX,
        MCI_STATE_RESET_REQ_WAKE,
        MCI_STATE_SEND_WLAN_COEX_VERSION,
-       MCI_STATE_SET_BT_COEX_VERSION,
-       MCI_STATE_SEND_WLAN_CHANNELS,
        MCI_STATE_SEND_VERSION_QUERY,
        MCI_STATE_SEND_STATUS_QUERY,
-       MCI_STATE_NEED_FLUSH_BT_INFO,
        MCI_STATE_SET_CONCUR_TX_PRI,
        MCI_STATE_RECOVER_RX,
        MCI_STATE_NEED_FTP_STOMP,
-       MCI_STATE_NEED_TUNING,
        MCI_STATE_DEBUG,
        MCI_STATE_MAX
 };
@@ -260,28 +248,26 @@ enum mci_gpm_coex_opcode {
 bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
                             u32 *payload, u8 len, bool wait_done,
                             bool check_bt);
-u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data);
+u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type);
 void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
                      u16 len, u32 sched_addr);
 void ar9003_mci_cleanup(struct ath_hw *ah);
 void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
                              u32 *rx_msg_intr);
-
+u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more);
+void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor);
+void ar9003_mci_send_wlan_channels(struct ath_hw *ah);
 /*
  * These functions are used by ath9k_hw.
  */
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
-       return ah->btcoex_hw.mci.ready;
-}
 void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
 void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
 void ar9003_mci_init_cal_done(struct ath_hw *ah);
 void ar9003_mci_set_full_sleep(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force);
 void ar9003_mci_check_bt(struct ath_hw *ah);
 bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
 int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
@@ -289,13 +275,12 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                      bool is_full_sleep);
 void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked);
+void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah);
+void ar9003_mci_set_power_awake(struct ath_hw *ah);
+void ar9003_mci_check_gpm_offset(struct ath_hw *ah);
 
 #else
 
-static inline bool ar9003_mci_is_ready(struct ath_hw *ah)
-{
-       return false;
-}
 static inline void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
 {
 }
@@ -330,6 +315,15 @@ static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
 static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
 }
+static inline void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_set_power_awake(struct ath_hw *ah)
+{
+}
+static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif
index 11abb972be1f6e74f22c04b6b9e8db8706c0d6ca..6b91ebb158fe19216c4b093d0b3a2c25ed74eb9e 100644 (file)
@@ -173,7 +173,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
        int cur_bb_spur, negative = 0, cck_spur_freq;
        int i;
        int range, max_spur_cnts, synth_freq;
-       u8 *spur_fbin_ptr = NULL;
+       u8 *spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan));
 
        /*
         * Need to verify range +/- 10 MHz in control channel, otherwise spur
@@ -181,8 +181,6 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
         */
 
        if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) {
-               spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
-                                                        IS_CHAN_2GHZ(chan));
                if (spur_fbin_ptr[0] == 0) /* No spur */
                        return;
                max_spur_cnts = 5;
@@ -676,6 +674,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        if (chan->channel == 2484)
                ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
 
+       if (AR_SREV_9462(ah))
+               REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
+                         AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
+
        ah->modes_index = modesIndex;
        ar9003_hw_override_ini(ah);
        ar9003_hw_set_channel_regs(ah, chan);
@@ -821,18 +823,18 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                        REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
                                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 
-               if (!on != aniState->ofdmWeakSigDetectOff) {
+               if (on != aniState->ofdmWeakSigDetect) {
                        ath_dbg(common, ANI,
                                "** ch %d: ofdm weak signal: %s=>%s\n",
                                chan->channel,
-                               !aniState->ofdmWeakSigDetectOff ?
+                               aniState->ofdmWeakSigDetect ?
                                "on" : "off",
                                on ? "on" : "off");
                        if (on)
                                ah->stats.ast_ani_ofdmon++;
                        else
                                ah->stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
+                       aniState->ofdmWeakSigDetect = on;
                }
                break;
        }
@@ -851,7 +853,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value = firstep_table[level] -
-                       firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+                       firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
                        aniState->iniDef.firstep;
                if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
                        value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -866,7 +868,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value2 = firstep_table[level] -
-                        firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+                        firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
                         aniState->iniDef.firstepLow;
                if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
                        value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
@@ -882,7 +884,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                chan->channel,
                                aniState->firstepLevel,
                                level,
-                               ATH9K_ANI_FIRSTEP_LVL_NEW,
+                               ATH9K_ANI_FIRSTEP_LVL,
                                value,
                                aniState->iniDef.firstep);
                        ath_dbg(common, ANI,
@@ -890,7 +892,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                chan->channel,
                                aniState->firstepLevel,
                                level,
-                               ATH9K_ANI_FIRSTEP_LVL_NEW,
+                               ATH9K_ANI_FIRSTEP_LVL,
                                value2,
                                aniState->iniDef.firstepLow);
                        if (level > aniState->firstepLevel)
@@ -915,7 +917,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value = cycpwrThr1_table[level] -
-                       cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+                       cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
                        aniState->iniDef.cycpwrThr1;
                if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
                        value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -931,7 +933,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                 * from INI file & cap value
                 */
                value2 = cycpwrThr1_table[level] -
-                        cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+                        cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
                         aniState->iniDef.cycpwrThr1Ext;
                if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
                        value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
@@ -946,7 +948,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                chan->channel,
                                aniState->spurImmunityLevel,
                                level,
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+                               ATH9K_ANI_SPUR_IMMUNE_LVL,
                                value,
                                aniState->iniDef.cycpwrThr1);
                        ath_dbg(common, ANI,
@@ -954,7 +956,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                chan->channel,
                                aniState->spurImmunityLevel,
                                level,
-                               ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+                               ATH9K_ANI_SPUR_IMMUNE_LVL,
                                value2,
                                aniState->iniDef.cycpwrThr1Ext);
                        if (level > aniState->spurImmunityLevel)
@@ -975,16 +977,16 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                              AR_PHY_MRC_CCK_ENABLE, is_on);
                REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
                              AR_PHY_MRC_CCK_MUX_REG, is_on);
-               if (!is_on != aniState->mrcCCKOff) {
+               if (is_on != aniState->mrcCCK) {
                        ath_dbg(common, ANI, "** ch %d: MRC CCK: %s=>%s\n",
                                chan->channel,
-                               !aniState->mrcCCKOff ? "on" : "off",
+                               aniState->mrcCCK ? "on" : "off",
                                is_on ? "on" : "off");
                if (is_on)
                        ah->stats.ast_ani_ccklow++;
                else
                        ah->stats.ast_ani_cckhigh++;
-               aniState->mrcCCKOff = !is_on;
+               aniState->mrcCCK = is_on;
                }
        break;
        }
@@ -998,9 +1000,9 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
        ath_dbg(common, ANI,
                "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
                aniState->spurImmunityLevel,
-               !aniState->ofdmWeakSigDetectOff ? "on" : "off",
+               aniState->ofdmWeakSigDetect ? "on" : "off",
                aniState->firstepLevel,
-               !aniState->mrcCCKOff ? "on" : "off",
+               aniState->mrcCCK ? "on" : "off",
                aniState->listenTime,
                aniState->ofdmPhyErrCount,
                aniState->cckPhyErrCount);
@@ -1107,10 +1109,10 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
                                               AR_PHY_EXT_CYCPWR_THR1);
 
        /* these levels just got reset to defaults by the INI */
-       aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
-       aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
-       aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
-       aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
+       aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+       aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+       aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+       aniState->mrcCCK = true;
 }
 
 static void ar9003_hw_set_radar_params(struct ath_hw *ah,
index 7268a48a92a178c95c953ffa3e0bbbfcc2fe3627..ed662c3bae5b8c1963903ff34a256c1d6a500293 100644 (file)
 #define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK         0x0001
 #define AR_PHY_RX_DELAY_DELAY   0x00003FFF
 #define AR_PHY_CCK_TX_CTRL_JAPAN    0x00000010
-#define AR_PHY_SPECTRAL_SCAN_ENABLE         0x00000001
-#define AR_PHY_SPECTRAL_SCAN_ENABLE_S       0
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE         0x00000002
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S       1
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD     0x000000F0
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S   4
-#define AR_PHY_SPECTRAL_SCAN_PERIOD         0x0000FF00
-#define AR_PHY_SPECTRAL_SCAN_PERIOD_S       8
-#define AR_PHY_SPECTRAL_SCAN_COUNT          0x00FF0000
-#define AR_PHY_SPECTRAL_SCAN_COUNT_S        16
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+
+#define AR_PHY_SPECTRAL_SCAN_ENABLE           0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENABLE_S         0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE           0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S         1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD       0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S     4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD           0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S         8
+#define AR_PHY_SPECTRAL_SCAN_COUNT            0x0FFF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S          16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT     0x10000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S   28
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY         0x20000000
+#define AR_PHY_SPECTRAL_SCAN_PRIORITY_S       29
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5         0x40000000
+#define AR_PHY_SPECTRAL_SCAN_USE_ERR5_S       30
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT   0x80000000
+#define AR_PHY_SPECTRAL_SCAN_COMPRESSED_RPT_S 31
+
 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION     0x00000001
 #define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S   0
index 1bd3a3d22101806aca2b06ebc9be5ee77afdddd7..6e1756bc38336ed63fadafa22b161bd1f93f64e2 100644 (file)
@@ -337,12 +337,7 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = {
        {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000},
 };
 
-static const u32 ar9331_1p1_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
+#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
 
 static const u32 ar9331_1p1_xtal_25M[][2] = {
        /* Addr      allmodes  */
@@ -783,17 +778,7 @@ static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = {
        {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000},
 };
 
-static const u32 ar9331_1p1_mac_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
+#define ar9331_1p1_mac_postamble ar9300_2p2_mac_postamble
 
 static const u32 ar9331_1p1_soc_preamble[][2] = {
        /* Addr      allmodes  */
@@ -1112,38 +1097,4 @@ static const u32 ar9331_common_tx_gain_offset1_1[][1] = {
        {0x00000000},
 };
 
-static const u32 ar9331_1p1_chansel_xtal_25M[] = {
-       0x0101479e,
-       0x0101d027,
-       0x010258af,
-       0x0102e138,
-       0x010369c0,
-       0x0103f249,
-       0x01047ad1,
-       0x0105035a,
-       0x01058be2,
-       0x0106146b,
-       0x01069cf3,
-       0x0107257c,
-       0x0107ae04,
-       0x0108f5b2,
-};
-
-static const u32 ar9331_1p1_chansel_xtal_40M[] = {
-       0x00a0ccbe,
-       0x00a12213,
-       0x00a17769,
-       0x00a1ccbe,
-       0x00a22213,
-       0x00a27769,
-       0x00a2ccbe,
-       0x00a32213,
-       0x00a37769,
-       0x00a3ccbe,
-       0x00a42213,
-       0x00a47769,
-       0x00a4ccbe,
-       0x00a5998b,
-};
-
 #endif /* INITVALS_9330_1P1_H */
index 0e6ca0834b345b3dd0240068a669983c325b9c90..57ed8a112173187d16b15ea15e12b8a38d8244b4 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2011 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
@@ -17,8 +18,8 @@
 #ifndef INITVALS_9330_1P2_H
 #define INITVALS_9330_1P2_H
 
-static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p2[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
        {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
@@ -102,8 +103,14 @@ static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p2[][5] = {
        {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
 };
 
+#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2
+
+#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_power_tx_gain_1p2
+
+#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_low_ob_db_tx_gain_1p2
+
 static const u32 ar9331_1p2_baseband_postamble[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
        {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
        {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
@@ -147,191 +154,6 @@ static const u32 ar9331_1p2_baseband_postamble[][5] = {
        {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
-static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200},
-       {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202},
-       {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400},
-       {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402},
-       {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404},
-       {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603},
-       {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02},
-       {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04},
-       {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20},
-       {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20},
-       {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22},
-       {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24},
-       {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640},
-       {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660},
-       {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861},
-       {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81},
-       {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83},
-       {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84},
-       {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3},
-       {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9},
-       {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb},
-       {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec},
-       {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802},
-       {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03},
-       {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-};
-
-static const u32 ar9331_modes_low_ob_db_tx_gain_1p2[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200},
-       {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202},
-       {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400},
-       {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402},
-       {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404},
-       {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603},
-       {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02},
-       {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04},
-       {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20},
-       {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20},
-       {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22},
-       {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24},
-       {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640},
-       {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660},
-       {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861},
-       {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81},
-       {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83},
-       {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84},
-       {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3},
-       {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9},
-       {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb},
-       {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec},
-       {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802},
-       {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03},
-       {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-};
-
-static const u32 ar9331_1p2_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
-
-static const u32 ar9331_1p2_xtal_25M[][2] = {
-       /* Addr      allmodes  */
-       {0x00007038, 0x000002f8},
-       {0x00008244, 0x0010f3d7},
-       {0x0000824c, 0x0001e7ae},
-       {0x0001609c, 0x0f508f29},
-};
-
 static const u32 ar9331_1p2_radio_core[][2] = {
        /* Addr      allmodes  */
        {0x00016000, 0x36db6db6},
@@ -397,684 +219,24 @@ static const u32 ar9331_1p2_radio_core[][2] = {
        {0x000163d4, 0x00000000},
 };
 
-static const u32 ar9331_1p2_soc_postamble[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x00007010, 0x00000022, 0x00000022, 0x00000022, 0x00000022},
-};
+#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484
 
-static const u32 ar9331_common_wo_xlna_rx_gain_1p2[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00060005},
-       {0x0000a004, 0x00810080},
-       {0x0000a008, 0x00830082},
-       {0x0000a00c, 0x00850084},
-       {0x0000a010, 0x01820181},
-       {0x0000a014, 0x01840183},
-       {0x0000a018, 0x01880185},
-       {0x0000a01c, 0x018a0189},
-       {0x0000a020, 0x02850284},
-       {0x0000a024, 0x02890288},
-       {0x0000a028, 0x028b028a},
-       {0x0000a02c, 0x03850384},
-       {0x0000a030, 0x03890388},
-       {0x0000a034, 0x038b038a},
-       {0x0000a038, 0x038d038c},
-       {0x0000a03c, 0x03910390},
-       {0x0000a040, 0x03930392},
-       {0x0000a044, 0x03950394},
-       {0x0000a048, 0x00000396},
-       {0x0000a04c, 0x00000000},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x28282828},
-       {0x0000a088, 0x28282828},
-       {0x0000a08c, 0x28282828},
-       {0x0000a090, 0x28282828},
-       {0x0000a094, 0x24242428},
-       {0x0000a098, 0x171e1e1e},
-       {0x0000a09c, 0x02020b0b},
-       {0x0000a0a0, 0x02020202},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x22072208},
-       {0x0000a0c4, 0x22052206},
-       {0x0000a0c8, 0x22032204},
-       {0x0000a0cc, 0x22012202},
-       {0x0000a0d0, 0x221f2200},
-       {0x0000a0d4, 0x221d221e},
-       {0x0000a0d8, 0x33023303},
-       {0x0000a0dc, 0x33003301},
-       {0x0000a0e0, 0x331e331f},
-       {0x0000a0e4, 0x4402331d},
-       {0x0000a0e8, 0x44004401},
-       {0x0000a0ec, 0x441e441f},
-       {0x0000a0f0, 0x55025503},
-       {0x0000a0f4, 0x55005501},
-       {0x0000a0f8, 0x551e551f},
-       {0x0000a0fc, 0x6602551d},
-       {0x0000a100, 0x66006601},
-       {0x0000a104, 0x661e661f},
-       {0x0000a108, 0x7703661d},
-       {0x0000a10c, 0x77017702},
-       {0x0000a110, 0x00007700},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x111f1100},
-       {0x0000a148, 0x111d111e},
-       {0x0000a14c, 0x111b111c},
-       {0x0000a150, 0x22032204},
-       {0x0000a154, 0x22012202},
-       {0x0000a158, 0x221f2200},
-       {0x0000a15c, 0x221d221e},
-       {0x0000a160, 0x33013302},
-       {0x0000a164, 0x331f3300},
-       {0x0000a168, 0x4402331e},
-       {0x0000a16c, 0x44004401},
-       {0x0000a170, 0x441e441f},
-       {0x0000a174, 0x55015502},
-       {0x0000a178, 0x551f5500},
-       {0x0000a17c, 0x6602551e},
-       {0x0000a180, 0x66006601},
-       {0x0000a184, 0x661e661f},
-       {0x0000a188, 0x7703661d},
-       {0x0000a18c, 0x77017702},
-       {0x0000a190, 0x00007700},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000296},
-};
+#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M
 
-static const u32 ar9331_1p2_baseband_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00009800, 0xafe68e30},
-       {0x00009804, 0xfd14e000},
-       {0x00009808, 0x9c0a8f6b},
-       {0x0000980c, 0x04800000},
-       {0x00009814, 0x9280c00a},
-       {0x00009818, 0x00000000},
-       {0x0000981c, 0x00020028},
-       {0x00009834, 0x5f3ca3de},
-       {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x14750600},
-       {0x00009880, 0x201fff00},
-       {0x00009884, 0x00001042},
-       {0x000098a4, 0x00200400},
-       {0x000098b0, 0x32840bbe},
-       {0x000098d0, 0x004b6a8e},
-       {0x000098d4, 0x00000820},
-       {0x000098dc, 0x00000000},
-       {0x000098f0, 0x00000000},
-       {0x000098f4, 0x00000000},
-       {0x00009c04, 0x00000000},
-       {0x00009c08, 0x03200000},
-       {0x00009c0c, 0x00000000},
-       {0x00009c10, 0x00000000},
-       {0x00009c14, 0x00046384},
-       {0x00009c18, 0x05b6b440},
-       {0x00009c1c, 0x00b6b440},
-       {0x00009d00, 0xc080a333},
-       {0x00009d04, 0x40206c10},
-       {0x00009d08, 0x009c4060},
-       {0x00009d0c, 0x1883800a},
-       {0x00009d10, 0x01834061},
-       {0x00009d14, 0x00c00400},
-       {0x00009d18, 0x00000000},
-       {0x00009e08, 0x0038233c},
-       {0x00009e24, 0x9927b515},
-       {0x00009e28, 0x12ef0200},
-       {0x00009e30, 0x06336f77},
-       {0x00009e34, 0x6af6532f},
-       {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
-       {0x00009e4c, 0x00001004},
-       {0x00009e50, 0x00ff03f1},
-       {0x00009fc0, 0x803e4788},
-       {0x00009fc4, 0x0001efb5},
-       {0x00009fcc, 0x40000014},
-       {0x0000a20c, 0x00000000},
-       {0x0000a220, 0x00000000},
-       {0x0000a224, 0x00000000},
-       {0x0000a228, 0x10002310},
-       {0x0000a23c, 0x00000000},
-       {0x0000a244, 0x0c000000},
-       {0x0000a2a0, 0x00000001},
-       {0x0000a2c0, 0x00000001},
-       {0x0000a2c8, 0x00000000},
-       {0x0000a2cc, 0x18c43433},
-       {0x0000a2d4, 0x00000000},
-       {0x0000a2dc, 0x00000000},
-       {0x0000a2e0, 0x00000000},
-       {0x0000a2e4, 0x00000000},
-       {0x0000a2e8, 0x00000000},
-       {0x0000a2ec, 0x00000000},
-       {0x0000a2f0, 0x00000000},
-       {0x0000a2f4, 0x00000000},
-       {0x0000a2f8, 0x00000000},
-       {0x0000a344, 0x00000000},
-       {0x0000a34c, 0x00000000},
-       {0x0000a350, 0x0000a000},
-       {0x0000a364, 0x00000000},
-       {0x0000a370, 0x00000000},
-       {0x0000a390, 0x00000001},
-       {0x0000a394, 0x00000444},
-       {0x0000a398, 0x001f0e0f},
-       {0x0000a39c, 0x0075393f},
-       {0x0000a3a0, 0xb79f6427},
-       {0x0000a3a4, 0x00000000},
-       {0x0000a3a8, 0xaaaaaaaa},
-       {0x0000a3ac, 0x3c466478},
-       {0x0000a3c0, 0x20202020},
-       {0x0000a3c4, 0x22222220},
-       {0x0000a3c8, 0x20200020},
-       {0x0000a3cc, 0x20202020},
-       {0x0000a3d0, 0x20202020},
-       {0x0000a3d4, 0x20202020},
-       {0x0000a3d8, 0x20202020},
-       {0x0000a3dc, 0x20202020},
-       {0x0000a3e0, 0x20202020},
-       {0x0000a3e4, 0x20202020},
-       {0x0000a3e8, 0x20202020},
-       {0x0000a3ec, 0x20202020},
-       {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000006},
-       {0x0000a3f8, 0x0cdbd380},
-       {0x0000a3fc, 0x000f0f01},
-       {0x0000a400, 0x8fa91f01},
-       {0x0000a404, 0x00000000},
-       {0x0000a408, 0x0e79e5c6},
-       {0x0000a40c, 0x00820820},
-       {0x0000a414, 0x1ce739ce},
-       {0x0000a418, 0x2d001dce},
-       {0x0000a41c, 0x1ce739ce},
-       {0x0000a420, 0x000001ce},
-       {0x0000a424, 0x1ce739ce},
-       {0x0000a428, 0x000001ce},
-       {0x0000a42c, 0x1ce739ce},
-       {0x0000a430, 0x1ce739ce},
-       {0x0000a434, 0x00000000},
-       {0x0000a438, 0x00001801},
-       {0x0000a43c, 0x00000000},
-       {0x0000a440, 0x00000000},
-       {0x0000a444, 0x00000000},
-       {0x0000a448, 0x04000000},
-       {0x0000a44c, 0x00000001},
-       {0x0000a450, 0x00010000},
-       {0x0000a458, 0x00000000},
-       {0x0000a640, 0x00000000},
-       {0x0000a644, 0x3fad9d74},
-       {0x0000a648, 0x0048060a},
-       {0x0000a64c, 0x00003c37},
-       {0x0000a670, 0x03020100},
-       {0x0000a674, 0x09080504},
-       {0x0000a678, 0x0d0c0b0a},
-       {0x0000a67c, 0x13121110},
-       {0x0000a680, 0x31301514},
-       {0x0000a684, 0x35343332},
-       {0x0000a688, 0x00000036},
-       {0x0000a690, 0x00000838},
-       {0x0000a7c0, 0x00000000},
-       {0x0000a7c4, 0xfffffffc},
-       {0x0000a7c8, 0x00000000},
-       {0x0000a7cc, 0x00000000},
-       {0x0000a7d0, 0x00000000},
-       {0x0000a7d4, 0x00000004},
-       {0x0000a7dc, 0x00000001},
-};
+#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M
 
-static const u32 ar9331_modes_high_power_tx_gain_1p2[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec},
-       {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200},
-       {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202},
-       {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400},
-       {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402},
-       {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404},
-       {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603},
-       {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02},
-       {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04},
-       {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20},
-       {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20},
-       {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22},
-       {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24},
-       {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640},
-       {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660},
-       {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861},
-       {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81},
-       {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83},
-       {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84},
-       {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3},
-       {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9},
-       {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb},
-       {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec},
-       {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802},
-       {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03},
-       {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-       {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004},
-};
+#define ar9331_1p2_baseband_core ar9331_1p1_baseband_core
 
-static const u32 ar9331_1p2_mac_postamble[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
+#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble
 
-static const u32 ar9331_1p2_soc_preamble[][2] = {
-       /* Addr      allmodes  */
-       {0x00007020, 0x00000000},
-       {0x00007034, 0x00000002},
-       {0x00007038, 0x000002f8},
-};
+#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble
 
-static const u32 ar9331_1p2_xtal_40M[][2] = {
-       /* Addr      allmodes  */
-       {0x00007038, 0x000004c2},
-       {0x00008244, 0x0010f400},
-       {0x0000824c, 0x0001e800},
-       {0x0001609c, 0x0b283f31},
-};
+#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble
 
-static const u32 ar9331_1p2_mac_core[][2] = {
-       /* Addr      allmodes  */
-       {0x00000008, 0x00000000},
-       {0x00000030, 0x00020085},
-       {0x00000034, 0x00000005},
-       {0x00000040, 0x00000000},
-       {0x00000044, 0x00000000},
-       {0x00000048, 0x00000008},
-       {0x0000004c, 0x00000010},
-       {0x00000050, 0x00000000},
-       {0x00001040, 0x002ffc0f},
-       {0x00001044, 0x002ffc0f},
-       {0x00001048, 0x002ffc0f},
-       {0x0000104c, 0x002ffc0f},
-       {0x00001050, 0x002ffc0f},
-       {0x00001054, 0x002ffc0f},
-       {0x00001058, 0x002ffc0f},
-       {0x0000105c, 0x002ffc0f},
-       {0x00001060, 0x002ffc0f},
-       {0x00001064, 0x002ffc0f},
-       {0x000010f0, 0x00000100},
-       {0x00001270, 0x00000000},
-       {0x000012b0, 0x00000000},
-       {0x000012f0, 0x00000000},
-       {0x0000143c, 0x00000000},
-       {0x0000147c, 0x00000000},
-       {0x00008000, 0x00000000},
-       {0x00008004, 0x00000000},
-       {0x00008008, 0x00000000},
-       {0x0000800c, 0x00000000},
-       {0x00008018, 0x00000000},
-       {0x00008020, 0x00000000},
-       {0x00008038, 0x00000000},
-       {0x0000803c, 0x00000000},
-       {0x00008040, 0x00000000},
-       {0x00008044, 0x00000000},
-       {0x00008048, 0x00000000},
-       {0x0000804c, 0xffffffff},
-       {0x00008054, 0x00000000},
-       {0x00008058, 0x00000000},
-       {0x0000805c, 0x000fc78f},
-       {0x00008060, 0x0000000f},
-       {0x00008064, 0x00000000},
-       {0x00008070, 0x00000310},
-       {0x00008074, 0x00000020},
-       {0x00008078, 0x00000000},
-       {0x0000809c, 0x0000000f},
-       {0x000080a0, 0x00000000},
-       {0x000080a4, 0x02ff0000},
-       {0x000080a8, 0x0e070605},
-       {0x000080ac, 0x0000000d},
-       {0x000080b0, 0x00000000},
-       {0x000080b4, 0x00000000},
-       {0x000080b8, 0x00000000},
-       {0x000080bc, 0x00000000},
-       {0x000080c0, 0x2a800000},
-       {0x000080c4, 0x06900168},
-       {0x000080c8, 0x13881c20},
-       {0x000080cc, 0x01f40000},
-       {0x000080d0, 0x00252500},
-       {0x000080d4, 0x00a00000},
-       {0x000080d8, 0x00400000},
-       {0x000080dc, 0x00000000},
-       {0x000080e0, 0xffffffff},
-       {0x000080e4, 0x0000ffff},
-       {0x000080e8, 0x3f3f3f3f},
-       {0x000080ec, 0x00000000},
-       {0x000080f0, 0x00000000},
-       {0x000080f4, 0x00000000},
-       {0x000080fc, 0x00020000},
-       {0x00008100, 0x00000000},
-       {0x00008108, 0x00000052},
-       {0x0000810c, 0x00000000},
-       {0x00008110, 0x00000000},
-       {0x00008114, 0x000007ff},
-       {0x00008118, 0x000000aa},
-       {0x0000811c, 0x00003210},
-       {0x00008124, 0x00000000},
-       {0x00008128, 0x00000000},
-       {0x0000812c, 0x00000000},
-       {0x00008130, 0x00000000},
-       {0x00008134, 0x00000000},
-       {0x00008138, 0x00000000},
-       {0x0000813c, 0x0000ffff},
-       {0x00008144, 0xffffffff},
-       {0x00008168, 0x00000000},
-       {0x0000816c, 0x00000000},
-       {0x00008170, 0x18486200},
-       {0x00008174, 0x33332210},
-       {0x00008178, 0x00000000},
-       {0x0000817c, 0x00020000},
-       {0x000081c0, 0x00000000},
-       {0x000081c4, 0x33332210},
-       {0x000081c8, 0x00000000},
-       {0x000081cc, 0x00000000},
-       {0x000081d4, 0x00000000},
-       {0x000081ec, 0x00000000},
-       {0x000081f0, 0x00000000},
-       {0x000081f4, 0x00000000},
-       {0x000081f8, 0x00000000},
-       {0x000081fc, 0x00000000},
-       {0x00008240, 0x00100000},
-       {0x00008248, 0x00000800},
-       {0x00008250, 0x00000000},
-       {0x00008254, 0x00000000},
-       {0x00008258, 0x00000000},
-       {0x0000825c, 0x40000000},
-       {0x00008260, 0x00080922},
-       {0x00008264, 0x9d400010},
-       {0x00008268, 0xffffffff},
-       {0x0000826c, 0x0000ffff},
-       {0x00008270, 0x00000000},
-       {0x00008274, 0x40000000},
-       {0x00008278, 0x003e4180},
-       {0x0000827c, 0x00000004},
-       {0x00008284, 0x0000002c},
-       {0x00008288, 0x0000002c},
-       {0x0000828c, 0x000000ff},
-       {0x00008294, 0x00000000},
-       {0x00008298, 0x00000000},
-       {0x0000829c, 0x00000000},
-       {0x00008300, 0x00000140},
-       {0x00008314, 0x00000000},
-       {0x0000831c, 0x0000010d},
-       {0x00008328, 0x00000000},
-       {0x0000832c, 0x00000007},
-       {0x00008330, 0x00000302},
-       {0x00008334, 0x00000700},
-       {0x00008338, 0x00ff0000},
-       {0x0000833c, 0x02400000},
-       {0x00008340, 0x000107ff},
-       {0x00008344, 0xaa48105b},
-       {0x00008348, 0x008f0000},
-       {0x0000835c, 0x00000000},
-       {0x00008360, 0xffffffff},
-       {0x00008364, 0xffffffff},
-       {0x00008368, 0x00000000},
-       {0x00008370, 0x00000000},
-       {0x00008374, 0x000000ff},
-       {0x00008378, 0x00000000},
-       {0x0000837c, 0x00000000},
-       {0x00008380, 0xffffffff},
-       {0x00008384, 0xffffffff},
-       {0x00008390, 0xffffffff},
-       {0x00008394, 0xffffffff},
-       {0x00008398, 0x00000000},
-       {0x0000839c, 0x00000000},
-       {0x000083a0, 0x00000000},
-       {0x000083a4, 0x0000fa14},
-       {0x000083a8, 0x000f0c00},
-       {0x000083ac, 0x33332210},
-       {0x000083b0, 0x33332210},
-       {0x000083b4, 0x33332210},
-       {0x000083b8, 0x33332210},
-       {0x000083bc, 0x00000000},
-       {0x000083c0, 0x00000000},
-       {0x000083c4, 0x00000000},
-       {0x000083c8, 0x00000000},
-       {0x000083cc, 0x00000200},
-       {0x000083d0, 0x000301ff},
-};
+#define ar9331_1p2_mac_core ar9331_1p1_mac_core
 
-static const u32 ar9331_common_rx_gain_1p2[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x01800082},
-       {0x0000a014, 0x01820181},
-       {0x0000a018, 0x01840183},
-       {0x0000a01c, 0x01880185},
-       {0x0000a020, 0x018a0189},
-       {0x0000a024, 0x02850284},
-       {0x0000a028, 0x02890288},
-       {0x0000a02c, 0x03850384},
-       {0x0000a030, 0x03890388},
-       {0x0000a034, 0x038b038a},
-       {0x0000a038, 0x038d038c},
-       {0x0000a03c, 0x03910390},
-       {0x0000a040, 0x03930392},
-       {0x0000a044, 0x03950394},
-       {0x0000a048, 0x00000396},
-       {0x0000a04c, 0x00000000},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x28282828},
-       {0x0000a088, 0x28282828},
-       {0x0000a08c, 0x28282828},
-       {0x0000a090, 0x28282828},
-       {0x0000a094, 0x21212128},
-       {0x0000a098, 0x171c1c1c},
-       {0x0000a09c, 0x02020212},
-       {0x0000a0a0, 0x00000202},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x111f1100},
-       {0x0000a0c8, 0x111d111e},
-       {0x0000a0cc, 0x111b111c},
-       {0x0000a0d0, 0x22032204},
-       {0x0000a0d4, 0x22012202},
-       {0x0000a0d8, 0x221f2200},
-       {0x0000a0dc, 0x221d221e},
-       {0x0000a0e0, 0x33013302},
-       {0x0000a0e4, 0x331f3300},
-       {0x0000a0e8, 0x4402331e},
-       {0x0000a0ec, 0x44004401},
-       {0x0000a0f0, 0x441e441f},
-       {0x0000a0f4, 0x55015502},
-       {0x0000a0f8, 0x551f5500},
-       {0x0000a0fc, 0x6602551e},
-       {0x0000a100, 0x66006601},
-       {0x0000a104, 0x661e661f},
-       {0x0000a108, 0x7703661d},
-       {0x0000a10c, 0x77017702},
-       {0x0000a110, 0x00007700},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x111f1100},
-       {0x0000a148, 0x111d111e},
-       {0x0000a14c, 0x111b111c},
-       {0x0000a150, 0x22032204},
-       {0x0000a154, 0x22012202},
-       {0x0000a158, 0x221f2200},
-       {0x0000a15c, 0x221d221e},
-       {0x0000a160, 0x33013302},
-       {0x0000a164, 0x331f3300},
-       {0x0000a168, 0x4402331e},
-       {0x0000a16c, 0x44004401},
-       {0x0000a170, 0x441e441f},
-       {0x0000a174, 0x55015502},
-       {0x0000a178, 0x551f5500},
-       {0x0000a17c, 0x6602551e},
-       {0x0000a180, 0x66006601},
-       {0x0000a184, 0x661e661f},
-       {0x0000a188, 0x7703661d},
-       {0x0000a18c, 0x77017702},
-       {0x0000a190, 0x00007700},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000296},
-};
+#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1
+
+#define ar9331_common_rx_gain_1p2 ar9485_common_rx_gain_1_1
 
 #endif /* INITVALS_9330_1P2_H */
index 815a8af1beefd6684f09c29924a586e3f471dcb1..1d8235e19f0fcd15afe2b114d39f28da2ce10390 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2011 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
 #define INITVALS_9340_H
 
 static const u32 ar9340_1p0_radio_postamble[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
-       {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+       {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
-       {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+       {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
 };
 
 static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
-       /*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -99,21 +100,10 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
        {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
 };
 
-static const u32 ar9340Modes_fast_clock_1p0[][3] = {
-       /*  Addr      5G_HT20     5G_HT40  */
-       {0x00001030, 0x00000268, 0x000004d0},
-       {0x00001070, 0x0000018c, 0x00000318},
-       {0x000010b0, 0x00000fd0, 0x00001fa0},
-       {0x00008014, 0x044c044c, 0x08980898},
-       {0x0000801c, 0x148ec02b, 0x148ec057},
-       {0x00008318, 0x000044c0, 0x00008980},
-       {0x00009e00, 0x03721821, 0x03721821},
-       {0x0000a230, 0x0000000b, 0x00000016},
-       {0x0000a254, 0x00000898, 0x00001130},
-};
+#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2
 
 static const u32 ar9340_1p0_radio_core[][2] = {
-       /*  Addr     allmodes  */
+       /* Addr      allmodes  */
        {0x00016000, 0x36db6db6},
        {0x00016004, 0x6db6db40},
        {0x00016008, 0x73f00000},
@@ -146,15 +136,13 @@ static const u32 ar9340_1p0_radio_core[][2] = {
        {0x00016100, 0x04cb0001},
        {0x00016104, 0xfff80000},
        {0x00016108, 0x00080010},
-       {0x0001610c, 0x00000000},
        {0x00016140, 0x50804008},
        {0x00016144, 0x01884080},
        {0x00016148, 0x000080c0},
        {0x00016280, 0x01000015},
-       {0x00016284, 0x05530000},
+       {0x00016284, 0x15530000},
        {0x00016288, 0x00318000},
        {0x0001628c, 0x50000000},
-       {0x00016290, 0x4080294f},
        {0x00016380, 0x00000000},
        {0x00016384, 0x00000000},
        {0x00016388, 0x00800700},
@@ -219,52 +207,43 @@ static const u32 ar9340_1p0_radio_core[][2] = {
 };
 
 static const u32 ar9340_1p0_radio_core_40M[][2] = {
+       /* Addr      allmodes  */
        {0x0001609c, 0x02566f3a},
        {0x000160ac, 0xa4647c00},
        {0x000160b0, 0x01885f5a},
 };
 
-static const u32 ar9340_1p0_mac_postamble[][5] = {
-       /* Addr       5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
+#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble
 
-static const u32 ar9340_1p0_soc_postamble[][5] = {
-       /*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
-       {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
-};
+#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble
 
 static const u32 ar9340_1p0_baseband_postamble[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
        {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
        {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
-       {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
-       {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
-       {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+       {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+       {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+       {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
        {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e},
-       {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
        {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-       {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0},
+       {0x0000a204, 0x00003ec0, 0x00003ec4, 0x00003ec4, 0x00003ec0},
        {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+       {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
        {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+       {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
        {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
        {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
        {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
@@ -277,11 +256,11 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = {
        {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110},
        {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222},
        {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
-       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+       {0x0000a2d0, 0x00041983, 0x00041983, 0x00041982, 0x00041982},
+       {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
-       {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000},
+       {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
        {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
        {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
@@ -289,21 +268,21 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = {
 };
 
 static const u32 ar9340_1p0_baseband_core[][2] = {
-       /*  Addr     allmodes  */
+       /* Addr      allmodes  */
        {0x00009800, 0xafe68e30},
        {0x00009804, 0xfd14e000},
        {0x00009808, 0x9c0a9f6b},
        {0x0000980c, 0x04900000},
-       {0x00009814, 0xb280c00a},
+       {0x00009814, 0x3280c00a},
        {0x00009818, 0x00000000},
        {0x0000981c, 0x00020028},
-       {0x00009834, 0x5f3ca3de},
+       {0x00009834, 0x6400a190},
        {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x14750600},
+       {0x0000983c, 0x14000600},
        {0x00009880, 0x201fff00},
        {0x00009884, 0x00001042},
        {0x000098a4, 0x00200400},
-       {0x000098b0, 0x52440bbe},
+       {0x000098b0, 0x32840bbe},
        {0x000098d0, 0x004b6a8e},
        {0x000098d4, 0x00000820},
        {0x000098dc, 0x00000000},
@@ -329,7 +308,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
        {0x00009e38, 0x0cc80c00},
-       {0x00009e3c, 0xcf946222},
        {0x00009e40, 0x0d261820},
        {0x00009e4c, 0x00001004},
        {0x00009e50, 0x00ff03f1},
@@ -342,8 +320,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a220, 0x00000000},
        {0x0000a224, 0x00000000},
        {0x0000a228, 0x10002310},
-       {0x0000a22c, 0x01036a1e},
-       {0x0000a234, 0x10000fff},
        {0x0000a23c, 0x00000000},
        {0x0000a244, 0x0c000000},
        {0x0000a2a0, 0x00000001},
@@ -351,10 +327,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a2c8, 0x00000000},
        {0x0000a2cc, 0x18c43433},
        {0x0000a2d4, 0x00000000},
-       {0x0000a2dc, 0x00000000},
-       {0x0000a2e0, 0x00000000},
-       {0x0000a2e4, 0x00000000},
-       {0x0000a2e8, 0x00000000},
        {0x0000a2ec, 0x00000000},
        {0x0000a2f0, 0x00000000},
        {0x0000a2f4, 0x00000000},
@@ -385,7 +357,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a3e8, 0x20202020},
        {0x0000a3ec, 0x20202020},
        {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000246},
+       {0x0000a3f4, 0x00000000},
        {0x0000a3f8, 0x0cdbd380},
        {0x0000a3fc, 0x000f0f01},
        {0x0000a400, 0x8fa91f01},
@@ -402,33 +374,17 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a430, 0x1ce739ce},
        {0x0000a434, 0x00000000},
        {0x0000a438, 0x00001801},
-       {0x0000a43c, 0x00000000},
+       {0x0000a43c, 0x00100000},
        {0x0000a440, 0x00000000},
        {0x0000a444, 0x00000000},
-       {0x0000a448, 0x04000080},
+       {0x0000a448, 0x05000080},
        {0x0000a44c, 0x00000001},
        {0x0000a450, 0x00010000},
        {0x0000a458, 0x00000000},
-       {0x0000a600, 0x00000000},
-       {0x0000a604, 0x00000000},
-       {0x0000a608, 0x00000000},
-       {0x0000a60c, 0x00000000},
-       {0x0000a610, 0x00000000},
-       {0x0000a614, 0x00000000},
-       {0x0000a618, 0x00000000},
-       {0x0000a61c, 0x00000000},
-       {0x0000a620, 0x00000000},
-       {0x0000a624, 0x00000000},
-       {0x0000a628, 0x00000000},
-       {0x0000a62c, 0x00000000},
-       {0x0000a630, 0x00000000},
-       {0x0000a634, 0x00000000},
-       {0x0000a638, 0x00000000},
-       {0x0000a63c, 0x00000000},
        {0x0000a640, 0x00000000},
        {0x0000a644, 0x3fad9d74},
        {0x0000a648, 0x0048060a},
-       {0x0000a64c, 0x00000637},
+       {0x0000a64c, 0x00003c37},
        {0x0000a670, 0x03020100},
        {0x0000a674, 0x09080504},
        {0x0000a678, 0x0d0c0b0a},
@@ -451,10 +407,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
        {0x0000a8f4, 0x00000000},
        {0x0000b2d0, 0x00000080},
        {0x0000b2d4, 0x00000000},
-       {0x0000b2dc, 0x00000000},
-       {0x0000b2e0, 0x00000000},
-       {0x0000b2e4, 0x00000000},
-       {0x0000b2e8, 0x00000000},
        {0x0000b2ec, 0x00000000},
        {0x0000b2f0, 0x00000000},
        {0x0000b2f4, 0x00000000},
@@ -465,80 +417,108 @@ static const u32 ar9340_1p0_baseband_core[][2] = {
 };
 
 static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
-       {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
-       {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
-       {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
-       {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
-       {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+       {0x0000a504, 0x04002222, 0x04002222, 0x02000001, 0x02000001},
+       {0x0000a508, 0x09002421, 0x09002421, 0x05000003, 0x05000003},
+       {0x0000a50c, 0x0d002621, 0x0d002621, 0x0a000005, 0x0a000005},
+       {0x0000a510, 0x13004620, 0x13004620, 0x0e000201, 0x0e000201},
+       {0x0000a514, 0x19004a20, 0x19004a20, 0x11000203, 0x11000203},
+       {0x0000a518, 0x1d004e20, 0x1d004e20, 0x14000401, 0x14000401},
+       {0x0000a51c, 0x21005420, 0x21005420, 0x18000403, 0x18000403},
+       {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000602, 0x1b000602},
+       {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000802, 0x1f000802},
+       {0x0000a528, 0x2f005e42, 0x2f005e42, 0x21000620, 0x21000620},
+       {0x0000a52c, 0x33005e44, 0x33005e44, 0x25000820, 0x25000820},
+       {0x0000a530, 0x38005e65, 0x38005e65, 0x29000822, 0x29000822},
+       {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2d000824, 0x2d000824},
+       {0x0000a538, 0x40005e6b, 0x40005e6b, 0x30000828, 0x30000828},
+       {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x3400082a, 0x3400082a},
+       {0x0000a540, 0x49005e72, 0x49005e72, 0x38000849, 0x38000849},
+       {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b000a2c, 0x3b000a2c},
+       {0x0000a548, 0x53005f12, 0x53005f12, 0x3e000e2b, 0x3e000e2b},
+       {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42000e2d, 0x42000e2d},
+       {0x0000a550, 0x5e025f12, 0x5e025f12, 0x4500124a, 0x4500124a},
+       {0x0000a554, 0x61027f12, 0x61027f12, 0x4900124c, 0x4900124c},
+       {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c00126c, 0x4c00126c},
+       {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x4f00128c, 0x4f00128c},
+       {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x52001290, 0x52001290},
+       {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
+       {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292},
        {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-       {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
-       {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
-       {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
-       {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
-       {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
-       {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
-       {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
-       {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
-       {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
-       {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
-       {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
-       {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
-       {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
-       {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
-       {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
-       {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
-       {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
-       {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
-       {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
-       {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
-       {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
-       {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
-       {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
-       {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
-       {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+       {0x0000a584, 0x04802222, 0x04802222, 0x02800001, 0x02800001},
+       {0x0000a588, 0x09802421, 0x09802421, 0x05800003, 0x05800003},
+       {0x0000a58c, 0x0d802621, 0x0d802621, 0x0a800005, 0x0a800005},
+       {0x0000a590, 0x13804620, 0x13804620, 0x0e800201, 0x0e800201},
+       {0x0000a594, 0x19804a20, 0x19804a20, 0x11800203, 0x11800203},
+       {0x0000a598, 0x1d804e20, 0x1d804e20, 0x14800401, 0x14800401},
+       {0x0000a59c, 0x21805420, 0x21805420, 0x18800403, 0x18800403},
+       {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800602, 0x1b800602},
+       {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800802, 0x1f800802},
+       {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x21800620, 0x21800620},
+       {0x0000a5ac, 0x33805e44, 0x33805e44, 0x25800820, 0x25800820},
+       {0x0000a5b0, 0x38805e65, 0x38805e65, 0x29800822, 0x29800822},
+       {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2d800824, 0x2d800824},
+       {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x30800828, 0x30800828},
+       {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x3480082a, 0x3480082a},
+       {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38800849, 0x38800849},
+       {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b800a2c, 0x3b800a2c},
+       {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e800e2b, 0x3e800e2b},
+       {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42800e2d, 0x42800e2d},
+       {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x4580124a, 0x4580124a},
+       {0x0000a5d4, 0x61827f12, 0x61827f12, 0x4980124c, 0x4980124c},
+       {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c80126c, 0x4c80126c},
+       {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x4f80128c, 0x4f80128c},
+       {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x52801290, 0x52801290},
+       {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292},
+       {0x00016044, 0x056db2db, 0x056db2db, 0x022492db, 0x022492db},
        {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
-       {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+       {0x00016444, 0x056db2db, 0x056db2db, 0x022492db, 0x022492db},
        {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
 };
 
 static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = {
-       /*  Addr       5G_HT20    5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
        {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -559,7 +539,7 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
        {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
@@ -604,13 +584,43 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
        {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
        {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
+       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
+       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
-       {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+       {0x00016048, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266},
+       {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
        {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
-       {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+       {0x00016448, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266},
 };
+
 static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
-       /*  Addr      5G_HT20      5G_HT40     2G_HT40    2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
+       {0x00009820, 0x206a022e, 0x206a022e, 0x206a00ae, 0x206a00ae},
+       {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
+       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec82d2e, 0x7ec82d2e},
+       {0x0000a2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52},
+       {0x0000a2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84},
+       {0x0000a2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000},
+       {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000},
        {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
        {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -676,15 +686,34 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
        {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
        {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
        {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
-       {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
-       {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
-       {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+       {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+       {0x00016048, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086},
+       {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+       {0x00016448, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
+       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
+       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52},
+       {0x0000b2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84},
+       {0x0000b2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000},
+       {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000},
 };
 
-
 static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
-       /*   Addr     allmodes */
+       /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
        {0x0000a008, 0x00050004},
@@ -845,14 +874,14 @@ static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
        {0x0000b074, 0x00000000},
        {0x0000b078, 0x00000000},
        {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x32323232},
-       {0x0000b084, 0x2f2f3232},
-       {0x0000b088, 0x23282a2d},
-       {0x0000b08c, 0x1c1e2123},
-       {0x0000b090, 0x14171919},
-       {0x0000b094, 0x0e0e1214},
-       {0x0000b098, 0x03050707},
-       {0x0000b09c, 0x00030303},
+       {0x0000b080, 0x23232323},
+       {0x0000b084, 0x21232323},
+       {0x0000b088, 0x19191c1e},
+       {0x0000b08c, 0x12141417},
+       {0x0000b090, 0x07070e0e},
+       {0x0000b094, 0x03030305},
+       {0x0000b098, 0x00000003},
+       {0x0000b09c, 0x00000000},
        {0x0000b0a0, 0x00000000},
        {0x0000b0a4, 0x00000000},
        {0x0000b0a8, 0x00000000},
@@ -944,7 +973,11 @@ static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
 };
 
 static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
-       /*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -952,8 +985,8 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
        {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
        {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-       {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
-       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+       {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
        {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
        {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
        {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
@@ -965,19 +998,19 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
        {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
        {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
-       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
-       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
-       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
-       {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
-       {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
-       {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
        {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
        {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
        {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -1010,14 +1043,40 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
        {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
-       {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+       {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
+       {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+       {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000},
        {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
-       {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+       {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266},
 };
 
 static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
-       /*  Addr       5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -1025,8 +1084,8 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
        {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
        {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
-       {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+       {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
        {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
        {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
        {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
@@ -1038,19 +1097,19 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
        {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84},
-       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+       {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec},
        {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
        {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
        {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -1083,14 +1142,36 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
        {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
        {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
        {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
+       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
+       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
+       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
+       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
+       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
+       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
+       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
+       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
        {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
-       {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266},
+       {0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
+       {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015},
+       {0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000},
        {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
-       {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266},
+       {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266},
 };
 
 static const u32 ar9340_1p0_mac_core[][2] = {
-       /*    Addr        allmodes        */
+       /* Addr      allmodes  */
        {0x00000008, 0x00000000},
        {0x00000030, 0x00020085},
        {0x00000034, 0x00000005},
@@ -1119,6 +1200,7 @@ static const u32 ar9340_1p0_mac_core[][2] = {
        {0x00008004, 0x00000000},
        {0x00008008, 0x00000000},
        {0x0000800c, 0x00000000},
+       {0x00008010, 0x00080800},
        {0x00008018, 0x00000000},
        {0x00008020, 0x00000000},
        {0x00008038, 0x00000000},
@@ -1146,7 +1228,7 @@ static const u32 ar9340_1p0_mac_core[][2] = {
        {0x000080bc, 0x00000000},
        {0x000080c0, 0x2a800000},
        {0x000080c4, 0x06900168},
-       {0x000080c8, 0x13881c20},
+       {0x000080c8, 0x13881c22},
        {0x000080cc, 0x01f40000},
        {0x000080d0, 0x00252500},
        {0x000080d4, 0x00a00000},
@@ -1250,276 +1332,17 @@ static const u32 ar9340_1p0_mac_core[][2] = {
        {0x000083c4, 0x00000000},
        {0x000083c8, 0x00000000},
        {0x000083cc, 0x00000200},
-       {0x000083d0, 0x000301ff},
+       {0x000083d0, 0x000101ff},
 };
 
-static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = {
-       /*    Addr        allmodes        */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x32323232},
-       {0x0000b084, 0x2f2f3232},
-       {0x0000b088, 0x23282a2d},
-       {0x0000b08c, 0x1c1e2123},
-       {0x0000b090, 0x14171919},
-       {0x0000b094, 0x0e0e1214},
-       {0x0000b098, 0x03050707},
-       {0x0000b09c, 0x00030303},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
+#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2
 
 static const u32 ar9340_1p0_soc_preamble[][2] = {
-       /*    Addr        allmodes        */
-       {0x000040a4, 0x00a0c1c9},
+       /* Addr      allmodes  */
        {0x00007008, 0x00000000},
        {0x00007020, 0x00000000},
        {0x00007034, 0x00000002},
        {0x00007038, 0x000004c2},
 };
 
-#endif
+#endif /* INITVALS_9340_H */
index 1d6658e139b56203460f5df454de83de6d0a1b73..4ef7dcccaa2f6bd114dfef8cd3741956ac63f328 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
@@ -52,7 +53,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
        {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
@@ -61,7 +62,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-       {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0},
+       {0x0000a204, 0x01318fc0, 0x01318fc4, 0x01318fc4, 0x01318fc0},
        {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
        {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f},
        {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
@@ -958,7 +959,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
        {0x0001604c, 0x2699e04f},
        {0x00016050, 0x6db6db6c},
        {0x00016058, 0x6c200000},
-       {0x00016080, 0x00040000},
+       {0x00016080, 0x000c0000},
        {0x00016084, 0x9a68048c},
        {0x00016088, 0x54214514},
        {0x0001608c, 0x1203040b},
@@ -981,7 +982,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
        {0x00016144, 0x02084080},
        {0x00016148, 0x000080c0},
        {0x00016280, 0x050a0001},
-       {0x00016284, 0x3d841400},
+       {0x00016284, 0x3d841418},
        {0x00016288, 0x00000000},
        {0x0001628c, 0xe3000000},
        {0x00016290, 0xa1005080},
@@ -1007,6 +1008,7 @@ static const u32 ar9462_2p0_radio_core[][2] = {
 
 static const u32 ar9462_2p0_soc_preamble[][2] = {
        /* Addr      allmodes  */
+       {0x000040a4, 0x00a0c1c9},
        {0x00007020, 0x00000000},
        {0x00007034, 0x00000002},
        {0x00007038, 0x000004c2},
index d16d029f81a9db1d45dbd7f0115e057d3be3bf1d..fb4497fc7a3da1e87547cda3e8a7fe76497504c8 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
 #ifndef INITVALS_9485_H
 #define INITVALS_9485_H
 
-static const u32 ar9485_1_1_mac_core[][2] = {
-       /*  Addr       allmodes */
-       {0x00000008, 0x00000000},
-       {0x00000030, 0x00020085},
-       {0x00000034, 0x00000005},
-       {0x00000040, 0x00000000},
-       {0x00000044, 0x00000000},
-       {0x00000048, 0x00000008},
-       {0x0000004c, 0x00000010},
-       {0x00000050, 0x00000000},
-       {0x00001040, 0x002ffc0f},
-       {0x00001044, 0x002ffc0f},
-       {0x00001048, 0x002ffc0f},
-       {0x0000104c, 0x002ffc0f},
-       {0x00001050, 0x002ffc0f},
-       {0x00001054, 0x002ffc0f},
-       {0x00001058, 0x002ffc0f},
-       {0x0000105c, 0x002ffc0f},
-       {0x00001060, 0x002ffc0f},
-       {0x00001064, 0x002ffc0f},
-       {0x000010f0, 0x00000100},
-       {0x00001270, 0x00000000},
-       {0x000012b0, 0x00000000},
-       {0x000012f0, 0x00000000},
-       {0x0000143c, 0x00000000},
-       {0x0000147c, 0x00000000},
-       {0x00008000, 0x00000000},
-       {0x00008004, 0x00000000},
-       {0x00008008, 0x00000000},
-       {0x0000800c, 0x00000000},
-       {0x00008018, 0x00000000},
-       {0x00008020, 0x00000000},
-       {0x00008038, 0x00000000},
-       {0x0000803c, 0x00000000},
-       {0x00008040, 0x00000000},
-       {0x00008044, 0x00000000},
-       {0x00008048, 0x00000000},
-       {0x0000804c, 0xffffffff},
-       {0x00008054, 0x00000000},
-       {0x00008058, 0x00000000},
-       {0x0000805c, 0x000fc78f},
-       {0x00008060, 0x0000000f},
-       {0x00008064, 0x00000000},
-       {0x00008070, 0x00000310},
-       {0x00008074, 0x00000020},
-       {0x00008078, 0x00000000},
-       {0x0000809c, 0x0000000f},
-       {0x000080a0, 0x00000000},
-       {0x000080a4, 0x02ff0000},
-       {0x000080a8, 0x0e070605},
-       {0x000080ac, 0x0000000d},
-       {0x000080b0, 0x00000000},
-       {0x000080b4, 0x00000000},
-       {0x000080b8, 0x00000000},
-       {0x000080bc, 0x00000000},
-       {0x000080c0, 0x2a800000},
-       {0x000080c4, 0x06900168},
-       {0x000080c8, 0x13881c22},
-       {0x000080cc, 0x01f40000},
-       {0x000080d0, 0x00252500},
-       {0x000080d4, 0x00a00000},
-       {0x000080d8, 0x00400000},
-       {0x000080dc, 0x00000000},
-       {0x000080e0, 0xffffffff},
-       {0x000080e4, 0x0000ffff},
-       {0x000080e8, 0x3f3f3f3f},
-       {0x000080ec, 0x00000000},
-       {0x000080f0, 0x00000000},
-       {0x000080f4, 0x00000000},
-       {0x000080fc, 0x00020000},
-       {0x00008100, 0x00000000},
-       {0x00008108, 0x00000052},
-       {0x0000810c, 0x00000000},
-       {0x00008110, 0x00000000},
-       {0x00008114, 0x000007ff},
-       {0x00008118, 0x000000aa},
-       {0x0000811c, 0x00003210},
-       {0x00008124, 0x00000000},
-       {0x00008128, 0x00000000},
-       {0x0000812c, 0x00000000},
-       {0x00008130, 0x00000000},
-       {0x00008134, 0x00000000},
-       {0x00008138, 0x00000000},
-       {0x0000813c, 0x0000ffff},
-       {0x00008144, 0xffffffff},
-       {0x00008168, 0x00000000},
-       {0x0000816c, 0x00000000},
-       {0x00008170, 0x18486200},
-       {0x00008174, 0x33332210},
-       {0x00008178, 0x00000000},
-       {0x0000817c, 0x00020000},
-       {0x000081c0, 0x00000000},
-       {0x000081c4, 0x33332210},
-       {0x000081d4, 0x00000000},
-       {0x000081ec, 0x00000000},
-       {0x000081f0, 0x00000000},
-       {0x000081f4, 0x00000000},
-       {0x000081f8, 0x00000000},
-       {0x000081fc, 0x00000000},
-       {0x00008240, 0x00100000},
-       {0x00008244, 0x0010f400},
-       {0x00008248, 0x00000800},
-       {0x0000824c, 0x0001e800},
-       {0x00008250, 0x00000000},
-       {0x00008254, 0x00000000},
-       {0x00008258, 0x00000000},
-       {0x0000825c, 0x40000000},
-       {0x00008260, 0x00080922},
-       {0x00008264, 0x9ca00010},
-       {0x00008268, 0xffffffff},
-       {0x0000826c, 0x0000ffff},
-       {0x00008270, 0x00000000},
-       {0x00008274, 0x40000000},
-       {0x00008278, 0x003e4180},
-       {0x0000827c, 0x00000004},
-       {0x00008284, 0x0000002c},
-       {0x00008288, 0x0000002c},
-       {0x0000828c, 0x000000ff},
-       {0x00008294, 0x00000000},
-       {0x00008298, 0x00000000},
-       {0x0000829c, 0x00000000},
-       {0x00008300, 0x00000140},
-       {0x00008314, 0x00000000},
-       {0x0000831c, 0x0000010d},
-       {0x00008328, 0x00000000},
-       {0x0000832c, 0x00000007},
-       {0x00008330, 0x00000302},
-       {0x00008334, 0x00000700},
-       {0x00008338, 0x00ff0000},
-       {0x0000833c, 0x02400000},
-       {0x00008340, 0x000107ff},
-       {0x00008344, 0xa248105b},
-       {0x00008348, 0x008f0000},
-       {0x0000835c, 0x00000000},
-       {0x00008360, 0xffffffff},
-       {0x00008364, 0xffffffff},
-       {0x00008368, 0x00000000},
-       {0x00008370, 0x00000000},
-       {0x00008374, 0x000000ff},
-       {0x00008378, 0x00000000},
-       {0x0000837c, 0x00000000},
-       {0x00008380, 0xffffffff},
-       {0x00008384, 0xffffffff},
-       {0x00008390, 0xffffffff},
-       {0x00008394, 0xffffffff},
-       {0x00008398, 0x00000000},
-       {0x0000839c, 0x00000000},
-       {0x000083a0, 0x00000000},
-       {0x000083a4, 0x0000fa14},
-       {0x000083a8, 0x000f0c00},
-       {0x000083ac, 0x33332210},
-       {0x000083b0, 0x33332210},
-       {0x000083b4, 0x33332210},
-       {0x000083b8, 0x33332210},
-       {0x000083bc, 0x00000000},
-       {0x000083c0, 0x00000000},
-       {0x000083c4, 0x00000000},
-       {0x000083c8, 0x00000000},
-       {0x000083cc, 0x00000200},
-       {0x000083d0, 0x000301ff},
-};
-
-static const u32 ar9485_1_1_baseband_core[][2] = {
-       /* Addr       allmodes */
-       {0x00009800, 0xafe68e30},
-       {0x00009804, 0xfd14e000},
-       {0x00009808, 0x9c0a8f6b},
-       {0x0000980c, 0x04800000},
-       {0x00009814, 0x9280c00a},
-       {0x00009818, 0x00000000},
-       {0x0000981c, 0x00020028},
-       {0x00009834, 0x5f3ca3de},
-       {0x00009838, 0x0108ecff},
-       {0x0000983c, 0x14750600},
-       {0x00009880, 0x201fff00},
-       {0x00009884, 0x00001042},
-       {0x000098a4, 0x00200400},
-       {0x000098b0, 0x52440bbe},
-       {0x000098d0, 0x004b6a8e},
-       {0x000098d4, 0x00000820},
-       {0x000098dc, 0x00000000},
-       {0x000098f0, 0x00000000},
-       {0x000098f4, 0x00000000},
-       {0x00009c04, 0x00000000},
-       {0x00009c08, 0x03200000},
-       {0x00009c0c, 0x00000000},
-       {0x00009c10, 0x00000000},
-       {0x00009c14, 0x00046384},
-       {0x00009c18, 0x05b6b440},
-       {0x00009c1c, 0x00b6b440},
-       {0x00009d00, 0xc080a333},
-       {0x00009d04, 0x40206c10},
-       {0x00009d08, 0x009c4060},
-       {0x00009d0c, 0x1883800a},
-       {0x00009d10, 0x01834061},
-       {0x00009d14, 0x00c00400},
-       {0x00009d18, 0x00000000},
-       {0x00009d1c, 0x00000000},
-       {0x00009e08, 0x0038233c},
-       {0x00009e24, 0x9927b515},
-       {0x00009e28, 0x12ef0200},
-       {0x00009e30, 0x06336f77},
-       {0x00009e34, 0x6af6532f},
-       {0x00009e38, 0x0cc80c00},
-       {0x00009e40, 0x0d261820},
-       {0x00009e4c, 0x00001004},
-       {0x00009e50, 0x00ff03f1},
-       {0x00009fc0, 0x80be4788},
-       {0x00009fc4, 0x0001efb5},
-       {0x00009fcc, 0x40000014},
-       {0x0000a20c, 0x00000000},
-       {0x0000a210, 0x00000000},
-       {0x0000a220, 0x00000000},
-       {0x0000a224, 0x00000000},
-       {0x0000a228, 0x10002310},
-       {0x0000a23c, 0x00000000},
-       {0x0000a244, 0x0c000000},
-       {0x0000a2a0, 0x00000001},
-       {0x0000a2c0, 0x00000001},
-       {0x0000a2c8, 0x00000000},
-       {0x0000a2cc, 0x18c43433},
-       {0x0000a2d4, 0x00000000},
-       {0x0000a2dc, 0x00000000},
-       {0x0000a2e0, 0x00000000},
-       {0x0000a2e4, 0x00000000},
-       {0x0000a2e8, 0x00000000},
-       {0x0000a2ec, 0x00000000},
-       {0x0000a2f0, 0x00000000},
-       {0x0000a2f4, 0x00000000},
-       {0x0000a2f8, 0x00000000},
-       {0x0000a344, 0x00000000},
-       {0x0000a34c, 0x00000000},
-       {0x0000a350, 0x0000a000},
-       {0x0000a364, 0x00000000},
-       {0x0000a370, 0x00000000},
-       {0x0000a390, 0x00000001},
-       {0x0000a394, 0x00000444},
-       {0x0000a398, 0x001f0e0f},
-       {0x0000a39c, 0x0075393f},
-       {0x0000a3a0, 0xb79f6427},
-       {0x0000a3a4, 0x000000ff},
-       {0x0000a3a8, 0x3b3b3b3b},
-       {0x0000a3ac, 0x2f2f2f2f},
-       {0x0000a3c0, 0x20202020},
-       {0x0000a3c4, 0x22222220},
-       {0x0000a3c8, 0x20200020},
-       {0x0000a3cc, 0x20202020},
-       {0x0000a3d0, 0x20202020},
-       {0x0000a3d4, 0x20202020},
-       {0x0000a3d8, 0x20202020},
-       {0x0000a3dc, 0x20202020},
-       {0x0000a3e0, 0x20202020},
-       {0x0000a3e4, 0x20202020},
-       {0x0000a3e8, 0x20202020},
-       {0x0000a3ec, 0x20202020},
-       {0x0000a3f0, 0x00000000},
-       {0x0000a3f4, 0x00000006},
-       {0x0000a3f8, 0x0cdbd380},
-       {0x0000a3fc, 0x000f0f01},
-       {0x0000a400, 0x8fa91f01},
-       {0x0000a404, 0x00000000},
-       {0x0000a408, 0x0e79e5c6},
-       {0x0000a40c, 0x00820820},
-       {0x0000a414, 0x1ce739cf},
-       {0x0000a418, 0x2d0019ce},
-       {0x0000a41c, 0x1ce739ce},
-       {0x0000a420, 0x000001ce},
-       {0x0000a424, 0x1ce739ce},
-       {0x0000a428, 0x000001ce},
-       {0x0000a42c, 0x1ce739ce},
-       {0x0000a430, 0x1ce739ce},
-       {0x0000a434, 0x00000000},
-       {0x0000a438, 0x00001801},
-       {0x0000a43c, 0x00000000},
-       {0x0000a440, 0x00000000},
-       {0x0000a444, 0x00000000},
-       {0x0000a448, 0x04000000},
-       {0x0000a44c, 0x00000001},
-       {0x0000a450, 0x00010000},
-       {0x0000a5c4, 0xbfad9d74},
-       {0x0000a5c8, 0x0048060a},
-       {0x0000a5cc, 0x00000637},
-       {0x0000a760, 0x03020100},
-       {0x0000a764, 0x09080504},
-       {0x0000a768, 0x0d0c0b0a},
-       {0x0000a76c, 0x13121110},
-       {0x0000a770, 0x31301514},
-       {0x0000a774, 0x35343332},
-       {0x0000a778, 0x00000036},
-       {0x0000a780, 0x00000838},
-       {0x0000a7c0, 0x00000000},
-       {0x0000a7c4, 0xfffffffc},
-       {0x0000a7c8, 0x00000000},
-       {0x0000a7cc, 0x00000000},
-       {0x0000a7d0, 0x00000000},
-       {0x0000a7d4, 0x00000004},
-       {0x0000a7dc, 0x00000000},
-};
-
-static const u32 ar9485Common_1_1[][2] = {
-       /*  Addr      allmodes */
-       {0x00007010, 0x00000022},
-       {0x00007020, 0x00000000},
-       {0x00007034, 0x00000002},
-       {0x00007038, 0x000004c2},
-};
-
-static const u32 ar9485_1_1_baseband_postamble[][5] = {
-       /* Addr       5G_HT20        5G_HT40       2G_HT40       2G_HT20 */
-       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
-       {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
-       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
-       {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
-       {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
-       {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
-       {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
-       {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
-       {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
-       {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
-       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
-       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
-       {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
-       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
-       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
-       {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
-       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
-       {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
-       {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
-       {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
-       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
-       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
-       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
-       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
-       {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
-       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
-       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
-       {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
-       {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
-       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
-       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
-       {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
-static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
-       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
-};
-
-static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20  */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
-       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
-};
-
-static const u32 ar9485_1_1_radio_postamble[][2] = {
-       /* Addr        allmodes */
-       {0x0001609c, 0x0b283f31},
-       {0x000160ac, 0x24611800},
-       {0x000160b0, 0x03284f3e},
-       {0x0001610c, 0x00170000},
-       {0x00016140, 0x50804008},
-};
-
-static const u32 ar9485_1_1_mac_postamble[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
+/* AR9485 1.0 */
 
-static const u32 ar9485_1_1_radio_core[][2] = {
-       /* Addr        allmodes */
-       {0x00016000, 0x36db6db6},
-       {0x00016004, 0x6db6db40},
-       {0x00016008, 0x73800000},
-       {0x0001600c, 0x00000000},
-       {0x00016040, 0x7f80fff8},
-       {0x0001604c, 0x000f0278},
-       {0x00016050, 0x4db6db8c},
-       {0x00016054, 0x6db60000},
-       {0x00016080, 0x00080000},
-       {0x00016084, 0x0e48048c},
-       {0x00016088, 0x14214514},
-       {0x0001608c, 0x119f081e},
-       {0x00016090, 0x24926490},
-       {0x00016098, 0xd28b3330},
-       {0x000160a0, 0xc2108ffe},
-       {0x000160a4, 0x812fc370},
-       {0x000160a8, 0x423c8000},
-       {0x000160b4, 0x92480040},
-       {0x000160c0, 0x006db6db},
-       {0x000160c4, 0x0186db60},
-       {0x000160c8, 0x6db6db6c},
-       {0x000160cc, 0x6de6fbe0},
-       {0x000160d0, 0xf7dfcf3c},
-       {0x00016100, 0x04cb0001},
-       {0x00016104, 0xfff80015},
-       {0x00016108, 0x00080010},
-       {0x00016144, 0x01884080},
-       {0x00016148, 0x00008040},
-       {0x00016240, 0x08400000},
-       {0x00016244, 0x1bf90f00},
-       {0x00016248, 0x00000000},
-       {0x0001624c, 0x00000000},
-       {0x00016280, 0x01000015},
-       {0x00016284, 0x00d30000},
-       {0x00016288, 0x00318000},
-       {0x0001628c, 0x50000000},
-       {0x00016290, 0x4b96210f},
-       {0x00016380, 0x00000000},
-       {0x00016384, 0x00000000},
-       {0x00016388, 0x00800700},
-       {0x0001638c, 0x00800700},
-       {0x00016390, 0x00800700},
-       {0x00016394, 0x00000000},
-       {0x00016398, 0x00000000},
-       {0x0001639c, 0x00000000},
-       {0x000163a0, 0x00000001},
-       {0x000163a4, 0x00000001},
-       {0x000163a8, 0x00000000},
-       {0x000163ac, 0x00000000},
-       {0x000163b0, 0x00000000},
-       {0x000163b4, 0x00000000},
-       {0x000163b8, 0x00000000},
-       {0x000163bc, 0x00000000},
-       {0x000163c0, 0x000000a0},
-       {0x000163c4, 0x000c0000},
-       {0x000163c8, 0x14021402},
-       {0x000163cc, 0x00001402},
-       {0x000163d0, 0x00000000},
-       {0x000163d4, 0x00000000},
-       {0x00016c40, 0x13188278},
-       {0x00016c44, 0x12000000},
-};
+#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble
 
-static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
-       /* Addr        allmodes */
-       {0x00018c00, 0x18052e5e},
+static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x18012e5e},
        {0x00018c04, 0x000801d8},
        {0x00018c08, 0x0000080c},
 };
 
+static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a000, 0x00060005},
+       {0x0000a004, 0x00810080},
+       {0x0000a008, 0x00830082},
+       {0x0000a00c, 0x00850084},
+       {0x0000a010, 0x01820181},
+       {0x0000a014, 0x01840183},
+       {0x0000a018, 0x01880185},
+       {0x0000a01c, 0x018a0189},
+       {0x0000a020, 0x02850284},
+       {0x0000a024, 0x02890288},
+       {0x0000a028, 0x028b028a},
+       {0x0000a02c, 0x03850384},
+       {0x0000a030, 0x03890388},
+       {0x0000a034, 0x038b038a},
+       {0x0000a038, 0x038d038c},
+       {0x0000a03c, 0x03910390},
+       {0x0000a040, 0x03930392},
+       {0x0000a044, 0x03950394},
+       {0x0000a048, 0x00000396},
+       {0x0000a04c, 0x00000000},
+       {0x0000a050, 0x00000000},
+       {0x0000a054, 0x00000000},
+       {0x0000a058, 0x00000000},
+       {0x0000a05c, 0x00000000},
+       {0x0000a060, 0x00000000},
+       {0x0000a064, 0x00000000},
+       {0x0000a068, 0x00000000},
+       {0x0000a06c, 0x00000000},
+       {0x0000a070, 0x00000000},
+       {0x0000a074, 0x00000000},
+       {0x0000a078, 0x00000000},
+       {0x0000a07c, 0x00000000},
+       {0x0000a080, 0x28282828},
+       {0x0000a084, 0x28282828},
+       {0x0000a088, 0x28282828},
+       {0x0000a08c, 0x28282828},
+       {0x0000a090, 0x28282828},
+       {0x0000a094, 0x24242428},
+       {0x0000a098, 0x171e1e1e},
+       {0x0000a09c, 0x02020b0b},
+       {0x0000a0a0, 0x02020202},
+       {0x0000a0a4, 0x00000000},
+       {0x0000a0a8, 0x00000000},
+       {0x0000a0ac, 0x00000000},
+       {0x0000a0b0, 0x00000000},
+       {0x0000a0b4, 0x00000000},
+       {0x0000a0b8, 0x00000000},
+       {0x0000a0bc, 0x00000000},
+       {0x0000a0c0, 0x22072208},
+       {0x0000a0c4, 0x22052206},
+       {0x0000a0c8, 0x22032204},
+       {0x0000a0cc, 0x22012202},
+       {0x0000a0d0, 0x221f2200},
+       {0x0000a0d4, 0x221d221e},
+       {0x0000a0d8, 0x33023303},
+       {0x0000a0dc, 0x33003301},
+       {0x0000a0e0, 0x331e331f},
+       {0x0000a0e4, 0x4402331d},
+       {0x0000a0e8, 0x44004401},
+       {0x0000a0ec, 0x441e441f},
+       {0x0000a0f0, 0x55025503},
+       {0x0000a0f4, 0x55005501},
+       {0x0000a0f8, 0x551e551f},
+       {0x0000a0fc, 0x6602551d},
+       {0x0000a100, 0x66006601},
+       {0x0000a104, 0x661e661f},
+       {0x0000a108, 0x7703661d},
+       {0x0000a10c, 0x77017702},
+       {0x0000a110, 0x00007700},
+       {0x0000a114, 0x00000000},
+       {0x0000a118, 0x00000000},
+       {0x0000a11c, 0x00000000},
+       {0x0000a120, 0x00000000},
+       {0x0000a124, 0x00000000},
+       {0x0000a128, 0x00000000},
+       {0x0000a12c, 0x00000000},
+       {0x0000a130, 0x00000000},
+       {0x0000a134, 0x00000000},
+       {0x0000a138, 0x00000000},
+       {0x0000a13c, 0x00000000},
+       {0x0000a140, 0x001f0000},
+       {0x0000a144, 0x111f1100},
+       {0x0000a148, 0x111d111e},
+       {0x0000a14c, 0x111b111c},
+       {0x0000a150, 0x22032204},
+       {0x0000a154, 0x22012202},
+       {0x0000a158, 0x221f2200},
+       {0x0000a15c, 0x221d221e},
+       {0x0000a160, 0x33013302},
+       {0x0000a164, 0x331f3300},
+       {0x0000a168, 0x4402331e},
+       {0x0000a16c, 0x44004401},
+       {0x0000a170, 0x441e441f},
+       {0x0000a174, 0x55015502},
+       {0x0000a178, 0x551f5500},
+       {0x0000a17c, 0x6602551e},
+       {0x0000a180, 0x66006601},
+       {0x0000a184, 0x661e661f},
+       {0x0000a188, 0x7703661d},
+       {0x0000a18c, 0x77017702},
+       {0x0000a190, 0x00007700},
+       {0x0000a194, 0x00000000},
+       {0x0000a198, 0x00000000},
+       {0x0000a19c, 0x00000000},
+       {0x0000a1a0, 0x00000000},
+       {0x0000a1a4, 0x00000000},
+       {0x0000a1a8, 0x00000000},
+       {0x0000a1ac, 0x00000000},
+       {0x0000a1b0, 0x00000000},
+       {0x0000a1b4, 0x00000000},
+       {0x0000a1b8, 0x00000000},
+       {0x0000a1bc, 0x00000000},
+       {0x0000a1c0, 0x00000000},
+       {0x0000a1c4, 0x00000000},
+       {0x0000a1c8, 0x00000000},
+       {0x0000a1cc, 0x00000000},
+       {0x0000a1d0, 0x00000000},
+       {0x0000a1d4, 0x00000000},
+       {0x0000a1d8, 0x00000000},
+       {0x0000a1dc, 0x00000000},
+       {0x0000a1e0, 0x00000000},
+       {0x0000a1e4, 0x00000000},
+       {0x0000a1e8, 0x00000000},
+       {0x0000a1ec, 0x00000000},
+       {0x0000a1f0, 0x00000396},
+       {0x0000a1f4, 0x00000396},
+       {0x0000a1f8, 0x00000396},
+       {0x0000a1fc, 0x00000296},
+};
+
 static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
        {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -681,8 +234,14 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
+#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1
+
+#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1
+
+#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
+
 static const u32 ar9485_1_1[][2] = {
-       /* Addr        allmodes */
+       /* Addr      allmodes  */
        {0x0000a580, 0x00000000},
        {0x0000a584, 0x00000000},
        {0x0000a588, 0x00000000},
@@ -701,194 +260,210 @@ static const u32 ar9485_1_1[][2] = {
        {0x0000a5bc, 0x00000000},
 };
 
-static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
-       {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-       {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
-       {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
-       {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
-       {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
-       {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
-       {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
-       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
-       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
-};
-
-static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
-       /* Addr        allmodes */
-       {0x00018c00, 0x18013e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
-static const u32 ar9485_1_1_soc_preamble[][2] = {
-       /* Addr        allmodes */
-       {0x00004014, 0xba280400},
-       {0x00004090, 0x00aa10aa},
-       {0x000040a4, 0x00a0c9c9},
-       {0x00007010, 0x00000022},
-       {0x00007020, 0x00000000},
-       {0x00007034, 0x00000002},
-       {0x00007038, 0x000004c2},
-       {0x00007048, 0x00000002},
-};
-
-static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr        allmodes */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
-
-static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
-       /* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20  */
-       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
-       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
-       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
-       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
-       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
-       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
-       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
-       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
-       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
-       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
-       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
-       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
-       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
-       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
-       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
-};
-
-static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = {
-       /* Addr        5G_HT2        5G_HT40  */
-       {0x00009e00, 0x03721821, 0x03721821},
-       {0x0000a230, 0x0000400b, 0x00004016},
-       {0x0000a254, 0x00000898, 0x00001130},
+static const u32 ar9485_1_1_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00016000, 0x36db6db6},
+       {0x00016004, 0x6db6db40},
+       {0x00016008, 0x73800000},
+       {0x0001600c, 0x00000000},
+       {0x00016040, 0x7f80fff8},
+       {0x0001604c, 0x000f0278},
+       {0x00016050, 0x4db6db8c},
+       {0x00016054, 0x6db60000},
+       {0x00016080, 0x00080000},
+       {0x00016084, 0x0e48048c},
+       {0x00016088, 0x14214514},
+       {0x0001608c, 0x119f081e},
+       {0x00016090, 0x24926490},
+       {0x00016098, 0xd28b3330},
+       {0x000160a0, 0xc2108ffe},
+       {0x000160a4, 0x812fc370},
+       {0x000160a8, 0x423c8000},
+       {0x000160b4, 0x92480040},
+       {0x000160c0, 0x006db6db},
+       {0x000160c4, 0x0186db60},
+       {0x000160c8, 0x6db6db6c},
+       {0x000160cc, 0x6de6fbe0},
+       {0x000160d0, 0xf7dfcf3c},
+       {0x00016100, 0x04cb0001},
+       {0x00016104, 0xfff80015},
+       {0x00016108, 0x00080010},
+       {0x00016144, 0x01884080},
+       {0x00016148, 0x00008040},
+       {0x00016240, 0x08400000},
+       {0x00016244, 0x1bf90f00},
+       {0x00016248, 0x00000000},
+       {0x0001624c, 0x00000000},
+       {0x00016280, 0x01000015},
+       {0x00016284, 0x00d30000},
+       {0x00016288, 0x00318000},
+       {0x0001628c, 0x50000000},
+       {0x00016290, 0x4b96210f},
+       {0x00016380, 0x00000000},
+       {0x00016384, 0x00000000},
+       {0x00016388, 0x00800700},
+       {0x0001638c, 0x00800700},
+       {0x00016390, 0x00800700},
+       {0x00016394, 0x00000000},
+       {0x00016398, 0x00000000},
+       {0x0001639c, 0x00000000},
+       {0x000163a0, 0x00000001},
+       {0x000163a4, 0x00000001},
+       {0x000163a8, 0x00000000},
+       {0x000163ac, 0x00000000},
+       {0x000163b0, 0x00000000},
+       {0x000163b4, 0x00000000},
+       {0x000163b8, 0x00000000},
+       {0x000163bc, 0x00000000},
+       {0x000163c0, 0x000000a0},
+       {0x000163c4, 0x000c0000},
+       {0x000163c8, 0x14021402},
+       {0x000163cc, 0x00001402},
+       {0x000163d0, 0x00000000},
+       {0x000163d4, 0x00000000},
+       {0x00016c40, 0x13188278},
+       {0x00016c44, 0x12000000},
 };
 
-static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
-       /* Addr        allmodes  */
-       {0x00018c00, 0x18012e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
+static const u32 ar9485_1_1_baseband_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00009800, 0xafe68e30},
+       {0x00009804, 0xfd14e000},
+       {0x00009808, 0x9c0a8f6b},
+       {0x0000980c, 0x04800000},
+       {0x00009814, 0x9280c00a},
+       {0x00009818, 0x00000000},
+       {0x0000981c, 0x00020028},
+       {0x00009834, 0x5f3ca3de},
+       {0x00009838, 0x0108ecff},
+       {0x0000983c, 0x14750600},
+       {0x00009880, 0x201fff00},
+       {0x00009884, 0x00001042},
+       {0x000098a4, 0x00200400},
+       {0x000098b0, 0x52440bbe},
+       {0x000098d0, 0x004b6a8e},
+       {0x000098d4, 0x00000820},
+       {0x000098dc, 0x00000000},
+       {0x000098f0, 0x00000000},
+       {0x000098f4, 0x00000000},
+       {0x00009c04, 0x00000000},
+       {0x00009c08, 0x03200000},
+       {0x00009c0c, 0x00000000},
+       {0x00009c10, 0x00000000},
+       {0x00009c14, 0x00046384},
+       {0x00009c18, 0x05b6b440},
+       {0x00009c1c, 0x00b6b440},
+       {0x00009d00, 0xc080a333},
+       {0x00009d04, 0x40206c10},
+       {0x00009d08, 0x009c4060},
+       {0x00009d0c, 0x1883800a},
+       {0x00009d10, 0x01834061},
+       {0x00009d14, 0x00c00400},
+       {0x00009d18, 0x00000000},
+       {0x00009d1c, 0x00000000},
+       {0x00009e08, 0x0038233c},
+       {0x00009e24, 0x9927b515},
+       {0x00009e28, 0x12ef0200},
+       {0x00009e30, 0x06336f77},
+       {0x00009e34, 0x6af6532f},
+       {0x00009e38, 0x0cc80c00},
+       {0x00009e40, 0x0d261820},
+       {0x00009e4c, 0x00001004},
+       {0x00009e50, 0x00ff03f1},
+       {0x00009fc0, 0x80be4788},
+       {0x00009fc4, 0x0001efb5},
+       {0x00009fcc, 0x40000014},
+       {0x0000a20c, 0x00000000},
+       {0x0000a210, 0x00000000},
+       {0x0000a220, 0x00000000},
+       {0x0000a224, 0x00000000},
+       {0x0000a228, 0x10002310},
+       {0x0000a23c, 0x00000000},
+       {0x0000a244, 0x0c000000},
+       {0x0000a2a0, 0x00000001},
+       {0x0000a2c0, 0x00000001},
+       {0x0000a2c8, 0x00000000},
+       {0x0000a2cc, 0x18c43433},
+       {0x0000a2d4, 0x00000000},
+       {0x0000a2dc, 0x00000000},
+       {0x0000a2e0, 0x00000000},
+       {0x0000a2e4, 0x00000000},
+       {0x0000a2e8, 0x00000000},
+       {0x0000a2ec, 0x00000000},
+       {0x0000a2f0, 0x00000000},
+       {0x0000a2f4, 0x00000000},
+       {0x0000a2f8, 0x00000000},
+       {0x0000a344, 0x00000000},
+       {0x0000a34c, 0x00000000},
+       {0x0000a350, 0x0000a000},
+       {0x0000a364, 0x00000000},
+       {0x0000a370, 0x00000000},
+       {0x0000a390, 0x00000001},
+       {0x0000a394, 0x00000444},
+       {0x0000a398, 0x001f0e0f},
+       {0x0000a39c, 0x0075393f},
+       {0x0000a3a0, 0xb79f6427},
+       {0x0000a3a4, 0x000000ff},
+       {0x0000a3a8, 0x3b3b3b3b},
+       {0x0000a3ac, 0x2f2f2f2f},
+       {0x0000a3c0, 0x20202020},
+       {0x0000a3c4, 0x22222220},
+       {0x0000a3c8, 0x20200020},
+       {0x0000a3cc, 0x20202020},
+       {0x0000a3d0, 0x20202020},
+       {0x0000a3d4, 0x20202020},
+       {0x0000a3d8, 0x20202020},
+       {0x0000a3dc, 0x20202020},
+       {0x0000a3e0, 0x20202020},
+       {0x0000a3e4, 0x20202020},
+       {0x0000a3e8, 0x20202020},
+       {0x0000a3ec, 0x20202020},
+       {0x0000a3f0, 0x00000000},
+       {0x0000a3f4, 0x00000006},
+       {0x0000a3f8, 0x0cdbd380},
+       {0x0000a3fc, 0x000f0f01},
+       {0x0000a400, 0x8fa91f01},
+       {0x0000a404, 0x00000000},
+       {0x0000a408, 0x0e79e5c6},
+       {0x0000a40c, 0x00820820},
+       {0x0000a414, 0x1ce739cf},
+       {0x0000a418, 0x2d0019ce},
+       {0x0000a41c, 0x1ce739ce},
+       {0x0000a420, 0x000001ce},
+       {0x0000a424, 0x1ce739ce},
+       {0x0000a428, 0x000001ce},
+       {0x0000a42c, 0x1ce739ce},
+       {0x0000a430, 0x1ce739ce},
+       {0x0000a434, 0x00000000},
+       {0x0000a438, 0x00001801},
+       {0x0000a43c, 0x00000000},
+       {0x0000a440, 0x00000000},
+       {0x0000a444, 0x00000000},
+       {0x0000a448, 0x04000000},
+       {0x0000a44c, 0x00000001},
+       {0x0000a450, 0x00010000},
+       {0x0000a5c4, 0xbfad9d74},
+       {0x0000a5c8, 0x0048060a},
+       {0x0000a5cc, 0x00000637},
+       {0x0000a760, 0x03020100},
+       {0x0000a764, 0x09080504},
+       {0x0000a768, 0x0d0c0b0a},
+       {0x0000a76c, 0x13121110},
+       {0x0000a770, 0x31301514},
+       {0x0000a774, 0x35343332},
+       {0x0000a778, 0x00000036},
+       {0x0000a780, 0x00000838},
+       {0x0000a7c0, 0x00000000},
+       {0x0000a7c4, 0xfffffffc},
+       {0x0000a7c8, 0x00000000},
+       {0x0000a7cc, 0x00000000},
+       {0x0000a7d0, 0x00000000},
+       {0x0000a7d4, 0x00000004},
+       {0x0000a7dc, 0x00000000},
 };
 
 static const u32 ar9485_common_rx_gain_1_1[][2] = {
-       /* Addr        allmodes */
+       /* Addr      allmodes  */
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
        {0x0000a008, 0x00050004},
@@ -945,153 +520,14 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
        {0x0000a0d4, 0x22012202},
        {0x0000a0d8, 0x221f2200},
        {0x0000a0dc, 0x221d221e},
-       {0x0000a0e0, 0x33013302},
-       {0x0000a0e4, 0x331f3300},
-       {0x0000a0e8, 0x4402331e},
-       {0x0000a0ec, 0x44004401},
-       {0x0000a0f0, 0x441e441f},
-       {0x0000a0f4, 0x55015502},
-       {0x0000a0f8, 0x551f5500},
-       {0x0000a0fc, 0x6602551e},
-       {0x0000a100, 0x66006601},
-       {0x0000a104, 0x661e661f},
-       {0x0000a108, 0x7703661d},
-       {0x0000a10c, 0x77017702},
-       {0x0000a110, 0x00007700},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x111f1100},
-       {0x0000a148, 0x111d111e},
-       {0x0000a14c, 0x111b111c},
-       {0x0000a150, 0x22032204},
-       {0x0000a154, 0x22012202},
-       {0x0000a158, 0x221f2200},
-       {0x0000a15c, 0x221d221e},
-       {0x0000a160, 0x33013302},
-       {0x0000a164, 0x331f3300},
-       {0x0000a168, 0x4402331e},
-       {0x0000a16c, 0x44004401},
-       {0x0000a170, 0x441e441f},
-       {0x0000a174, 0x55015502},
-       {0x0000a178, 0x551f5500},
-       {0x0000a17c, 0x6602551e},
-       {0x0000a180, 0x66006601},
-       {0x0000a184, 0x661e661f},
-       {0x0000a188, 0x7703661d},
-       {0x0000a18c, 0x77017702},
-       {0x0000a190, 0x00007700},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000296},
-};
-
-static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = {
-       /* Addr        allmodes */
-       {0x00018c00, 0x18053e5e},
-       {0x00018c04, 0x000801d8},
-       {0x00018c08, 0x0000080c},
-};
-
-static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
-       /* Addr        allmodes */
-       {0x0000a000, 0x00060005},
-       {0x0000a004, 0x00810080},
-       {0x0000a008, 0x00830082},
-       {0x0000a00c, 0x00850084},
-       {0x0000a010, 0x01820181},
-       {0x0000a014, 0x01840183},
-       {0x0000a018, 0x01880185},
-       {0x0000a01c, 0x018a0189},
-       {0x0000a020, 0x02850284},
-       {0x0000a024, 0x02890288},
-       {0x0000a028, 0x028b028a},
-       {0x0000a02c, 0x03850384},
-       {0x0000a030, 0x03890388},
-       {0x0000a034, 0x038b038a},
-       {0x0000a038, 0x038d038c},
-       {0x0000a03c, 0x03910390},
-       {0x0000a040, 0x03930392},
-       {0x0000a044, 0x03950394},
-       {0x0000a048, 0x00000396},
-       {0x0000a04c, 0x00000000},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x28282828},
-       {0x0000a088, 0x28282828},
-       {0x0000a08c, 0x28282828},
-       {0x0000a090, 0x28282828},
-       {0x0000a094, 0x24242428},
-       {0x0000a098, 0x171e1e1e},
-       {0x0000a09c, 0x02020b0b},
-       {0x0000a0a0, 0x02020202},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x22072208},
-       {0x0000a0c4, 0x22052206},
-       {0x0000a0c8, 0x22032204},
-       {0x0000a0cc, 0x22012202},
-       {0x0000a0d0, 0x221f2200},
-       {0x0000a0d4, 0x221d221e},
-       {0x0000a0d8, 0x33023303},
-       {0x0000a0dc, 0x33003301},
-       {0x0000a0e0, 0x331e331f},
-       {0x0000a0e4, 0x4402331d},
-       {0x0000a0e8, 0x44004401},
-       {0x0000a0ec, 0x441e441f},
-       {0x0000a0f0, 0x55025503},
-       {0x0000a0f4, 0x55005501},
-       {0x0000a0f8, 0x551e551f},
-       {0x0000a0fc, 0x6602551d},
+       {0x0000a0e0, 0x33013302},
+       {0x0000a0e4, 0x331f3300},
+       {0x0000a0e8, 0x4402331e},
+       {0x0000a0ec, 0x44004401},
+       {0x0000a0f0, 0x441e441f},
+       {0x0000a0f4, 0x55015502},
+       {0x0000a0f8, 0x551f5500},
+       {0x0000a0fc, 0x6602551e},
        {0x0000a100, 0x66006601},
        {0x0000a104, 0x661e661f},
        {0x0000a108, 0x7703661d},
@@ -1158,4 +594,260 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
        {0x0000a1fc, 0x00000296},
 };
 
-#endif
+static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x18052e5e},
+       {0x00018c04, 0x000801d8},
+       {0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x18053e5e},
+       {0x00018c04, 0x000801d8},
+       {0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_1_1_soc_preamble[][2] = {
+       /* Addr      allmodes  */
+       {0x00004014, 0xba280400},
+       {0x00004090, 0x00aa10aa},
+       {0x000040a4, 0x00a0c9c9},
+       {0x00007010, 0x00000022},
+       {0x00007020, 0x00000000},
+       {0x00007034, 0x00000002},
+       {0x00007038, 0x000004c2},
+       {0x00007048, 0x00000002},
+};
+
+static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = {
+       /* Addr      5G_HT20     5G_HT40   */
+       {0x00009e00, 0x03721821, 0x03721821},
+       {0x0000a230, 0x0000400b, 0x00004016},
+       {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9485_1_1_baseband_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
+       {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
+       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+       {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
+       {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
+       {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+       {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+       {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
+       {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+       {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
+       {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
+       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+       {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
+       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+       {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
+       {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
+       {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+       {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
+       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+       {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
+       {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+       {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
+       /* Addr      allmodes  */
+       {0x00018c00, 0x18013e5e},
+       {0x00018c04, 0x000801d8},
+       {0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_1_1_radio_postamble[][2] = {
+       /* Addr      allmodes  */
+       {0x0001609c, 0x0b283f31},
+       {0x000160ac, 0x24611800},
+       {0x000160b0, 0x03284f3e},
+       {0x0001610c, 0x00170000},
+       {0x00016140, 0x50804008},
+};
+
+static const u32 ar9485_1_1_mac_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00000008, 0x00000000},
+       {0x00000030, 0x00020085},
+       {0x00000034, 0x00000005},
+       {0x00000040, 0x00000000},
+       {0x00000044, 0x00000000},
+       {0x00000048, 0x00000008},
+       {0x0000004c, 0x00000010},
+       {0x00000050, 0x00000000},
+       {0x00001040, 0x002ffc0f},
+       {0x00001044, 0x002ffc0f},
+       {0x00001048, 0x002ffc0f},
+       {0x0000104c, 0x002ffc0f},
+       {0x00001050, 0x002ffc0f},
+       {0x00001054, 0x002ffc0f},
+       {0x00001058, 0x002ffc0f},
+       {0x0000105c, 0x002ffc0f},
+       {0x00001060, 0x002ffc0f},
+       {0x00001064, 0x002ffc0f},
+       {0x000010f0, 0x00000100},
+       {0x00001270, 0x00000000},
+       {0x000012b0, 0x00000000},
+       {0x000012f0, 0x00000000},
+       {0x0000143c, 0x00000000},
+       {0x0000147c, 0x00000000},
+       {0x00008000, 0x00000000},
+       {0x00008004, 0x00000000},
+       {0x00008008, 0x00000000},
+       {0x0000800c, 0x00000000},
+       {0x00008018, 0x00000000},
+       {0x00008020, 0x00000000},
+       {0x00008038, 0x00000000},
+       {0x0000803c, 0x00000000},
+       {0x00008040, 0x00000000},
+       {0x00008044, 0x00000000},
+       {0x00008048, 0x00000000},
+       {0x0000804c, 0xffffffff},
+       {0x00008054, 0x00000000},
+       {0x00008058, 0x00000000},
+       {0x0000805c, 0x000fc78f},
+       {0x00008060, 0x0000000f},
+       {0x00008064, 0x00000000},
+       {0x00008070, 0x00000310},
+       {0x00008074, 0x00000020},
+       {0x00008078, 0x00000000},
+       {0x0000809c, 0x0000000f},
+       {0x000080a0, 0x00000000},
+       {0x000080a4, 0x02ff0000},
+       {0x000080a8, 0x0e070605},
+       {0x000080ac, 0x0000000d},
+       {0x000080b0, 0x00000000},
+       {0x000080b4, 0x00000000},
+       {0x000080b8, 0x00000000},
+       {0x000080bc, 0x00000000},
+       {0x000080c0, 0x2a800000},
+       {0x000080c4, 0x06900168},
+       {0x000080c8, 0x13881c22},
+       {0x000080cc, 0x01f40000},
+       {0x000080d0, 0x00252500},
+       {0x000080d4, 0x00a00000},
+       {0x000080d8, 0x00400000},
+       {0x000080dc, 0x00000000},
+       {0x000080e0, 0xffffffff},
+       {0x000080e4, 0x0000ffff},
+       {0x000080e8, 0x3f3f3f3f},
+       {0x000080ec, 0x00000000},
+       {0x000080f0, 0x00000000},
+       {0x000080f4, 0x00000000},
+       {0x000080fc, 0x00020000},
+       {0x00008100, 0x00000000},
+       {0x00008108, 0x00000052},
+       {0x0000810c, 0x00000000},
+       {0x00008110, 0x00000000},
+       {0x00008114, 0x000007ff},
+       {0x00008118, 0x000000aa},
+       {0x0000811c, 0x00003210},
+       {0x00008124, 0x00000000},
+       {0x00008128, 0x00000000},
+       {0x0000812c, 0x00000000},
+       {0x00008130, 0x00000000},
+       {0x00008134, 0x00000000},
+       {0x00008138, 0x00000000},
+       {0x0000813c, 0x0000ffff},
+       {0x00008144, 0xffffffff},
+       {0x00008168, 0x00000000},
+       {0x0000816c, 0x00000000},
+       {0x00008170, 0x18486200},
+       {0x00008174, 0x33332210},
+       {0x00008178, 0x00000000},
+       {0x0000817c, 0x00020000},
+       {0x000081c0, 0x00000000},
+       {0x000081c4, 0x33332210},
+       {0x000081d4, 0x00000000},
+       {0x000081ec, 0x00000000},
+       {0x000081f0, 0x00000000},
+       {0x000081f4, 0x00000000},
+       {0x000081f8, 0x00000000},
+       {0x000081fc, 0x00000000},
+       {0x00008240, 0x00100000},
+       {0x00008244, 0x0010f400},
+       {0x00008248, 0x00000800},
+       {0x0000824c, 0x0001e800},
+       {0x00008250, 0x00000000},
+       {0x00008254, 0x00000000},
+       {0x00008258, 0x00000000},
+       {0x0000825c, 0x40000000},
+       {0x00008260, 0x00080922},
+       {0x00008264, 0x9ca00010},
+       {0x00008268, 0xffffffff},
+       {0x0000826c, 0x0000ffff},
+       {0x00008270, 0x00000000},
+       {0x00008274, 0x40000000},
+       {0x00008278, 0x003e4180},
+       {0x0000827c, 0x00000004},
+       {0x00008284, 0x0000002c},
+       {0x00008288, 0x0000002c},
+       {0x0000828c, 0x000000ff},
+       {0x00008294, 0x00000000},
+       {0x00008298, 0x00000000},
+       {0x0000829c, 0x00000000},
+       {0x00008300, 0x00000140},
+       {0x00008314, 0x00000000},
+       {0x0000831c, 0x0000010d},
+       {0x00008328, 0x00000000},
+       {0x0000832c, 0x00000007},
+       {0x00008330, 0x00000302},
+       {0x00008334, 0x00000700},
+       {0x00008338, 0x00ff0000},
+       {0x0000833c, 0x02400000},
+       {0x00008340, 0x000107ff},
+       {0x00008344, 0xa248105b},
+       {0x00008348, 0x008f0000},
+       {0x0000835c, 0x00000000},
+       {0x00008360, 0xffffffff},
+       {0x00008364, 0xffffffff},
+       {0x00008368, 0x00000000},
+       {0x00008370, 0x00000000},
+       {0x00008374, 0x000000ff},
+       {0x00008378, 0x00000000},
+       {0x0000837c, 0x00000000},
+       {0x00008380, 0xffffffff},
+       {0x00008384, 0xffffffff},
+       {0x00008390, 0xffffffff},
+       {0x00008394, 0xffffffff},
+       {0x00008398, 0x00000000},
+       {0x0000839c, 0x00000000},
+       {0x000083a0, 0x00000000},
+       {0x000083a4, 0x0000fa14},
+       {0x000083a8, 0x000f0c00},
+       {0x000083ac, 0x33332210},
+       {0x000083b0, 0x33332210},
+       {0x000083b4, 0x33332210},
+       {0x000083b8, 0x33332210},
+       {0x000083bc, 0x00000000},
+       {0x000083c0, 0x00000000},
+       {0x000083c4, 0x00000000},
+       {0x000083c8, 0x00000000},
+       {0x000083cc, 0x00000200},
+       {0x000083d0, 0x000301ff},
+};
+
+#endif /* INITVALS_9485_H */
index 06b3f0df9fad50f707c79fc8f71ec90f6a493129..6e1915aee712c5978d2d581311366e82b0d24d70 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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
 
 /* AR9580 1.0 */
 
-static const u32 ar9580_1p0_modes_fast_clock[][3] = {
-       /* Addr      5G_HT20     5G_HT40   */
-       {0x00001030, 0x00000268, 0x000004d0},
-       {0x00001070, 0x0000018c, 0x00000318},
-       {0x000010b0, 0x00000fd0, 0x00001fa0},
-       {0x00008014, 0x044c044c, 0x08980898},
-       {0x0000801c, 0x148ec02b, 0x148ec057},
-       {0x00008318, 0x000044c0, 0x00008980},
-       {0x00009e00, 0x0372131c, 0x0372131c},
-       {0x0000a230, 0x0000000b, 0x00000016},
-       {0x0000a254, 0x00000898, 0x00001130},
-};
+#define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2
 
 static const u32 ar9580_1p0_radio_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
@@ -208,17 +198,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = {
        {0x0000c420, 0x00000000},
 };
 
-static const u32 ar9580_1p0_mac_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
-       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
-       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
-       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
-       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
-       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
-       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
-       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
-};
+#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
 
 static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
@@ -326,111 +306,7 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
-       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
-       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
-       {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
-       {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
-       {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
-       {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
-       {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
-       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
-       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
-       {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
-       {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
-       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
-       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
-       {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
-       {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
-       {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
-       {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
-       {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
-       {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
-       {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
-       {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
-       {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
-       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
-       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
-       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
-       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
-       {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
-       {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
-       {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
-       {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
-       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
-       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
-       {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
-       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
-       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
-       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
-       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
-       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
-       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
-       {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
-       {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
-       {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
-       {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
-       {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
-       {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
-       {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
-       {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
-       {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
-       {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
-       {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
-       {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
-       {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
-       {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
-       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
-       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
-       {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
-       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-};
+#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table
 
 static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
@@ -538,12 +414,7 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9580_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a398, 0x00000000},
-       {0x0000a39c, 0x6f7f0301},
-       {0x0000a3a0, 0xca9228ee},
-};
+#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
 
 static const u32 ar9580_1p0_mac_core[][2] = {
        /* Addr      allmodes  */
@@ -808,376 +679,11 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = {
        {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
 };
 
-static const u32 ar9580_1p0_wo_xlna_rx_gain_table[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x03820190},
-       {0x0000a030, 0x03840383},
-       {0x0000a034, 0x03880385},
-       {0x0000a038, 0x038a0389},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x29292929},
-       {0x0000a084, 0x29292929},
-       {0x0000a088, 0x29292929},
-       {0x0000a08c, 0x29292929},
-       {0x0000a090, 0x22292929},
-       {0x0000a094, 0x1d1d2222},
-       {0x0000a098, 0x0c111117},
-       {0x0000a09c, 0x00030303},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x32323232},
-       {0x0000b084, 0x2f2f3232},
-       {0x0000b088, 0x23282a2d},
-       {0x0000b08c, 0x1c1e2123},
-       {0x0000b090, 0x14171919},
-       {0x0000b094, 0x0e0e1214},
-       {0x0000b098, 0x03050707},
-       {0x0000b09c, 0x00030303},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
+#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
 
-static const u32 ar9580_1p0_soc_postamble[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
-};
+#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
 
-static const u32 ar9580_1p0_high_ob_db_tx_gain_table[][5] = {
-       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
-       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
-       {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
-       {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
-       {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
-       {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
-       {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
-       {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
-       {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
-       {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
-       {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
-       {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
-       {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
-       {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
-       {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
-       {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
-       {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
-       {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
-       {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
-       {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
-       {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
-       {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
-       {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
-       {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
-       {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
-       {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
-       {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
-       {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
-       {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
-       {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
-       {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
-       {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
-       {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
-       {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
-       {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
-       {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
-       {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
-       {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
-       {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
-       {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
-       {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
-       {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
-       {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
-       {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
-       {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
-       {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
-       {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
-       {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
-       {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
-       {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
-       {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
-       {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
-       {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
-       {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
-       {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
-       {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
-       {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
-       {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
-       {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
-       {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
-       {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
-       {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
-       {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
-       {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
-       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-       {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
-       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-       {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
-       {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
-       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
-};
+#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2
 
 static const u32 ar9580_1p0_soc_preamble[][2] = {
        /* Addr      allmodes  */
@@ -1189,265 +695,7 @@ static const u32 ar9580_1p0_soc_preamble[][2] = {
        {0x00007048, 0x00000008},
 };
 
-static const u32 ar9580_1p0_rx_gain_table[][2] = {
-       /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x00830082},
-       {0x0000a014, 0x01810180},
-       {0x0000a018, 0x01830182},
-       {0x0000a01c, 0x01850184},
-       {0x0000a020, 0x01890188},
-       {0x0000a024, 0x018b018a},
-       {0x0000a028, 0x018d018c},
-       {0x0000a02c, 0x01910190},
-       {0x0000a030, 0x01930192},
-       {0x0000a034, 0x01950194},
-       {0x0000a038, 0x038a0196},
-       {0x0000a03c, 0x038c038b},
-       {0x0000a040, 0x0390038d},
-       {0x0000a044, 0x03920391},
-       {0x0000a048, 0x03940393},
-       {0x0000a04c, 0x03960395},
-       {0x0000a050, 0x00000000},
-       {0x0000a054, 0x00000000},
-       {0x0000a058, 0x00000000},
-       {0x0000a05c, 0x00000000},
-       {0x0000a060, 0x00000000},
-       {0x0000a064, 0x00000000},
-       {0x0000a068, 0x00000000},
-       {0x0000a06c, 0x00000000},
-       {0x0000a070, 0x00000000},
-       {0x0000a074, 0x00000000},
-       {0x0000a078, 0x00000000},
-       {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x22222229},
-       {0x0000a084, 0x1d1d1d1d},
-       {0x0000a088, 0x1d1d1d1d},
-       {0x0000a08c, 0x1d1d1d1d},
-       {0x0000a090, 0x171d1d1d},
-       {0x0000a094, 0x11111717},
-       {0x0000a098, 0x00030311},
-       {0x0000a09c, 0x00000000},
-       {0x0000a0a0, 0x00000000},
-       {0x0000a0a4, 0x00000000},
-       {0x0000a0a8, 0x00000000},
-       {0x0000a0ac, 0x00000000},
-       {0x0000a0b0, 0x00000000},
-       {0x0000a0b4, 0x00000000},
-       {0x0000a0b8, 0x00000000},
-       {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x01000101},
-       {0x0000a0c8, 0x011e011f},
-       {0x0000a0cc, 0x011c011d},
-       {0x0000a0d0, 0x02030204},
-       {0x0000a0d4, 0x02010202},
-       {0x0000a0d8, 0x021f0200},
-       {0x0000a0dc, 0x0302021e},
-       {0x0000a0e0, 0x03000301},
-       {0x0000a0e4, 0x031e031f},
-       {0x0000a0e8, 0x0402031d},
-       {0x0000a0ec, 0x04000401},
-       {0x0000a0f0, 0x041e041f},
-       {0x0000a0f4, 0x0502041d},
-       {0x0000a0f8, 0x05000501},
-       {0x0000a0fc, 0x051e051f},
-       {0x0000a100, 0x06010602},
-       {0x0000a104, 0x061f0600},
-       {0x0000a108, 0x061d061e},
-       {0x0000a10c, 0x07020703},
-       {0x0000a110, 0x07000701},
-       {0x0000a114, 0x00000000},
-       {0x0000a118, 0x00000000},
-       {0x0000a11c, 0x00000000},
-       {0x0000a120, 0x00000000},
-       {0x0000a124, 0x00000000},
-       {0x0000a128, 0x00000000},
-       {0x0000a12c, 0x00000000},
-       {0x0000a130, 0x00000000},
-       {0x0000a134, 0x00000000},
-       {0x0000a138, 0x00000000},
-       {0x0000a13c, 0x00000000},
-       {0x0000a140, 0x001f0000},
-       {0x0000a144, 0x01000101},
-       {0x0000a148, 0x011e011f},
-       {0x0000a14c, 0x011c011d},
-       {0x0000a150, 0x02030204},
-       {0x0000a154, 0x02010202},
-       {0x0000a158, 0x021f0200},
-       {0x0000a15c, 0x0302021e},
-       {0x0000a160, 0x03000301},
-       {0x0000a164, 0x031e031f},
-       {0x0000a168, 0x0402031d},
-       {0x0000a16c, 0x04000401},
-       {0x0000a170, 0x041e041f},
-       {0x0000a174, 0x0502041d},
-       {0x0000a178, 0x05000501},
-       {0x0000a17c, 0x051e051f},
-       {0x0000a180, 0x06010602},
-       {0x0000a184, 0x061f0600},
-       {0x0000a188, 0x061d061e},
-       {0x0000a18c, 0x07020703},
-       {0x0000a190, 0x07000701},
-       {0x0000a194, 0x00000000},
-       {0x0000a198, 0x00000000},
-       {0x0000a19c, 0x00000000},
-       {0x0000a1a0, 0x00000000},
-       {0x0000a1a4, 0x00000000},
-       {0x0000a1a8, 0x00000000},
-       {0x0000a1ac, 0x00000000},
-       {0x0000a1b0, 0x00000000},
-       {0x0000a1b4, 0x00000000},
-       {0x0000a1b8, 0x00000000},
-       {0x0000a1bc, 0x00000000},
-       {0x0000a1c0, 0x00000000},
-       {0x0000a1c4, 0x00000000},
-       {0x0000a1c8, 0x00000000},
-       {0x0000a1cc, 0x00000000},
-       {0x0000a1d0, 0x00000000},
-       {0x0000a1d4, 0x00000000},
-       {0x0000a1d8, 0x00000000},
-       {0x0000a1dc, 0x00000000},
-       {0x0000a1e0, 0x00000000},
-       {0x0000a1e4, 0x00000000},
-       {0x0000a1e8, 0x00000000},
-       {0x0000a1ec, 0x00000000},
-       {0x0000a1f0, 0x00000396},
-       {0x0000a1f4, 0x00000396},
-       {0x0000a1f8, 0x00000396},
-       {0x0000a1fc, 0x00000196},
-       {0x0000b000, 0x00010000},
-       {0x0000b004, 0x00030002},
-       {0x0000b008, 0x00050004},
-       {0x0000b00c, 0x00810080},
-       {0x0000b010, 0x00830082},
-       {0x0000b014, 0x01810180},
-       {0x0000b018, 0x01830182},
-       {0x0000b01c, 0x01850184},
-       {0x0000b020, 0x02810280},
-       {0x0000b024, 0x02830282},
-       {0x0000b028, 0x02850284},
-       {0x0000b02c, 0x02890288},
-       {0x0000b030, 0x028b028a},
-       {0x0000b034, 0x0388028c},
-       {0x0000b038, 0x038a0389},
-       {0x0000b03c, 0x038c038b},
-       {0x0000b040, 0x0390038d},
-       {0x0000b044, 0x03920391},
-       {0x0000b048, 0x03940393},
-       {0x0000b04c, 0x03960395},
-       {0x0000b050, 0x00000000},
-       {0x0000b054, 0x00000000},
-       {0x0000b058, 0x00000000},
-       {0x0000b05c, 0x00000000},
-       {0x0000b060, 0x00000000},
-       {0x0000b064, 0x00000000},
-       {0x0000b068, 0x00000000},
-       {0x0000b06c, 0x00000000},
-       {0x0000b070, 0x00000000},
-       {0x0000b074, 0x00000000},
-       {0x0000b078, 0x00000000},
-       {0x0000b07c, 0x00000000},
-       {0x0000b080, 0x2a2d2f32},
-       {0x0000b084, 0x21232328},
-       {0x0000b088, 0x19191c1e},
-       {0x0000b08c, 0x12141417},
-       {0x0000b090, 0x07070e0e},
-       {0x0000b094, 0x03030305},
-       {0x0000b098, 0x00000003},
-       {0x0000b09c, 0x00000000},
-       {0x0000b0a0, 0x00000000},
-       {0x0000b0a4, 0x00000000},
-       {0x0000b0a8, 0x00000000},
-       {0x0000b0ac, 0x00000000},
-       {0x0000b0b0, 0x00000000},
-       {0x0000b0b4, 0x00000000},
-       {0x0000b0b8, 0x00000000},
-       {0x0000b0bc, 0x00000000},
-       {0x0000b0c0, 0x003f0020},
-       {0x0000b0c4, 0x00400041},
-       {0x0000b0c8, 0x0140005f},
-       {0x0000b0cc, 0x0160015f},
-       {0x0000b0d0, 0x017e017f},
-       {0x0000b0d4, 0x02410242},
-       {0x0000b0d8, 0x025f0240},
-       {0x0000b0dc, 0x027f0260},
-       {0x0000b0e0, 0x0341027e},
-       {0x0000b0e4, 0x035f0340},
-       {0x0000b0e8, 0x037f0360},
-       {0x0000b0ec, 0x04400441},
-       {0x0000b0f0, 0x0460045f},
-       {0x0000b0f4, 0x0541047f},
-       {0x0000b0f8, 0x055f0540},
-       {0x0000b0fc, 0x057f0560},
-       {0x0000b100, 0x06400641},
-       {0x0000b104, 0x0660065f},
-       {0x0000b108, 0x067e067f},
-       {0x0000b10c, 0x07410742},
-       {0x0000b110, 0x075f0740},
-       {0x0000b114, 0x077f0760},
-       {0x0000b118, 0x07800781},
-       {0x0000b11c, 0x07a0079f},
-       {0x0000b120, 0x07c107bf},
-       {0x0000b124, 0x000007c0},
-       {0x0000b128, 0x00000000},
-       {0x0000b12c, 0x00000000},
-       {0x0000b130, 0x00000000},
-       {0x0000b134, 0x00000000},
-       {0x0000b138, 0x00000000},
-       {0x0000b13c, 0x00000000},
-       {0x0000b140, 0x003f0020},
-       {0x0000b144, 0x00400041},
-       {0x0000b148, 0x0140005f},
-       {0x0000b14c, 0x0160015f},
-       {0x0000b150, 0x017e017f},
-       {0x0000b154, 0x02410242},
-       {0x0000b158, 0x025f0240},
-       {0x0000b15c, 0x027f0260},
-       {0x0000b160, 0x0341027e},
-       {0x0000b164, 0x035f0340},
-       {0x0000b168, 0x037f0360},
-       {0x0000b16c, 0x04400441},
-       {0x0000b170, 0x0460045f},
-       {0x0000b174, 0x0541047f},
-       {0x0000b178, 0x055f0540},
-       {0x0000b17c, 0x057f0560},
-       {0x0000b180, 0x06400641},
-       {0x0000b184, 0x0660065f},
-       {0x0000b188, 0x067e067f},
-       {0x0000b18c, 0x07410742},
-       {0x0000b190, 0x075f0740},
-       {0x0000b194, 0x077f0760},
-       {0x0000b198, 0x07800781},
-       {0x0000b19c, 0x07a0079f},
-       {0x0000b1a0, 0x07c107bf},
-       {0x0000b1a4, 0x000007c0},
-       {0x0000b1a8, 0x00000000},
-       {0x0000b1ac, 0x00000000},
-       {0x0000b1b0, 0x00000000},
-       {0x0000b1b4, 0x00000000},
-       {0x0000b1b8, 0x00000000},
-       {0x0000b1bc, 0x00000000},
-       {0x0000b1c0, 0x00000000},
-       {0x0000b1c4, 0x00000000},
-       {0x0000b1c8, 0x00000000},
-       {0x0000b1cc, 0x00000000},
-       {0x0000b1d0, 0x00000000},
-       {0x0000b1d4, 0x00000000},
-       {0x0000b1d8, 0x00000000},
-       {0x0000b1dc, 0x00000000},
-       {0x0000b1e0, 0x00000000},
-       {0x0000b1e4, 0x00000000},
-       {0x0000b1e8, 0x00000000},
-       {0x0000b1ec, 0x00000000},
-       {0x0000b1f0, 0x00000396},
-       {0x0000b1f4, 0x00000396},
-       {0x0000b1f8, 0x00000396},
-       {0x0000b1fc, 0x00000196},
-};
+#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0
 
 static const u32 ar9580_1p0_radio_core[][2] = {
        /* Addr      allmodes  */
index 4866550ddd965eb0370133bc21ad55b22e29b240..fe39eb4c42a1f37b6357b7550b1dffeed572dac9 100644 (file)
@@ -308,6 +308,7 @@ struct ath_rx {
        u8 defant;
        u8 rxotherant;
        u32 *rxlink;
+       u32 num_pkts;
        unsigned int rxfilter;
        spinlock_t rxbuflock;
        struct list_head rxbuf;
@@ -326,6 +327,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq);
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq);
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
 bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx);
 void ath_draintxq(struct ath_softc *sc,
@@ -415,9 +419,9 @@ int ath_beaconq_config(struct ath_softc *sc);
 void ath_set_beacon(struct ath_softc *sc);
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 
-/*******/
-/* ANI */
-/*******/
+/*******************/
+/* Link Monitoring */
+/*******************/
 
 #define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
 #define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
@@ -428,7 +432,9 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
 #define ATH_PAPRD_TIMEOUT      100 /* msecs */
+#define ATH_PLL_WORK_INTERVAL   100
 
+void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
 void ath_hw_check(struct work_struct *work);
 void ath_hw_pll_work(struct work_struct *work);
@@ -437,22 +443,31 @@ void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 void ath_start_ani(struct ath_common *common);
+int ath_update_survey_stats(struct ath_softc *sc);
+void ath_update_survey_nf(struct ath_softc *sc, int channel);
 
 /**********/
 /* BTCOEX */
 /**********/
 
+enum bt_op_flags {
+       BT_OP_PRIORITY_DETECTED,
+       BT_OP_SCAN,
+};
+
 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;
+       unsigned long op_flags;
        int bt_stomp_type; /* Types of BT stomping */
        u32 btcoex_no_stomp; /* in usec */
        u32 btcoex_period; /* in usec */
        u32 btscan_no_stomp; /* in usec */
        u32 duty_cycle;
+       u32 bt_wait_time;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
        struct ath_mci_profile mci;
 };
@@ -514,8 +529,10 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
 }
 #endif
 
-
+/*******************************/
 /* Antenna diversity/combining */
+/*******************************/
+
 #define ATH_ANT_RX_CURRENT_SHIFT 4
 #define ATH_ANT_RX_MAIN_SHIFT 2
 #define ATH_ANT_RX_MASK 0x3
@@ -568,6 +585,9 @@ struct ath_ant_comb {
        unsigned long scan_start_time;
 };
 
+void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
+void ath_ant_comb_update(struct ath_softc *sc);
+
 /********************/
 /* Main driver core */
 /********************/
@@ -585,15 +605,15 @@ struct ath_ant_comb {
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 #define ATH_RATE_DUMMY_MARKER   0
 
-#define SC_OP_INVALID                BIT(0)
-#define SC_OP_BEACONS                BIT(1)
-#define SC_OP_OFFCHANNEL             BIT(2)
-#define SC_OP_RXFLUSH                BIT(3)
-#define SC_OP_TSF_RESET              BIT(4)
-#define SC_OP_BT_PRIORITY_DETECTED   BIT(5)
-#define SC_OP_BT_SCAN                BIT(6)
-#define SC_OP_ANI_RUN                BIT(7)
-#define SC_OP_PRIM_STA_VIF           BIT(8)
+enum sc_op_flags {
+       SC_OP_INVALID,
+       SC_OP_BEACONS,
+       SC_OP_RXFLUSH,
+       SC_OP_TSF_RESET,
+       SC_OP_ANI_RUN,
+       SC_OP_PRIM_STA_VIF,
+       SC_OP_HW_RESET,
+};
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -639,9 +659,9 @@ struct ath_softc {
        struct completion paprd_complete;
 
        unsigned int hw_busy_count;
+       unsigned long sc_flags;
 
        u32 intrstatus;
-       u32 sc_flags; /* SC_OP_* */
        u16 ps_flags; /* PS_* */
        u16 curtxpow;
        bool ps_enabled;
@@ -679,6 +699,7 @@ struct ath_softc {
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
        struct ath_mci_coex mci_coex;
+       struct work_struct mci_work;
 #endif
 
        struct ath_descdma txsdma;
@@ -701,6 +722,7 @@ extern int ath9k_modparam_nohwcrypt;
 extern int led_blink;
 extern bool is_ath9k_unloaded;
 
+u8 ath9k_parse_mpdudensity(u8 mpdudensity);
 irqreturn_t ath_isr(int irq, void *dev);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
                    const struct ath_bus_ops *bus_ops);
@@ -737,5 +759,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               struct ath9k_vif_iter_data *iter_data);
 
-
 #endif /* ATH9K_H */
index 11bc55e3d69759088e34433ce19c74ee9ef9e5b1..40775da8941ef4eeb73596ba5f7add44d2c2c817 100644 (file)
@@ -48,7 +48,10 @@ int ath_beaconq_config(struct ath_softc *sc)
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
                qi.tqi_aifs = qi_be.tqi_aifs;
-               qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+               if (ah->slottime == ATH9K_SLOT_TIME_20)
+                       qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+               else
+                       qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
                qi.tqi_cwmax = qi_be.tqi_cwmax;
        }
 
@@ -387,7 +390,7 @@ void ath_beacon_tasklet(unsigned long data)
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
                        ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
                        sc->beacon.bmisscnt = 0;
-                       sc->sc_flags |= SC_OP_TSF_RESET;
+                       set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
                }
 
@@ -477,16 +480,16 @@ static void ath9k_beacon_init(struct ath_softc *sc,
                              u32 next_beacon,
                              u32 beacon_period)
 {
-       if (sc->sc_flags & SC_OP_TSF_RESET) {
+       if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
                ath9k_ps_wakeup(sc);
                ath9k_hw_reset_tsf(sc->sc_ah);
        }
 
        ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
 
-       if (sc->sc_flags & SC_OP_TSF_RESET) {
+       if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
                ath9k_ps_restore(sc);
-               sc->sc_flags &= ~SC_OP_TSF_RESET;
+               clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
        }
 }
 
@@ -516,7 +519,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
        /* Set the computed AP beacon timers */
 
        ath9k_hw_disable_interrupts(ah);
-       sc->sc_flags |= SC_OP_TSF_RESET;
+       set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
        ath9k_hw_set_interrupts(ah);
@@ -659,7 +662,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        u32 tsf, intval, nexttbtt;
 
        ath9k_reset_beacon_status(sc);
-       if (!(sc->sc_flags & SC_OP_BEACONS))
+       if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
                ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
 
        intval = TU_TO_USEC(conf->beacon_interval);
@@ -724,7 +727,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc,
         */
        if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
            (vif->type == NL80211_IFTYPE_STATION) &&
-           (sc->sc_flags & SC_OP_BEACONS) &&
+           test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
            !avp->primary_sta_vif) {
                ath_dbg(common, CONFIG,
                        "Beacon already configured for a station interface\n");
@@ -810,7 +813,7 @@ void ath_set_beacon(struct ath_softc *sc)
                return;
        }
 
-       sc->sc_flags |= SC_OP_BEACONS;
+       set_bit(SC_OP_BEACONS, &sc->sc_flags);
 }
 
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
@@ -818,7 +821,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
        struct ath_hw *ah = sc->sc_ah;
 
        if (!ath_has_valid_bslot(sc)) {
-               sc->sc_flags &= ~SC_OP_BEACONS;
+               clear_bit(SC_OP_BEACONS, &sc->sc_flags);
                return;
        }
 
index 1ca6da80d4ad3f16c1ac152b31d1b8724e598052..acd437384fe47840852aeb3f967524ac52265975 100644 (file)
@@ -336,10 +336,16 @@ static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
                         enum ath_stomp_type stomp_type)
 {
        struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
-       const u32 *weight = AR_SREV_9462(ah) ? ar9003_wlan_weights[stomp_type] :
-                                              ar9462_wlan_weights[stomp_type];
+       const u32 *weight = ar9003_wlan_weights[stomp_type];
        int i;
 
+       if (AR_SREV_9462(ah)) {
+               if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
+                   btcoex->mci.stomp_ftp)
+                       stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
+               weight = ar9462_wlan_weights[stomp_type];
+       }
+
        for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
                btcoex->bt_weight[i] = AR9300_BT_WGHT;
                btcoex->wlan_weight[i] = weight[i];
index 3a1e1cfabd5e28f15345f89b1f428c1a35c63841..20092f98658f84b3f0ad2429543f168de2d2866b 100644 (file)
@@ -36,6 +36,9 @@
 #define ATH_BT_CNT_THRESHOLD          3
 #define ATH_BT_CNT_SCAN_THRESHOLD      15
 
+#define ATH_BTCOEX_RX_WAIT_TIME       100
+#define ATH_BTCOEX_STOMP_FTP_THRESH   5
+
 #define AR9300_NUM_BT_WEIGHTS   4
 #define AR9300_NUM_WLAN_WEIGHTS 4
 /* Defines the BT AR_BT_COEX_WGHT used */
@@ -80,6 +83,7 @@ struct ath9k_hw_mci {
        u8 bt_ver_major;
        u8 bt_ver_minor;
        u8 bt_state;
+       u8 stomp_ftp;
 };
 
 struct ath_btcoex_hw {
index fde700c4e49092d760e537ba6dda6409b609fa63..5c3192ffc196d9a75315131f10559ff16914559a 100644 (file)
@@ -205,10 +205,10 @@ static ssize_t write_file_disable_ani(struct file *file,
        common->disable_ani = !!disable_ani;
 
        if (disable_ani) {
-               sc->sc_flags &= ~SC_OP_ANI_RUN;
+               clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                del_timer_sync(&common->ani.timer);
        } else {
-               sc->sc_flags |= SC_OP_ANI_RUN;
+               set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                ath_start_ani(common);
        }
 
@@ -348,8 +348,6 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
                sc->debug.stats.istats.txok++;
        if (status & ATH9K_INT_TXURN)
                sc->debug.stats.istats.txurn++;
-       if (status & ATH9K_INT_MIB)
-               sc->debug.stats.istats.mib++;
        if (status & ATH9K_INT_RXPHY)
                sc->debug.stats.istats.rxphyerr++;
        if (status & ATH9K_INT_RXKCM)
@@ -374,6 +372,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
                sc->debug.stats.istats.dtim++;
        if (status & ATH9K_INT_TSFOOR)
                sc->debug.stats.istats.tsfoor++;
+       if (status & ATH9K_INT_MCI)
+               sc->debug.stats.istats.mci++;
 }
 
 static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -418,6 +418,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
        PR_IS("DTIMSYNC", dtimsync);
        PR_IS("DTIM", dtim);
        PR_IS("TSFOOR", tsfoor);
+       PR_IS("MCI", mci);
        PR_IS("TOTAL", total);
 
        len += snprintf(buf + len, mxlen - len,
@@ -1318,7 +1319,7 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
        u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
        u8 nread;
 
-       if (sc->sc_flags & SC_OP_INVALID)
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EAGAIN;
 
        buf = vmalloc(size);
index c34da09d91032518b7ad49fea2e41f31b2bc9152..d0f851cea43ab83fa8ccce8f8d8c9e9def080bca 100644 (file)
@@ -86,6 +86,7 @@ struct ath_interrupt_stats {
        u32 dtim;
        u32 bb_watchdog;
        u32 tsfoor;
+       u32 mci;
 
        /* Sync-cause stats */
        u32 sync_cause_all;
index 4322ac80c203c1dfc6762f7f8547c73fbf3af7b3..a850f44fa76714e0f506907ac897c48777ab9069 100644 (file)
@@ -135,7 +135,7 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        if (!dump_base_hdr) {
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "2GHz modal Header");
-               len += ath9k_dump_4k_modal_eeprom(buf, len, size,
+               len = ath9k_dump_4k_modal_eeprom(buf, len, size,
                                                  &eep->modalHeader);
                goto out;
        }
index aa614767adffc8b342a4b37cb5265cbb15c3fad3..cd742fb944c274528ee5cfce31625ba329f42b55 100644 (file)
@@ -132,7 +132,7 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        if (!dump_base_hdr) {
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "2GHz modal Header");
-               len += ar9287_dump_modal_eeprom(buf, len, size,
+               len = ar9287_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader);
                goto out;
        }
index b5fba8b18b8b851fbe985820c9d8021729171290..56290f3185208e0e6863f3ee70bb622dd5e04e0b 100644 (file)
@@ -211,11 +211,11 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        if (!dump_base_hdr) {
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "2GHz modal Header");
-               len += ath9k_def_dump_modal_eeprom(buf, len, size,
+               len = ath9k_def_dump_modal_eeprom(buf, len, size,
                                                   &eep->modalHeader[0]);
                len += snprintf(buf + len, size - len,
                                "%20s :\n", "5GHz modal Header");
-               len += ath9k_def_dump_modal_eeprom(buf, len, size,
+               len = ath9k_def_dump_modal_eeprom(buf, len, size,
                                                   &eep->modalHeader[1]);
                goto out;
        }
index 281a9af0f1b60b62ceaa3a449fa752854af2d5b9..9ae6a4d9769144f42722933846f3b5fa83ff3ebb 100644 (file)
@@ -132,17 +132,18 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
 
        if (time_after(jiffies, btcoex->bt_priority_time +
                        msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-               sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+               clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+               clear_bit(BT_OP_SCAN, &btcoex->op_flags);
                /* Detect if colocated bt started scanning */
                if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
                        ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
                                "BT scan detected\n");
-                       sc->sc_flags |= (SC_OP_BT_SCAN |
-                                        SC_OP_BT_PRIORITY_DETECTED);
+                       set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
+                       set_bit(BT_OP_SCAN, &btcoex->op_flags);
                } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
                        ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
                                "BT priority traffic detected\n");
-                       sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+                       set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
                }
 
                btcoex->bt_priority_cnt = 0;
@@ -190,13 +191,26 @@ 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;
+       struct ath_mci_profile *mci = &btcoex->mci;
        u32 timer_period;
        bool is_btscan;
 
        ath9k_ps_wakeup(sc);
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
                ath_detect_bt_priority(sc);
-       is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+       is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags);
+
+       btcoex->bt_wait_time += btcoex->btcoex_period;
+       if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
+               if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
+                   (mci->num_pan || mci->num_other_acl))
+                       ah->btcoex_hw.mci.stomp_ftp =
+                               (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
+               else
+                       ah->btcoex_hw.mci.stomp_ftp = false;
+               btcoex->bt_wait_time = 0;
+               sc->rx.num_pkts = 0;
+       }
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
@@ -218,9 +232,8 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
-       timer_period = btcoex->btcoex_period / 1000;
-       mod_timer(&btcoex->period_timer, jiffies +
-                                 msecs_to_jiffies(timer_period));
+       timer_period = btcoex->btcoex_period;
+       mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
 }
 
 /*
@@ -233,14 +246,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_common *common = ath9k_hw_common(ah);
-       bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        ath_dbg(common, BTCOEX, "no stomp timer running\n");
 
        ath9k_ps_wakeup(sc);
        spin_lock_bh(&btcoex->btcoex_lock);
 
-       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
+           test_bit(BT_OP_SCAN, &btcoex->op_flags))
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
@@ -254,10 +267,10 @@ 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 = ATH_BTCOEX_DEF_BT_PERIOD;
+       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
                btcoex->btcoex_period / 100;
-       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
                                   btcoex->btcoex_period / 100;
 
        setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
@@ -292,7 +305,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
 
        btcoex->bt_priority_cnt = 0;
        btcoex->bt_priority_time = jiffies;
-       sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+       btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN);
 
        mod_timer(&btcoex->period_timer, jiffies);
 }
@@ -316,12 +329,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc)
 
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
 {
+       struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_mci_profile *mci = &sc->btcoex.mci;
        u16 aggr_limit = 0;
 
        if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
                aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
-       else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+       else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags))
                aggr_limit = min((max_4ms_framelen * 3) / 8,
                                 (u32)ATH_AMPDU_LIMIT_MAX);
 
@@ -402,7 +416,7 @@ int ath9k_init_btcoex(struct ath_softc *sc)
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-               if (AR_SREV_9462(ah)) {
+               if (ath9k_hw_mci_is_enabled(ah)) {
                        sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
                        INIT_LIST_HEAD(&sc->btcoex.mci.info);
 
index 135795257d95ab2a13ef684598a4ca3d57912470..936e920fb88e7cc0dfc40766f27b0e7ab1fa7ab3 100644 (file)
@@ -453,7 +453,6 @@ struct ath9k_htc_priv {
        u8 num_sta_assoc_vif;
        u8 num_ap_vif;
 
-       u16 op_flags;
        u16 curtxpow;
        u16 txpowlimit;
        u16 nvifs;
@@ -461,6 +460,7 @@ struct ath9k_htc_priv {
        bool rearm_ani;
        bool reconfig_beacon;
        unsigned int rxfilter;
+       unsigned long op_flags;
 
        struct ath9k_hw_cal_data caldata;
        struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -572,8 +572,6 @@ bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
 
 void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
 void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
-void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
-void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
 
 #ifdef CONFIG_MAC80211_LEDS
 void ath9k_init_leds(struct ath9k_htc_priv *priv);
index 2eadffb7971cc82c935ab8db1530bb27944b0659..77d541feb9102a9af2e8aabfea180da57fc5d317 100644 (file)
@@ -207,9 +207,9 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
        else
                priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 
-       if (priv->op_flags & OP_TSF_RESET) {
+       if (test_bit(OP_TSF_RESET, &priv->op_flags)) {
                ath9k_hw_reset_tsf(priv->ah);
-               priv->op_flags &= ~OP_TSF_RESET;
+               clear_bit(OP_TSF_RESET, &priv->op_flags);
        } else {
                /*
                 * Pull nexttbtt forward to reflect the current TSF.
@@ -221,7 +221,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
                } while (nexttbtt < tsftu);
        }
 
-       if (priv->op_flags & OP_ENABLE_BEACON)
+       if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
                imask |= ATH9K_INT_SWBA;
 
        ath_dbg(common, CONFIG,
@@ -269,7 +269,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
        else
                priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
 
-       if (priv->op_flags & OP_ENABLE_BEACON)
+       if (test_bit(OP_ENABLE_BEACON, &priv->op_flags))
                imask |= ATH9K_INT_SWBA;
 
        ath_dbg(common, CONFIG,
@@ -365,7 +365,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
        vif = priv->cur_beacon_conf.bslot[slot];
        avp = (struct ath9k_htc_vif *)vif->drv_priv;
 
-       if (unlikely(priv->op_flags & OP_SCANNING)) {
+       if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) {
                spin_unlock_bh(&priv->beacon_lock);
                return;
        }
index 1c10e2e5c237d2a8233b8a09ae056b0a909f7bb2..07df279c8d467a0ee33bf4c44015a6b2d3f69dbf 100644 (file)
@@ -37,17 +37,18 @@ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
 
        if (time_after(jiffies, btcoex->bt_priority_time +
                        msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-               priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+               clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+               clear_bit(OP_BT_SCAN, &priv->op_flags);
                /* Detect if colocated bt started scanning */
                if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
                        ath_dbg(ath9k_hw_common(ah), BTCOEX,
                                "BT scan detected\n");
-                       priv->op_flags |= (OP_BT_SCAN |
-                                        OP_BT_PRIORITY_DETECTED);
+                       set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+                       set_bit(OP_BT_SCAN, &priv->op_flags);
                } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
                        ath_dbg(ath9k_hw_common(ah), BTCOEX,
                                "BT priority traffic detected\n");
-                       priv->op_flags |= OP_BT_PRIORITY_DETECTED;
+                       set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
                }
 
                btcoex->bt_priority_cnt = 0;
@@ -67,26 +68,23 @@ static void ath_btcoex_period_work(struct work_struct *work)
        struct ath_btcoex *btcoex = &priv->btcoex;
        struct ath_common *common = ath9k_hw_common(priv->ah);
        u32 timer_period;
-       bool is_btscan;
        int ret;
 
        ath_detect_bt_priority(priv);
 
-       is_btscan = !!(priv->op_flags & OP_BT_SCAN);
-
        ret = ath9k_htc_update_cap_target(priv,
-                                 !!(priv->op_flags & OP_BT_PRIORITY_DETECTED));
+                         test_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags));
        if (ret) {
                ath_err(common, "Unable to set BTCOEX parameters\n");
                return;
        }
 
-       ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
-                       btcoex->bt_stomp_type);
+       ath9k_hw_btcoex_bt_stomp(priv->ah, test_bit(OP_BT_SCAN, &priv->op_flags) ?
+                                ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type);
 
        ath9k_hw_btcoex_enable(priv->ah);
-       timer_period = is_btscan ? btcoex->btscan_no_stomp :
-               btcoex->btcoex_no_stomp;
+       timer_period = test_bit(OP_BT_SCAN, &priv->op_flags) ?
+               btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp;
        ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
                                     msecs_to_jiffies(timer_period));
        ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
@@ -104,14 +102,15 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
        struct ath_hw *ah = priv->ah;
        struct ath_btcoex *btcoex = &priv->btcoex;
        struct ath_common *common = ath9k_hw_common(ah);
-       bool is_btscan = priv->op_flags & OP_BT_SCAN;
 
        ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n");
 
-       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
+           test_bit(OP_BT_SCAN, &priv->op_flags))
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
        else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
+
        ath9k_hw_btcoex_enable(priv->ah);
 }
 
@@ -141,7 +140,8 @@ static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
 
        btcoex->bt_priority_cnt = 0;
        btcoex->bt_priority_time = jiffies;
-       priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+       clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags);
+       clear_bit(OP_BT_SCAN, &priv->op_flags);
        ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
 }
 
@@ -310,95 +310,3 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
        if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                wiphy_rfkill_start_polling(priv->hw->wiphy);
 }
-
-void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
-{
-       struct ath9k_htc_priv *priv = hw->priv;
-       struct ath_hw *ah = priv->ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       int ret;
-       u8 cmd_rsp;
-
-       if (!ah->curchan)
-               ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
-
-       /* Reset the HW */
-       ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
-       if (ret) {
-               ath_err(common,
-                       "Unable to reset hardware; reset status %d (freq %u MHz)\n",
-                       ret, ah->curchan->channel);
-       }
-
-       ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
-                              &priv->curtxpow);
-
-       /* Start RX */
-       WMI_CMD(WMI_START_RECV_CMDID);
-       ath9k_host_rx_init(priv);
-
-       /* Start TX */
-       htc_start(priv->htc);
-       spin_lock_bh(&priv->tx.tx_lock);
-       priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
-       spin_unlock_bh(&priv->tx.tx_lock);
-       ieee80211_wake_queues(hw);
-
-       WMI_CMD(WMI_ENABLE_INTR_CMDID);
-
-       /* Enable LED */
-       ath9k_hw_cfg_output(ah, ah->led_pin,
-                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-       ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-}
-
-void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
-{
-       struct ath9k_htc_priv *priv = hw->priv;
-       struct ath_hw *ah = priv->ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       int ret;
-       u8 cmd_rsp;
-
-       ath9k_htc_ps_wakeup(priv);
-
-       /* Disable LED */
-       ath9k_hw_set_gpio(ah, ah->led_pin, 1);
-       ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-
-       WMI_CMD(WMI_DISABLE_INTR_CMDID);
-
-       /* Stop TX */
-       ieee80211_stop_queues(hw);
-       ath9k_htc_tx_drain(priv);
-       WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
-
-       /* Stop RX */
-       WMI_CMD(WMI_STOP_RECV_CMDID);
-
-       /* Clear the WMI event queue */
-       ath9k_wmi_event_drain(priv);
-
-       /*
-        * The MIB counters have to be disabled here,
-        * since the target doesn't do it.
-        */
-       ath9k_hw_disable_mib_counters(ah);
-
-       if (!ah->curchan)
-               ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
-
-       /* Reset the HW */
-       ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
-       if (ret) {
-               ath_err(common,
-                       "Unable to reset hardware; reset status %d (freq %u MHz)\n",
-                       ret, ah->curchan->channel);
-       }
-
-       /* Disable the PHY */
-       ath9k_hw_phy_disable(ah);
-
-       ath9k_htc_ps_restore(priv);
-       ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
-}
index 25213d521bc2ddc9d2beaa916f48f5a2d66ee03a..a035a380d669b6dcd723e9e3d8aabef70feba79b 100644 (file)
@@ -611,7 +611,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
        struct ath_common *common;
        int i, ret = 0, csz = 0;
 
-       priv->op_flags |= OP_INVALID;
+       set_bit(OP_INVALID, &priv->op_flags);
 
        ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
        if (!ah)
@@ -718,7 +718,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 
        hw->queues = 4;
        hw->channel_change_time = 5000;
-       hw->max_listen_interval = 10;
+       hw->max_listen_interval = 1;
 
        hw->vif_data_size = sizeof(struct ath9k_htc_vif);
        hw->sta_data_size = sizeof(struct ath9k_htc_sta);
index abbd6effd60d31eb6a871e101ac10d0bbfa16f2e..374c32ed905ad95407368c13f340e7ef79d7cff7 100644 (file)
@@ -75,14 +75,19 @@ unlock:
 
 void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
 {
+       bool reset;
+
        mutex_lock(&priv->htc_pm_lock);
        if (--priv->ps_usecount != 0)
                goto unlock;
 
-       if (priv->ps_idle)
+       if (priv->ps_idle) {
+               ath9k_hw_setrxabort(priv->ah, true);
+               ath9k_hw_stopdmarecv(priv->ah, &reset);
                ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
-       else if (priv->ps_enabled)
+       } else if (priv->ps_enabled) {
                ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+       }
 
 unlock:
        mutex_unlock(&priv->htc_pm_lock);
@@ -250,7 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
        u8 cmd_rsp;
        int ret;
 
-       if (priv->op_flags & OP_INVALID)
+       if (test_bit(OP_INVALID, &priv->op_flags))
                return -EIO;
 
        fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
@@ -304,7 +309,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 
        htc_start(priv->htc);
 
-       if (!(priv->op_flags & OP_SCANNING) &&
+       if (!test_bit(OP_SCANNING, &priv->op_flags) &&
            !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
                ath9k_htc_vif_reconfig(priv);
 
@@ -750,7 +755,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
        common->ani.shortcal_timer = timestamp;
        common->ani.checkani_timer = timestamp;
 
-       priv->op_flags |= OP_ANI_RUNNING;
+       set_bit(OP_ANI_RUNNING, &priv->op_flags);
 
        ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
                                     msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@@ -759,7 +764,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
 void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
 {
        cancel_delayed_work_sync(&priv->ani_work);
-       priv->op_flags &= ~OP_ANI_RUNNING;
+       clear_bit(OP_ANI_RUNNING, &priv->op_flags);
 }
 
 void ath9k_htc_ani_work(struct work_struct *work)
@@ -944,7 +949,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
                ath_dbg(common, CONFIG,
                        "Failed to update capability in target\n");
 
-       priv->op_flags &= ~OP_INVALID;
+       clear_bit(OP_INVALID, &priv->op_flags);
        htc_start(priv->htc);
 
        spin_lock_bh(&priv->tx.tx_lock);
@@ -973,7 +978,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
 
-       if (priv->op_flags & OP_INVALID) {
+       if (test_bit(OP_INVALID, &priv->op_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&priv->mutex);
                return;
@@ -1015,7 +1020,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        ath9k_htc_ps_restore(priv);
        ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
-       priv->op_flags |= OP_INVALID;
+       set_bit(OP_INVALID, &priv->op_flags);
 
        ath_dbg(common, CONFIG, "Driver halt\n");
        mutex_unlock(&priv->mutex);
@@ -1105,7 +1110,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
        ath9k_htc_set_opmode(priv);
 
        if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
-           !(priv->op_flags & OP_ANI_RUNNING)) {
+           !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
                ath9k_hw_set_tsfadjust(priv->ah, 1);
                ath9k_htc_start_ani(priv);
        }
@@ -1178,24 +1183,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ieee80211_conf *conf = &hw->conf;
+       bool chip_reset = false;
+       int ret = 0;
 
        mutex_lock(&priv->mutex);
+       ath9k_htc_ps_wakeup(priv);
 
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-               bool enable_radio = false;
-               bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
-
                mutex_lock(&priv->htc_pm_lock);
-               if (!idle && priv->ps_idle)
-                       enable_radio = true;
-               priv->ps_idle = idle;
-               mutex_unlock(&priv->htc_pm_lock);
 
-               if (enable_radio) {
-                       ath_dbg(common, CONFIG, "not-idle: enabling radio\n");
-                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
-                       ath9k_htc_radio_enable(hw);
-               }
+               priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+               if (priv->ps_idle)
+                       chip_reset = true;
+
+               mutex_unlock(&priv->htc_pm_lock);
        }
 
        /*
@@ -1210,7 +1211,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                        ath9k_htc_remove_monitor_interface(priv);
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+       if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
 
@@ -1223,8 +1224,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
 
                if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
                        ath_err(common, "Unable to set channel\n");
-                       mutex_unlock(&priv->mutex);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
 
        }
@@ -1246,21 +1247,10 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                                       priv->txpowlimit, &priv->curtxpow);
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-               mutex_lock(&priv->htc_pm_lock);
-               if (!priv->ps_idle) {
-                       mutex_unlock(&priv->htc_pm_lock);
-                       goto out;
-               }
-               mutex_unlock(&priv->htc_pm_lock);
-
-               ath_dbg(common, CONFIG, "idle: disabling radio\n");
-               ath9k_htc_radio_disable(hw);
-       }
-
 out:
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
-       return 0;
+       return ret;
 }
 
 #define SUPPORTED_FILTERS                      \
@@ -1285,7 +1275,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
        changed_flags &= SUPPORTED_FILTERS;
        *total_flags &= SUPPORTED_FILTERS;
 
-       if (priv->op_flags & OP_INVALID) {
+       if (test_bit(OP_INVALID, &priv->op_flags)) {
                ath_dbg(ath9k_hw_common(priv->ah), ANY,
                        "Unable to configure filter on invalid state\n");
                mutex_unlock(&priv->mutex);
@@ -1516,7 +1506,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
                        bss_conf->bssid);
                ath9k_htc_set_tsfadjust(priv, vif);
-               priv->op_flags |= OP_ENABLE_BEACON;
+               set_bit(OP_ENABLE_BEACON, &priv->op_flags);
                ath9k_htc_beacon_config(priv, vif);
        }
 
@@ -1529,7 +1519,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                        ath_dbg(common, CONFIG,
                                "Beacon disabled for BSS: %pM\n",
                                bss_conf->bssid);
-                       priv->op_flags &= ~OP_ENABLE_BEACON;
+                       clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
                        ath9k_htc_beacon_config(priv, vif);
                }
        }
@@ -1542,7 +1532,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                    (priv->nvifs == 1) &&
                    (priv->num_ap_vif == 1) &&
                    (vif->type == NL80211_IFTYPE_AP)) {
-                       priv->op_flags |= OP_TSF_RESET;
+                       set_bit(OP_TSF_RESET, &priv->op_flags);
                }
                ath_dbg(common, CONFIG,
                        "Beacon interval changed for BSS: %pM\n",
@@ -1654,7 +1644,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
        spin_lock_bh(&priv->beacon_lock);
-       priv->op_flags |= OP_SCANNING;
+       set_bit(OP_SCANNING, &priv->op_flags);
        spin_unlock_bh(&priv->beacon_lock);
        cancel_work_sync(&priv->ps_work);
        ath9k_htc_stop_ani(priv);
@@ -1667,7 +1657,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
 
        mutex_lock(&priv->mutex);
        spin_lock_bh(&priv->beacon_lock);
-       priv->op_flags &= ~OP_SCANNING;
+       clear_bit(OP_SCANNING, &priv->op_flags);
        spin_unlock_bh(&priv->beacon_lock);
        ath9k_htc_ps_wakeup(priv);
        ath9k_htc_vif_reconfig(priv);
index 3e40a6461512b7748200617317484219f5f9f0d1..47e61d0da33bf1043b02dcc5e1422aa3c83e37cc 100644 (file)
@@ -916,7 +916,7 @@ void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
 {
        ath9k_hw_rxena(priv->ah);
        ath9k_htc_opmode_init(priv);
-       ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING));
+       ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags));
        priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
 }
 
index 995ca8e1302efc7562ff9905d8e91d00ffb25f74..ebfb2a3c645c51c1732af8d169e948fef32e71cc 100644 (file)
@@ -390,14 +390,6 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 }
 
-static void ath9k_hw_aspm_init(struct ath_hw *ah)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (common->bus_ops->aspm_init)
-               common->bus_ops->aspm_init(common);
-}
-
 /* This should work for all families including legacy */
 static bool ath9k_hw_chip_test(struct ath_hw *ah)
 {
@@ -693,9 +685,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        if (r)
                return r;
 
-       if (ah->is_pciexpress)
-               ath9k_hw_aspm_init(ah);
-
        r = ath9k_hw_init_macaddr(ah);
        if (r) {
                ath_err(common, "Failed to initialize MAC address\n");
@@ -1371,6 +1360,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                }
        }
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_check_gpm_offset(ah);
+
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
        REGWRITE_BUFFER_FLUSH(ah);
@@ -1455,9 +1447,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
                break;
        }
 
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-               REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
        return ret;
 }
 
@@ -1733,8 +1722,8 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
        ath9k_hw_loadnf(ah, ah->curchan);
        ath9k_hw_start_nfcal(ah, true);
 
-       if ((ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && ar9003_mci_is_ready(ah))
-               ar9003_mci_2g5g_switch(ah, true);
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_2g5g_switch(ah, false);
 
        if (AR_SREV_9271(ah))
                ar9002_hw_load_ani_reg(ah, chan);
@@ -1754,10 +1743,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u64 tsf = 0;
        int i, r;
        bool start_mci_reset = false;
-       bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
        bool save_fullsleep = ah->chip_fullsleep;
 
-       if (mci) {
+       if (ath9k_hw_mci_is_enabled(ah)) {
                start_mci_reset = ar9003_mci_start_reset(ah, chan);
                if (start_mci_reset)
                        return 0;
@@ -1786,7 +1774,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                        return r;
        }
 
-       if (mci)
+       if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_stop_bt(ah, save_fullsleep);
 
        saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
@@ -1844,7 +1832,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (r)
                return r;
 
-       if (mci)
+       if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
 
        /*
@@ -1939,7 +1927,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_set_dma(ah);
 
-       REG_WRITE(ah, AR_OBS, 8);
+       if (!ath9k_hw_mci_is_enabled(ah))
+               REG_WRITE(ah, AR_OBS, 8);
 
        if (ah->config.rx_intr_mitigation) {
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
@@ -1963,7 +1952,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
-       if (mci && ar9003_mci_end_reset(ah, chan, caldata))
+       if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata))
                return -EIO;
 
        ENABLE_REGWRITE_BUFFER(ah);
@@ -2008,7 +1997,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ath9k_hw_btcoex_is_enabled(ah))
                ath9k_hw_btcoex_enable(ah);
 
-       if (mci)
+       if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_check_bt(ah);
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -2031,39 +2020,35 @@ EXPORT_SYMBOL(ath9k_hw_reset);
  * Notify Power Mgt is disabled in self-generated frames.
  * If requested, force chip to sleep.
  */
-static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_sleep(struct ath_hw *ah)
 {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-       if (setChip) {
-               if (AR_SREV_9462(ah)) {
-                       REG_WRITE(ah, AR_TIMER_MODE,
-                                 REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00);
-                       REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah,
-                                 AR_NDP2_TIMER_MODE) & 0xFFFFFF00);
-                       REG_WRITE(ah, AR_SLP32_INC,
-                                 REG_READ(ah, AR_SLP32_INC) & 0xFFF00000);
-                       /* xxx Required for WLAN only case ? */
-                       REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
-                       udelay(100);
-               }
 
-               /*
-                * Clear the RTC force wake bit to allow the
-                * mac to go to sleep.
-                */
-               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+       if (AR_SREV_9462(ah)) {
+               REG_CLR_BIT(ah, AR_TIMER_MODE, 0xff);
+               REG_CLR_BIT(ah, AR_NDP2_TIMER_MODE, 0xff);
+               REG_CLR_BIT(ah, AR_SLP32_INC, 0xfffff);
+               /* xxx Required for WLAN only case ? */
+               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
+               udelay(100);
+       }
 
-               if (AR_SREV_9462(ah))
-                       udelay(100);
+       /*
+        * Clear the RTC force wake bit to allow the
+        * mac to go to sleep.
+        */
+       REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
 
-               if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
-                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+       if (ath9k_hw_mci_is_enabled(ah))
+               udelay(100);
 
-               /* Shutdown chip. Active low */
-               if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
-                       REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
-                       udelay(2);
-               }
+       if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+
+       /* Shutdown chip. Active low */
+       if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) {
+               REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN);
+               udelay(2);
        }
 
        /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
@@ -2076,44 +2061,38 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
  * frames. If request, set power mode of chip to
  * auto/normal.  Duration in units of 128us (1/8 TU).
  */
-static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
+static void ath9k_set_power_network_sleep(struct ath_hw *ah)
 {
-       u32 val;
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
 
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-       if (setChip) {
-               struct ath9k_hw_capabilities *pCap = &ah->caps;
 
-               if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-                       /* Set WakeOnInterrupt bit; clear ForceWake bit */
-                       REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-                                 AR_RTC_FORCE_WAKE_ON_INT);
-               } else {
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+               /* Set WakeOnInterrupt bit; clear ForceWake bit */
+               REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+                         AR_RTC_FORCE_WAKE_ON_INT);
+       } else {
 
-                       /* When chip goes into network sleep, it could be waken
-                        * up by MCI_INT interrupt caused by BT's HW messages
-                        * (LNA_xxx, CONT_xxx) which chould be in a very fast
-                        * rate (~100us). This will cause chip to leave and
-                        * re-enter network sleep mode frequently, which in
-                        * consequence will have WLAN MCI HW to generate lots of
-                        * SYS_WAKING and SYS_SLEEPING messages which will make
-                        * BT CPU to busy to process.
-                        */
-                       if (AR_SREV_9462(ah)) {
-                               val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) &
-                                       ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK;
-                               REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val);
-                       }
-                       /*
-                        * Clear the RTC force wake bit to allow the
-                        * mac to go to sleep.
-                        */
-                       REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-                                   AR_RTC_FORCE_WAKE_EN);
-
-                       if (AR_SREV_9462(ah))
-                               udelay(30);
-               }
+               /* When chip goes into network sleep, it could be waken
+                * up by MCI_INT interrupt caused by BT's HW messages
+                * (LNA_xxx, CONT_xxx) which chould be in a very fast
+                * rate (~100us). This will cause chip to leave and
+                * re-enter network sleep mode frequently, which in
+                * consequence will have WLAN MCI HW to generate lots of
+                * SYS_WAKING and SYS_SLEEPING messages which will make
+                * BT CPU to busy to process.
+                */
+               if (ath9k_hw_mci_is_enabled(ah))
+                       REG_CLR_BIT(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
+                                   AR_MCI_INTERRUPT_RX_HW_MSG_MASK);
+               /*
+                * Clear the RTC force wake bit to allow the
+                * mac to go to sleep.
+                */
+               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN);
+
+               if (ath9k_hw_mci_is_enabled(ah))
+                       udelay(30);
        }
 
        /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */
@@ -2121,7 +2100,7 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
                REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
 }
 
-static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
+static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
 {
        u32 val;
        int i;
@@ -2132,37 +2111,38 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
                udelay(10);
        }
 
-       if (setChip) {
-               if ((REG_READ(ah, AR_RTC_STATUS) &
-                    AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
-                       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-                               return false;
-                       }
-                       if (!AR_SREV_9300_20_OR_LATER(ah))
-                               ath9k_hw_init_pll(ah, NULL);
+       if ((REG_READ(ah, AR_RTC_STATUS) &
+            AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+               if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+                       return false;
                }
-               if (AR_SREV_9100(ah))
-                       REG_SET_BIT(ah, AR_RTC_RESET,
-                                   AR_RTC_RESET_EN);
+               if (!AR_SREV_9300_20_OR_LATER(ah))
+                       ath9k_hw_init_pll(ah, NULL);
+       }
+       if (AR_SREV_9100(ah))
+               REG_SET_BIT(ah, AR_RTC_RESET,
+                           AR_RTC_RESET_EN);
 
+       REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+                   AR_RTC_FORCE_WAKE_EN);
+       udelay(50);
+
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_set_power_awake(ah);
+
+       for (i = POWER_UP_TIME / 50; i > 0; i--) {
+               val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+               if (val == AR_RTC_STATUS_ON)
+                       break;
+               udelay(50);
                REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
                            AR_RTC_FORCE_WAKE_EN);
-               udelay(50);
-
-               for (i = POWER_UP_TIME / 50; i > 0; i--) {
-                       val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
-                       if (val == AR_RTC_STATUS_ON)
-                               break;
-                       udelay(50);
-                       REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-                                   AR_RTC_FORCE_WAKE_EN);
-               }
-               if (i == 0) {
-                       ath_err(ath9k_hw_common(ah),
-                               "Failed to wakeup in %uus\n",
-                               POWER_UP_TIME / 20);
-                       return false;
-               }
+       }
+       if (i == 0) {
+               ath_err(ath9k_hw_common(ah),
+                       "Failed to wakeup in %uus\n",
+                       POWER_UP_TIME / 20);
+               return false;
        }
 
        REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
@@ -2173,7 +2153,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
 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;
+       int status = true;
        static const char *modes[] = {
                "AWAKE",
                "FULL-SLEEP",
@@ -2189,25 +2169,17 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 
        switch (mode) {
        case ATH9K_PM_AWAKE:
-               status = ath9k_hw_set_power_awake(ah, setChip);
-
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
+               status = ath9k_hw_set_power_awake(ah);
                break;
        case ATH9K_PM_FULL_SLEEP:
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               if (ath9k_hw_mci_is_enabled(ah))
                        ar9003_mci_set_full_sleep(ah);
 
-               ath9k_set_power_sleep(ah, setChip);
+               ath9k_set_power_sleep(ah);
                ah->chip_fullsleep = true;
                break;
        case ATH9K_PM_NETWORK_SLEEP:
-
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-                       REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
-
-               ath9k_set_power_network_sleep(ah, setChip);
+               ath9k_set_power_network_sleep(ah);
                break;
        default:
                ath_err(common, "Unknown power mode %u\n", mode);
@@ -2777,6 +2749,9 @@ EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
 bool ath9k_hw_phy_disable(struct ath_hw *ah)
 {
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_bt_gain_ctrl(ah);
+
        if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
                return false;
 
index b620c557c2a68a86411de8534a00df5c5e49455d..94096607cbdda9a8d8606f575a64a575ad94c3a1 100644 (file)
@@ -824,7 +824,6 @@ struct ath_hw {
        struct ar5416IniArray ini_japan2484;
        struct ar5416IniArray iniModes_9271_ANI_reg;
        struct ar5416IniArray ini_radio_post_sys2ant;
-       struct ar5416IniArray ini_BTCOEX_MAX_TXPWR;
 
        struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
        struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
@@ -1020,16 +1019,8 @@ void ar9002_hw_attach_ops(struct ath_hw *ah);
 void ar9003_hw_attach_ops(struct ath_hw *ah);
 
 void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
-/*
- * ANI work can be shared between all families but a next
- * generation implementation of ANI will be used only for AR9003 only
- * for now as the other families still need to be tested with the same
- * next generation ANI. Feel free to start testing it though for the
- * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
- */
-extern int modparam_force_new_ani;
+
 void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
-void ath9k_hw_proc_mib_event(struct ath_hw *ah);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
@@ -1037,6 +1028,12 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
 {
        return ah->btcoex_hw.enabled;
 }
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+       return ah->common.btcoex_enabled &&
+              (ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
+
+}
 void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 static inline enum ath_btcoex_scheme
 ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
@@ -1048,6 +1045,10 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
 {
        return false;
 }
+static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah)
+{
+       return false;
+}
 static inline void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 {
 }
index dee9e092449ab3fb00455abfdc26cb17ba57a4ca..9dfce1a69c73af0f493ef2acf6480710a211f750 100644 (file)
@@ -489,6 +489,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
 
        setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
+       sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
        sc->config.txpowlimit = ATH_TXPOWER_MAX;
        memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
        sc->beacon.slottime = ATH9K_SLOT_TIME_9;
@@ -560,6 +561,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
                     (unsigned long)sc);
 
+       INIT_WORK(&sc->hw_reset_work, ath_reset_work);
+       INIT_WORK(&sc->hw_check_work, ath_hw_check);
+       INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+       INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
+       setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
+
        /*
         * Cache line size is used to size and align various
         * structures used to communicate with the hardware.
@@ -590,6 +597,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        ath9k_cmn_init_crypto(sc->sc_ah);
        ath9k_init_misc(sc);
 
+       if (common->bus_ops->aspm_init)
+               common->bus_ops->aspm_init(common);
+
        return 0;
 
 err_btcoex:
@@ -782,11 +792,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
                ARRAY_SIZE(ath9k_tpt_blink));
 #endif
 
-       INIT_WORK(&sc->hw_reset_work, ath_reset_work);
-       INIT_WORK(&sc->hw_check_work, ath_hw_check);
-       INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
-       INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-
        /* Register with mac80211 */
        error = ieee80211_register_hw(hw);
        if (error)
@@ -805,9 +810,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
                        goto error_world;
        }
 
-       setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
-       sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-
        ath_init_leds(sc);
        ath_start_rfkill_poll(sc);
 
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
new file mode 100644 (file)
index 0000000..91650fe
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, 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 "ath9k.h"
+
+/*
+ * TX polling - checks if the TX engine is stuck somewhere
+ * and issues a chip reset if so.
+ */
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           tx_complete_work.work);
+       struct ath_txq *txq;
+       int i;
+       bool needreset = false;
+#ifdef CONFIG_ATH9K_DEBUGFS
+       sc->tx_complete_poll_work_seen++;
+#endif
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i)) {
+                       txq = &sc->tx.txq[i];
+                       ath_txq_lock(sc, txq);
+                       if (txq->axq_depth) {
+                               if (txq->axq_tx_inprogress) {
+                                       needreset = true;
+                                       ath_txq_unlock(sc, txq);
+                                       break;
+                               } else {
+                                       txq->axq_tx_inprogress = true;
+                               }
+                       }
+                       ath_txq_unlock_complete(sc, txq);
+               }
+
+       if (needreset) {
+               ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+                       "tx hung, resetting the chip\n");
+               RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
+               ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+               return;
+       }
+
+       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+                                    msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+/*
+ * Checks if the BB/MAC is hung.
+ */
+void ath_hw_check(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long flags;
+       int busy;
+       u8 is_alive, nbeacon = 1;
+
+       ath9k_ps_wakeup(sc);
+       is_alive = ath9k_hw_check_alive(sc->sc_ah);
+
+       if (is_alive && !AR_SREV_9300(sc->sc_ah))
+               goto out;
+       else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
+               ath_dbg(common, RESET,
+                       "DCU stuck is detected. Schedule chip reset\n");
+               RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
+               goto sched_reset;
+       }
+
+       spin_lock_irqsave(&common->cc_lock, flags);
+       busy = ath_update_survey_stats(sc);
+       spin_unlock_irqrestore(&common->cc_lock, flags);
+
+       ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
+               busy, sc->hw_busy_count + 1);
+       if (busy >= 99) {
+               if (++sc->hw_busy_count >= 3) {
+                       RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
+                       goto sched_reset;
+               }
+       } else if (busy >= 0) {
+               sc->hw_busy_count = 0;
+               nbeacon = 3;
+       }
+
+       ath_start_rx_poll(sc, nbeacon);
+       goto out;
+
+sched_reset:
+       ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+out:
+       ath9k_ps_restore(sc);
+}
+
+/*
+ * PLL-WAR for AR9485/AR9340
+ */
+static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+       static int count;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       if (pll_sqsum >= 0x40000) {
+               count++;
+               if (count == 3) {
+                       ath_dbg(common, RESET, "PLL WAR, resetting the chip\n");
+                       RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
+                       ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+                       count = 0;
+                       return true;
+               }
+       } else {
+               count = 0;
+       }
+
+       return false;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+       u32 pll_sqsum;
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           hw_pll_work.work);
+       /*
+        * ensure that the PLL WAR is executed only
+        * after the STA is associated (or) if the
+        * beaconing had started in interfaces that
+        * uses beacons.
+        */
+       if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+               return;
+
+       ath9k_ps_wakeup(sc);
+       pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+       ath9k_ps_restore(sc);
+       if (ath_hw_pll_rx_hang_check(sc, pll_sqsum))
+               return;
+
+       ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+                                    msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+}
+
+/*
+ * RX Polling - monitors baseband hangs.
+ */
+void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
+{
+       if (!AR_SREV_9300(sc->sc_ah))
+               return;
+
+       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
+               return;
+
+       mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
+                 (nbeacon * sc->cur_beacon_conf.beacon_interval));
+}
+
+void ath_rx_poll(unsigned long data)
+{
+       struct ath_softc *sc = (struct ath_softc *)data;
+
+       ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+}
+
+/*
+ * PA Pre-distortion.
+ */
+static void ath_paprd_activate(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+       int chain;
+
+       if (!caldata || !caldata->paprd_done)
+               return;
+
+       ath9k_ps_wakeup(sc);
+       ar9003_paprd_enable(ah, false);
+       for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+               if (!(ah->txchainmask & BIT(chain)))
+                       continue;
+
+               ar9003_paprd_populate_single_table(ah, caldata, chain);
+       }
+
+       ar9003_paprd_enable(ah, true);
+       ath9k_ps_restore(sc);
+}
+
+static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_tx_control txctl;
+       int time_left;
+
+       memset(&txctl, 0, sizeof(txctl));
+       txctl.txq = sc->tx.txq_map[WME_AC_BE];
+
+       memset(tx_info, 0, sizeof(*tx_info));
+       tx_info->band = hw->conf.channel->band;
+       tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       tx_info->control.rates[0].idx = 0;
+       tx_info->control.rates[0].count = 1;
+       tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+       tx_info->control.rates[1].idx = -1;
+
+       init_completion(&sc->paprd_complete);
+       txctl.paprd = BIT(chain);
+
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
+               ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
+               dev_kfree_skb_any(skb);
+               return false;
+       }
+
+       time_left = wait_for_completion_timeout(&sc->paprd_complete,
+                       msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
+
+       if (!time_left)
+               ath_dbg(common, CALIBRATE,
+                       "Timeout waiting for paprd training on TX chain %d\n",
+                       chain);
+
+       return !!time_left;
+}
+
+void ath_paprd_calibrate(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ieee80211_hdr *hdr;
+       struct sk_buff *skb = NULL;
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+       struct ath_common *common = ath9k_hw_common(ah);
+       int ftype;
+       int chain_ok = 0;
+       int chain;
+       int len = 1800;
+
+       if (!caldata)
+               return;
+
+       ath9k_ps_wakeup(sc);
+
+       if (ar9003_paprd_init_table(ah) < 0)
+               goto fail_paprd;
+
+       skb = alloc_skb(len, GFP_KERNEL);
+       if (!skb)
+               goto fail_paprd;
+
+       skb_put(skb, len);
+       memset(skb->data, 0, len);
+       hdr = (struct ieee80211_hdr *)skb->data;
+       ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
+       hdr->frame_control = cpu_to_le16(ftype);
+       hdr->duration_id = cpu_to_le16(10);
+       memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+       memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+       memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+       for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+               if (!(ah->txchainmask & BIT(chain)))
+                       continue;
+
+               chain_ok = 0;
+
+               ath_dbg(common, CALIBRATE,
+                       "Sending PAPRD frame for thermal measurement on chain %d\n",
+                       chain);
+               if (!ath_paprd_send_frame(sc, skb, chain))
+                       goto fail_paprd;
+
+               ar9003_paprd_setup_gain_table(ah, chain);
+
+               ath_dbg(common, CALIBRATE,
+                       "Sending PAPRD training frame on chain %d\n", chain);
+               if (!ath_paprd_send_frame(sc, skb, chain))
+                       goto fail_paprd;
+
+               if (!ar9003_paprd_is_done(ah)) {
+                       ath_dbg(common, CALIBRATE,
+                               "PAPRD not yet done on chain %d\n", chain);
+                       break;
+               }
+
+               if (ar9003_paprd_create_curve(ah, caldata, chain)) {
+                       ath_dbg(common, CALIBRATE,
+                               "PAPRD create curve failed on chain %d\n",
+                               chain);
+                       break;
+               }
+
+               chain_ok = 1;
+       }
+       kfree_skb(skb);
+
+       if (chain_ok) {
+               caldata->paprd_done = true;
+               ath_paprd_activate(sc);
+       }
+
+fail_paprd:
+       ath9k_ps_restore(sc);
+}
+
+/*
+ *  ANI performs periodic noise floor calibration
+ *  that is used to adjust and optimize the chip performance.  This
+ *  takes environmental changes (location, temperature) into account.
+ *  When the task is complete, it reschedules itself depending on the
+ *  appropriate interval that was calculated.
+ */
+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;
+       unsigned int timestamp = jiffies_to_msecs(jiffies);
+       u32 cal_interval, short_cal_interval, long_cal_interval;
+       unsigned long flags;
+
+       if (ah->caldata && ah->caldata->nfcal_interference)
+               long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+       else
+               long_cal_interval = ATH_LONG_CALINTERVAL;
+
+       short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
+               ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
+
+       /* Only calibrate if awake */
+       if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+               goto set_timer;
+
+       ath9k_ps_wakeup(sc);
+
+       /* Long calibration runs independently of short calibration. */
+       if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
+               longcal = true;
+               common->ani.longcal_timer = timestamp;
+       }
+
+       /* Short calibration applies only while caldone is false */
+       if (!common->ani.caldone) {
+               if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
+                       shortcal = true;
+                       common->ani.shortcal_timer = timestamp;
+                       common->ani.resetcal_timer = timestamp;
+               }
+       } else {
+               if ((timestamp - common->ani.resetcal_timer) >=
+                   ATH_RESTART_CALINTERVAL) {
+                       common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+                       if (common->ani.caldone)
+                               common->ani.resetcal_timer = timestamp;
+               }
+       }
+
+       /* Verify whether we must check ANI */
+       if (sc->sc_ah->config.enable_ani
+           && (timestamp - common->ani.checkani_timer) >=
+           ah->config.ani_poll_interval) {
+               aniflag = true;
+               common->ani.checkani_timer = timestamp;
+       }
+
+       /* Call ANI routine if necessary */
+       if (aniflag) {
+               spin_lock_irqsave(&common->cc_lock, flags);
+               ath9k_hw_ani_monitor(ah, ah->curchan);
+               ath_update_survey_stats(sc);
+               spin_unlock_irqrestore(&common->cc_lock, flags);
+       }
+
+       /* Perform calibration if necessary */
+       if (longcal || shortcal) {
+               common->ani.caldone =
+                       ath9k_hw_calibrate(ah, ah->curchan,
+                                          ah->rxchainmask, longcal);
+       }
+
+       ath_dbg(common, ANI,
+               "Calibration @%lu finished: %s %s %s, caldone: %s\n",
+               jiffies,
+               longcal ? "long" : "", shortcal ? "short" : "",
+               aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
+
+       ath9k_debug_samp_bb_mac(sc);
+       ath9k_ps_restore(sc);
+
+set_timer:
+       /*
+       * Set timer interval based on previous results.
+       * The interval must be the shortest necessary to satisfy ANI,
+       * short calibration and long calibration.
+       */
+       cal_interval = ATH_LONG_CALINTERVAL;
+       if (sc->sc_ah->config.enable_ani)
+               cal_interval = min(cal_interval,
+                                  (u32)ah->config.ani_poll_interval);
+       if (!common->ani.caldone)
+               cal_interval = min(cal_interval, (u32)short_cal_interval);
+
+       mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+               if (!ah->caldata->paprd_done)
+                       ieee80211_queue_work(sc->hw, &sc->paprd_work);
+               else if (!ah->paprd_table_write_done)
+                       ath_paprd_activate(sc);
+       }
+}
+
+void ath_start_ani(struct ath_common *common)
+{
+       struct ath_hw *ah = common->ah;
+       unsigned long timestamp = jiffies_to_msecs(jiffies);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+       if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags))
+               return;
+
+       if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+               return;
+
+       common->ani.longcal_timer = timestamp;
+       common->ani.shortcal_timer = timestamp;
+       common->ani.checkani_timer = timestamp;
+
+       mod_timer(&common->ani.timer,
+                 jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval));
+}
+
+void ath_update_survey_nf(struct ath_softc *sc, int channel)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_channel *chan = &ah->channels[channel];
+       struct survey_info *survey = &sc->survey[channel];
+
+       if (chan->noisefloor) {
+               survey->filled |= SURVEY_INFO_NOISE_DBM;
+               survey->noise = ath9k_hw_getchan_noise(ah, chan);
+       }
+}
+
+/*
+ * Updates the survey statistics and returns the busy time since last
+ * update in %, if the measurement duration was long enough for the
+ * result to be useful, -1 otherwise.
+ */
+int ath_update_survey_stats(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       int pos = ah->curchan - &ah->channels[0];
+       struct survey_info *survey = &sc->survey[pos];
+       struct ath_cycle_counters *cc = &common->cc_survey;
+       unsigned int div = common->clockrate * 1000;
+       int ret = 0;
+
+       if (!ah->curchan)
+               return -1;
+
+       if (ah->power_mode == ATH9K_PM_AWAKE)
+               ath_hw_cycle_counters_update(common);
+
+       if (cc->cycles > 0) {
+               survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+                       SURVEY_INFO_CHANNEL_TIME_BUSY |
+                       SURVEY_INFO_CHANNEL_TIME_RX |
+                       SURVEY_INFO_CHANNEL_TIME_TX;
+               survey->channel_time += cc->cycles / div;
+               survey->channel_time_busy += cc->rx_busy / div;
+               survey->channel_time_rx += cc->rx_frame / div;
+               survey->channel_time_tx += cc->tx_frame / div;
+       }
+
+       if (cc->cycles < div)
+               return -1;
+
+       if (cc->cycles > 0)
+               ret = cc->rx_busy * 100 / cc->cycles;
+
+       memset(cc, 0, sizeof(*cc));
+
+       ath_update_survey_nf(sc, pos);
+
+       return ret;
+}
index dac1a2709e3cb7aa961240a088ef15fe3311bec2..e4e73f061a221e6c0eb30f7df2e2360164becd6b 100644 (file)
@@ -19,7 +19,7 @@
 #include "ath9k.h"
 #include "btcoex.h"
 
-static u8 parse_mpdudensity(u8 mpdudensity)
+u8 ath9k_parse_mpdudensity(u8 mpdudensity)
 {
        /*
         * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
@@ -101,6 +101,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
                spin_lock(&common->cc_lock);
                ath_hw_cycle_counters_update(common);
                memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+               memset(&common->cc_ani, 0, sizeof(common->cc_ani));
                spin_unlock(&common->cc_lock);
        }
 
@@ -143,90 +144,17 @@ void ath9k_ps_restore(struct ath_softc *sc)
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 }
 
-void ath_start_ani(struct ath_common *common)
-{
-       struct ath_hw *ah = common->ah;
-       unsigned long timestamp = jiffies_to_msecs(jiffies);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-       if (!(sc->sc_flags & SC_OP_ANI_RUN))
-               return;
-
-       if (sc->sc_flags & SC_OP_OFFCHANNEL)
-               return;
-
-       common->ani.longcal_timer = timestamp;
-       common->ani.shortcal_timer = timestamp;
-       common->ani.checkani_timer = timestamp;
-
-       mod_timer(&common->ani.timer,
-                 jiffies +
-                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
-}
-
-static void ath_update_survey_nf(struct ath_softc *sc, int channel)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath9k_channel *chan = &ah->channels[channel];
-       struct survey_info *survey = &sc->survey[channel];
-
-       if (chan->noisefloor) {
-               survey->filled |= SURVEY_INFO_NOISE_DBM;
-               survey->noise = ath9k_hw_getchan_noise(ah, chan);
-       }
-}
-
-/*
- * Updates the survey statistics and returns the busy time since last
- * update in %, if the measurement duration was long enough for the
- * result to be useful, -1 otherwise.
- */
-static int ath_update_survey_stats(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       int pos = ah->curchan - &ah->channels[0];
-       struct survey_info *survey = &sc->survey[pos];
-       struct ath_cycle_counters *cc = &common->cc_survey;
-       unsigned int div = common->clockrate * 1000;
-       int ret = 0;
-
-       if (!ah->curchan)
-               return -1;
-
-       if (ah->power_mode == ATH9K_PM_AWAKE)
-               ath_hw_cycle_counters_update(common);
-
-       if (cc->cycles > 0) {
-               survey->filled |= SURVEY_INFO_CHANNEL_TIME |
-                       SURVEY_INFO_CHANNEL_TIME_BUSY |
-                       SURVEY_INFO_CHANNEL_TIME_RX |
-                       SURVEY_INFO_CHANNEL_TIME_TX;
-               survey->channel_time += cc->cycles / div;
-               survey->channel_time_busy += cc->rx_busy / div;
-               survey->channel_time_rx += cc->rx_frame / div;
-               survey->channel_time_tx += cc->tx_frame / div;
-       }
-
-       if (cc->cycles < div)
-               return -1;
-
-       if (cc->cycles > 0)
-               ret = cc->rx_busy * 100 / cc->cycles;
-
-       memset(cc, 0, sizeof(*cc));
-
-       ath_update_survey_nf(sc, pos);
-
-       return ret;
-}
-
 static void __ath_cancel_work(struct ath_softc *sc)
 {
        cancel_work_sync(&sc->paprd_work);
        cancel_work_sync(&sc->hw_check_work);
        cancel_delayed_work_sync(&sc->tx_complete_work);
        cancel_delayed_work_sync(&sc->hw_pll_work);
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+               cancel_work_sync(&sc->mci_work);
+#endif
 }
 
 static void ath_cancel_work(struct ath_softc *sc)
@@ -235,6 +163,22 @@ static void ath_cancel_work(struct ath_softc *sc)
        cancel_work_sync(&sc->hw_reset_work);
 }
 
+static void ath_restart_work(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+
+       if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah))
+               ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+                                    msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
+
+       ath_start_rx_poll(sc, 3);
+
+       if (!common->disable_ani)
+               ath_start_ani(common);
+}
+
 static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -271,6 +215,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
+       unsigned long flags;
 
        if (ath_startrecv(sc) != 0) {
                ath_err(common, "Unable to restart recv logic\n");
@@ -279,36 +224,30 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
 
        ath9k_cmn_update_txpow(ah, sc->curtxpow,
                               sc->config.txpowlimit, &sc->curtxpow);
+
+       clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
        ath9k_hw_set_interrupts(ah);
        ath9k_hw_enable_interrupts(ah);
 
-       if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
-               if (sc->sc_flags & SC_OP_BEACONS)
-                       ath_set_beacon(sc);
-
-               ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
-               ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
-               ath_start_rx_poll(sc, 3);
-               if (!common->disable_ani)
-                       ath_start_ani(common);
-       }
-
-       if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
-               struct ath_hw_antcomb_conf div_ant_conf;
-               u8 lna_conf;
+       if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
+               if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
+                       goto work;
 
-               ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+               ath_set_beacon(sc);
 
-               if (sc->ant_rx == 1)
-                       lna_conf = ATH_ANT_DIV_COMB_LNA1;
-               else
-                       lna_conf = ATH_ANT_DIV_COMB_LNA2;
-               div_ant_conf.main_lna_conf = lna_conf;
-               div_ant_conf.alt_lna_conf = lna_conf;
-
-               ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
+               if (ah->opmode == NL80211_IFTYPE_STATION &&
+                   test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
+                       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+                       sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+                       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+               }
+       work:
+               ath_restart_work(sc);
        }
 
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3)
+               ath_ant_comb_update(sc);
+
        ieee80211_wake_queues(sc->hw);
 
        return true;
@@ -328,7 +267,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
 
        spin_lock_bh(&sc->sc_pcu_lock);
 
-       if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
+       if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
                fastcc = false;
                caldata = &sc->caldata;
        }
@@ -371,7 +310,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 {
        int r;
 
-       if (sc->sc_flags & SC_OP_INVALID)
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
 
        r = ath_reset_internal(sc, hchan, false);
@@ -379,262 +318,11 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
        return r;
 }
 
-static void ath_paprd_activate(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath9k_hw_cal_data *caldata = ah->caldata;
-       int chain;
-
-       if (!caldata || !caldata->paprd_done)
-               return;
-
-       ath9k_ps_wakeup(sc);
-       ar9003_paprd_enable(ah, false);
-       for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
-               if (!(ah->txchainmask & BIT(chain)))
-                       continue;
-
-               ar9003_paprd_populate_single_table(ah, caldata, chain);
-       }
-
-       ar9003_paprd_enable(ah, true);
-       ath9k_ps_restore(sc);
-}
-
-static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain)
-{
-       struct ieee80211_hw *hw = sc->hw;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_tx_control txctl;
-       int time_left;
-
-       memset(&txctl, 0, sizeof(txctl));
-       txctl.txq = sc->tx.txq_map[WME_AC_BE];
-
-       memset(tx_info, 0, sizeof(*tx_info));
-       tx_info->band = hw->conf.channel->band;
-       tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
-       tx_info->control.rates[0].idx = 0;
-       tx_info->control.rates[0].count = 1;
-       tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
-       tx_info->control.rates[1].idx = -1;
-
-       init_completion(&sc->paprd_complete);
-       txctl.paprd = BIT(chain);
-
-       if (ath_tx_start(hw, skb, &txctl) != 0) {
-               ath_dbg(common, CALIBRATE, "PAPRD TX failed\n");
-               dev_kfree_skb_any(skb);
-               return false;
-       }
-
-       time_left = wait_for_completion_timeout(&sc->paprd_complete,
-                       msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
-
-       if (!time_left)
-               ath_dbg(common, CALIBRATE,
-                       "Timeout waiting for paprd training on TX chain %d\n",
-                       chain);
-
-       return !!time_left;
-}
-
-void ath_paprd_calibrate(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work);
-       struct ieee80211_hw *hw = sc->hw;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ieee80211_hdr *hdr;
-       struct sk_buff *skb = NULL;
-       struct ath9k_hw_cal_data *caldata = ah->caldata;
-       struct ath_common *common = ath9k_hw_common(ah);
-       int ftype;
-       int chain_ok = 0;
-       int chain;
-       int len = 1800;
-
-       if (!caldata)
-               return;
-
-       ath9k_ps_wakeup(sc);
-
-       if (ar9003_paprd_init_table(ah) < 0)
-               goto fail_paprd;
-
-       skb = alloc_skb(len, GFP_KERNEL);
-       if (!skb)
-               goto fail_paprd;
-
-       skb_put(skb, len);
-       memset(skb->data, 0, len);
-       hdr = (struct ieee80211_hdr *)skb->data;
-       ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC;
-       hdr->frame_control = cpu_to_le16(ftype);
-       hdr->duration_id = cpu_to_le16(10);
-       memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
-       memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
-       memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
-
-       for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
-               if (!(ah->txchainmask & BIT(chain)))
-                       continue;
-
-               chain_ok = 0;
-
-               ath_dbg(common, CALIBRATE,
-                       "Sending PAPRD frame for thermal measurement on chain %d\n",
-                       chain);
-               if (!ath_paprd_send_frame(sc, skb, chain))
-                       goto fail_paprd;
-
-               ar9003_paprd_setup_gain_table(ah, chain);
-
-               ath_dbg(common, CALIBRATE,
-                       "Sending PAPRD training frame on chain %d\n", chain);
-               if (!ath_paprd_send_frame(sc, skb, chain))
-                       goto fail_paprd;
-
-               if (!ar9003_paprd_is_done(ah)) {
-                       ath_dbg(common, CALIBRATE,
-                               "PAPRD not yet done on chain %d\n", chain);
-                       break;
-               }
-
-               if (ar9003_paprd_create_curve(ah, caldata, chain)) {
-                       ath_dbg(common, CALIBRATE,
-                               "PAPRD create curve failed on chain %d\n",
-                                                                  chain);
-                       break;
-               }
-
-               chain_ok = 1;
-       }
-       kfree_skb(skb);
-
-       if (chain_ok) {
-               caldata->paprd_done = true;
-               ath_paprd_activate(sc);
-       }
-
-fail_paprd:
-       ath9k_ps_restore(sc);
-}
-
-/*
- *  This routine performs the periodic noise floor calibration function
- *  that is used to adjust and optimize the chip performance.  This
- *  takes environmental changes (location, temperature) into account.
- *  When the task is complete, it reschedules itself depending on the
- *  appropriate interval that was calculated.
- */
-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;
-       unsigned int timestamp = jiffies_to_msecs(jiffies);
-       u32 cal_interval, short_cal_interval, long_cal_interval;
-       unsigned long flags;
-
-       if (ah->caldata && ah->caldata->nfcal_interference)
-               long_cal_interval = ATH_LONG_CALINTERVAL_INT;
-       else
-               long_cal_interval = ATH_LONG_CALINTERVAL;
-
-       short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
-               ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
-
-       /* Only calibrate if awake */
-       if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
-               goto set_timer;
-
-       ath9k_ps_wakeup(sc);
-
-       /* Long calibration runs independently of short calibration. */
-       if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
-               longcal = true;
-               common->ani.longcal_timer = timestamp;
-       }
-
-       /* Short calibration applies only while caldone is false */
-       if (!common->ani.caldone) {
-               if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
-                       shortcal = true;
-                       common->ani.shortcal_timer = timestamp;
-                       common->ani.resetcal_timer = timestamp;
-               }
-       } else {
-               if ((timestamp - common->ani.resetcal_timer) >=
-                   ATH_RESTART_CALINTERVAL) {
-                       common->ani.caldone = ath9k_hw_reset_calvalid(ah);
-                       if (common->ani.caldone)
-                               common->ani.resetcal_timer = timestamp;
-               }
-       }
-
-       /* Verify whether we must check ANI */
-       if (sc->sc_ah->config.enable_ani
-           && (timestamp - common->ani.checkani_timer) >=
-           ah->config.ani_poll_interval) {
-               aniflag = true;
-               common->ani.checkani_timer = timestamp;
-       }
-
-       /* Call ANI routine if necessary */
-       if (aniflag) {
-               spin_lock_irqsave(&common->cc_lock, flags);
-               ath9k_hw_ani_monitor(ah, ah->curchan);
-               ath_update_survey_stats(sc);
-               spin_unlock_irqrestore(&common->cc_lock, flags);
-       }
-
-       /* Perform calibration if necessary */
-       if (longcal || shortcal) {
-               common->ani.caldone =
-                       ath9k_hw_calibrate(ah, ah->curchan,
-                                               ah->rxchainmask, longcal);
-       }
-
-       ath_dbg(common, ANI,
-               "Calibration @%lu finished: %s %s %s, caldone: %s\n",
-               jiffies,
-               longcal ? "long" : "", shortcal ? "short" : "",
-               aniflag ? "ani" : "", common->ani.caldone ? "true" : "false");
-
-       ath9k_ps_restore(sc);
-
-set_timer:
-       /*
-       * Set timer interval based on previous results.
-       * The interval must be the shortest necessary to satisfy ANI,
-       * short calibration and long calibration.
-       */
-       ath9k_debug_samp_bb_mac(sc);
-       cal_interval = ATH_LONG_CALINTERVAL;
-       if (sc->sc_ah->config.enable_ani)
-               cal_interval = min(cal_interval,
-                                  (u32)ah->config.ani_poll_interval);
-       if (!common->ani.caldone)
-               cal_interval = min(cal_interval, (u32)short_cal_interval);
-
-       mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
-               if (!ah->caldata->paprd_done)
-                       ieee80211_queue_work(sc->hw, &sc->paprd_work);
-               else if (!ah->paprd_table_write_done)
-                       ath_paprd_activate(sc);
-       }
-}
-
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
                            struct ieee80211_vif *vif)
 {
        struct ath_node *an;
+       u8 density;
        an = (struct ath_node *)sta->drv_priv;
 
 #ifdef CONFIG_ATH9K_DEBUGFS
@@ -649,7 +337,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
                ath_tx_node_init(sc, an);
                an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
                                     sta->ht_cap.ampdu_factor);
-               an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+               density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
+               an->mpdudensity = density;
        }
 }
 
@@ -668,13 +357,12 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
                ath_tx_node_cleanup(sc, an);
 }
 
-
 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);
-
+       unsigned long flags;
        u32 status = sc->intrstatus;
        u32 rxmask;
 
@@ -693,10 +381,12 @@ void ath9k_tasklet(unsigned long data)
 
                RESET_STAT_INC(sc, type);
 #endif
+               set_bit(SC_OP_HW_RESET, &sc->sc_flags);
                ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
                goto out;
        }
 
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
                 * TSF sync does not look correct; remain awake to sync with
@@ -705,6 +395,7 @@ void ath9k_tasklet(unsigned long data)
                ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
                sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
@@ -766,15 +457,17 @@ irqreturn_t ath_isr(int irq, void *dev)
         * touch anything. Note this can happen early
         * on if the IRQ is shared.
         */
-       if (sc->sc_flags & SC_OP_INVALID)
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return IRQ_NONE;
 
-
        /* shared irq, not for us */
 
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
 
+       if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+               return IRQ_HANDLED;
+
        /*
         * Figure out the reason(s) for the interrupt.  Note
         * that the hal returns a pseudo-ISR that may include
@@ -827,24 +520,6 @@ irqreturn_t ath_isr(int irq, void *dev)
                ath9k_hw_set_interrupts(ah);
        }
 
-       if (status & ATH9K_INT_MIB) {
-               /*
-                * Disable interrupts until we service the MIB
-                * interrupt; otherwise it will continue to
-                * fire.
-                */
-               ath9k_hw_disable_interrupts(ah);
-               /*
-                * Let the hal handle the event. We assume
-                * it will clear whatever condition caused
-                * the interrupt.
-                */
-               spin_lock(&common->cc_lock);
-               ath9k_hw_proc_mib_event(ah);
-               spin_unlock(&common->cc_lock);
-               ath9k_hw_enable_interrupts(ah);
-       }
-
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                if (status & ATH9K_INT_TIM_TIMER) {
                        if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
@@ -852,8 +527,10 @@ irqreturn_t ath_isr(int irq, void *dev)
                        /* Clear RxAbort bit so that we can
                         * receive frames */
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
+                       spin_lock(&sc->sc_pm_lock);
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                        sc->ps_flags |= PS_WAIT_FOR_BEACON;
+                       spin_unlock(&sc->sc_pm_lock);
                }
 
 chip_reset:
@@ -902,96 +579,6 @@ void ath_reset_work(struct work_struct *work)
        ath_reset(sc, true);
 }
 
-void ath_hw_check(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       unsigned long flags;
-       int busy;
-       u8 is_alive, nbeacon = 1;
-
-       ath9k_ps_wakeup(sc);
-       is_alive = ath9k_hw_check_alive(sc->sc_ah);
-
-       if (is_alive && !AR_SREV_9300(sc->sc_ah))
-               goto out;
-       else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
-               ath_dbg(common, RESET,
-                       "DCU stuck is detected. Schedule chip reset\n");
-               RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG);
-               goto sched_reset;
-       }
-
-       spin_lock_irqsave(&common->cc_lock, flags);
-       busy = ath_update_survey_stats(sc);
-       spin_unlock_irqrestore(&common->cc_lock, flags);
-
-       ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
-               busy, sc->hw_busy_count + 1);
-       if (busy >= 99) {
-               if (++sc->hw_busy_count >= 3) {
-                       RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
-                       goto sched_reset;
-               }
-       } else if (busy >= 0) {
-               sc->hw_busy_count = 0;
-               nbeacon = 3;
-       }
-
-       ath_start_rx_poll(sc, nbeacon);
-       goto out;
-
-sched_reset:
-       ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-out:
-       ath9k_ps_restore(sc);
-}
-
-static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
-{
-       static int count;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-       if (pll_sqsum >= 0x40000) {
-               count++;
-               if (count == 3) {
-                       /* Rx is hung for more than 500ms. Reset it */
-                       ath_dbg(common, RESET, "Possible RX hang, resetting\n");
-                       RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
-                       ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-                       count = 0;
-               }
-       } else
-               count = 0;
-}
-
-void ath_hw_pll_work(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                                           hw_pll_work.work);
-       u32 pll_sqsum;
-
-       /*
-        * ensure that the PLL WAR is executed only
-        * after the STA is associated (or) if the
-        * beaconing had started in interfaces that
-        * uses beacons.
-        */
-       if (!(sc->sc_flags & SC_OP_BEACONS))
-               return;
-
-       if (AR_SREV_9485(sc->sc_ah)) {
-
-               ath9k_ps_wakeup(sc);
-               pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
-               ath9k_ps_restore(sc);
-
-               ath_hw_pll_rx_hang_check(sc, pll_sqsum);
-
-               ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
-       }
-}
-
 /**********************/
 /* mac80211 callbacks */
 /**********************/
@@ -1054,10 +641,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ah->imask |= ATH9K_INT_CST;
 
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
-               ah->imask |= ATH9K_INT_MCI;
+       ath_mci_enable(sc);
 
-       sc->sc_flags &= ~SC_OP_INVALID;
+       clear_bit(SC_OP_INVALID, &sc->sc_flags);
        sc->sc_ah->is_monitoring = false;
 
        if (!ath_complete_reset(sc, false)) {
@@ -1099,6 +685,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_tx_control txctl;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       unsigned long flags;
 
        if (sc->ps_enabled) {
                /*
@@ -1121,6 +708,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                 * completed and if needed, also for RX of buffered frames.
                 */
                ath9k_ps_wakeup(sc);
+               spin_lock_irqsave(&sc->sc_pm_lock, flags);
                if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
                if (ieee80211_is_pspoll(hdr->frame_control)) {
@@ -1136,6 +724,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                 * the ps_flags bit is cleared. We are just dropping
                 * the ps_usecount here.
                 */
+               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
                ath9k_ps_restore(sc);
        }
 
@@ -1176,7 +765,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        ath_cancel_work(sc);
        del_timer_sync(&sc->rx_poll_timer);
 
-       if (sc->sc_flags & SC_OP_INVALID) {
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
@@ -1233,7 +822,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        ath9k_ps_restore(sc);
 
-       sc->sc_flags |= SC_OP_INVALID;
+       set_bit(SC_OP_INVALID, &sc->sc_flags);
        sc->ps_idle = prev_idle;
 
        mutex_unlock(&sc->mutex);
@@ -1337,11 +926,11 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
        /* Set op-mode & TSF */
        if (iter_data.naps > 0) {
                ath9k_hw_set_tsfadjust(ah, 1);
-               sc->sc_flags |= SC_OP_TSF_RESET;
+               set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
                ah->opmode = NL80211_IFTYPE_AP;
        } else {
                ath9k_hw_set_tsfadjust(ah, 0);
-               sc->sc_flags &= ~SC_OP_TSF_RESET;
+               clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 
                if (iter_data.nmeshes)
                        ah->opmode = NL80211_IFTYPE_MESH_POINT;
@@ -1356,14 +945,10 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
        /*
         * Enable MIB interrupts when there are hardware phy counters.
         */
-       if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) {
-               if (ah->config.enable_ani)
-                       ah->imask |= ATH9K_INT_MIB;
+       if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
                ah->imask |= ATH9K_INT_TSFOOR;
-       } else {
-               ah->imask &= ~ATH9K_INT_MIB;
+       else
                ah->imask &= ~ATH9K_INT_TSFOOR;
-       }
 
        ath9k_hw_set_interrupts(ah);
 
@@ -1372,12 +957,12 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
                if (!common->disable_ani) {
-                       sc->sc_flags |= SC_OP_ANI_RUN;
+                       set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        ath_start_ani(common);
                }
 
        } else {
-               sc->sc_flags &= ~SC_OP_ANI_RUN;
+               clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                del_timer_sync(&common->ani.timer);
        }
 }
@@ -1398,25 +983,6 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
        }
 }
 
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
-{
-       if (!AR_SREV_9300(sc->sc_ah))
-               return;
-
-       if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
-               return;
-
-       mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
-                       (nbeacon * sc->cur_beacon_conf.beacon_interval));
-}
-
-void ath_rx_poll(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *)data;
-
-       ieee80211_queue_work(sc->hw, &sc->hw_check_work);
-}
-
 static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif)
 {
@@ -1618,11 +1184,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                if (ah->curchan)
                        old_pos = ah->curchan - &ah->channels[0];
 
-               if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
-                       sc->sc_flags |= SC_OP_OFFCHANNEL;
-               else
-                       sc->sc_flags &= ~SC_OP_OFFCHANNEL;
-
                ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
                        curchan->center_freq, conf->channel_type);
 
@@ -1664,6 +1225,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
                        ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
+                       ath9k_ps_restore(sc);
                        return -EINVAL;
                }
 
@@ -1902,16 +1464,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
-
+       unsigned long flags;
        /*
         * Skip iteration if primary station vif's bss info
         * was not changed
         */
-       if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+       if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
                return;
 
        if (bss_conf->assoc) {
-               sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+               set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
                avp->primary_sta_vif = true;
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = bss_conf->aid;
@@ -1924,7 +1486,10 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
                 * on the receipt of the first Beacon frame (i.e.,
                 * after time sync with the AP).
                 */
+               spin_lock_irqsave(&sc->sc_pm_lock, flags);
                sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
                /* Reset rssi stats */
                sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -1932,7 +1497,7 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
                ath_start_rx_poll(sc, 3);
 
                if (!common->disable_ani) {
-                       sc->sc_flags |= SC_OP_ANI_RUN;
+                       set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        ath_start_ani(common);
                }
 
@@ -1952,7 +1517,8 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
        if (avp->primary_sta_vif && !bss_conf->assoc) {
                ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n",
                        common->curaid, common->curbssid);
-               sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+               clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
+               clear_bit(SC_OP_BEACONS, &sc->sc_flags);
                avp->primary_sta_vif = false;
                memset(common->curbssid, 0, ETH_ALEN);
                common->curaid = 0;
@@ -1965,10 +1531,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
         * None of station vifs are associated.
         * Clear bssid & aid
         */
-       if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
                ath9k_hw_write_associd(sc->sc_ah);
-               /* Stop ANI */
-               sc->sc_flags &= ~SC_OP_ANI_RUN;
+               clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                del_timer_sync(&common->ani.timer);
                del_timer_sync(&sc->rx_poll_timer);
                memset(&sc->caldata, 0, sizeof(sc->caldata));
@@ -2006,12 +1571,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
                        if (!common->disable_ani) {
-                               sc->sc_flags |= SC_OP_ANI_RUN;
+                               set_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                                ath_start_ani(common);
                        }
 
                } else {
-                       sc->sc_flags &= ~SC_OP_ANI_RUN;
+                       clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                        del_timer_sync(&common->ani.timer);
                        del_timer_sync(&sc->rx_poll_timer);
                }
@@ -2023,7 +1588,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
         */
        if ((changed & BSS_CHANGED_BEACON_INT) &&
            (vif->type == NL80211_IFTYPE_AP))
-               sc->sc_flags |= SC_OP_TSF_RESET;
+               set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
 
        /* Configure beaconing (AP, IBSS, MESH) */
        if (ath9k_uses_beacons(vif->type) &&
@@ -2215,7 +1780,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
                return;
        }
 
-       if (sc->sc_flags & SC_OP_INVALID) {
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
@@ -2380,6 +1945,134 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
        return 0;
 }
 
+#ifdef CONFIG_ATH9K_DEBUGFS
+
+/* Ethtool support for get-stats */
+
+#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
+static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "tx_pkts_nic",
+       "tx_bytes_nic",
+       "rx_pkts_nic",
+       "rx_bytes_nic",
+       AMKSTR(d_tx_pkts),
+       AMKSTR(d_tx_bytes),
+       AMKSTR(d_tx_mpdus_queued),
+       AMKSTR(d_tx_mpdus_completed),
+       AMKSTR(d_tx_mpdu_xretries),
+       AMKSTR(d_tx_aggregates),
+       AMKSTR(d_tx_ampdus_queued_hw),
+       AMKSTR(d_tx_ampdus_queued_sw),
+       AMKSTR(d_tx_ampdus_completed),
+       AMKSTR(d_tx_ampdu_retries),
+       AMKSTR(d_tx_ampdu_xretries),
+       AMKSTR(d_tx_fifo_underrun),
+       AMKSTR(d_tx_op_exceeded),
+       AMKSTR(d_tx_timer_expiry),
+       AMKSTR(d_tx_desc_cfg_err),
+       AMKSTR(d_tx_data_underrun),
+       AMKSTR(d_tx_delim_underrun),
+
+       "d_rx_decrypt_crc_err",
+       "d_rx_phy_err",
+       "d_rx_mic_err",
+       "d_rx_pre_delim_crc_err",
+       "d_rx_post_delim_crc_err",
+       "d_rx_decrypt_busy_err",
+
+       "d_rx_phyerr_radar",
+       "d_rx_phyerr_ofdm_timing",
+       "d_rx_phyerr_cck_timing",
+
+};
+#define ATH9K_SSTATS_LEN ARRAY_SIZE(ath9k_gstrings_stats)
+
+static void ath9k_get_et_strings(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                u32 sset, u8 *data)
+{
+       if (sset == ETH_SS_STATS)
+               memcpy(data, *ath9k_gstrings_stats,
+                      sizeof(ath9k_gstrings_stats));
+}
+
+static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif, int sset)
+{
+       if (sset == ETH_SS_STATS)
+               return ATH9K_SSTATS_LEN;
+       return 0;
+}
+
+#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
+#define AWDATA(elem)                                                   \
+       do {                                                            \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
+       } while (0)
+
+#define AWDATA_RX(elem)                                                \
+       do {                                                    \
+               data[i++] = sc->debug.stats.rxstats.elem;       \
+       } while (0)
+
+static void ath9k_get_et_stats(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ethtool_stats *stats, u64 *data)
+{
+       struct ath_softc *sc = hw->priv;
+       int i = 0;
+
+       data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
+       data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
+       AWDATA_RX(rx_pkts_all);
+       AWDATA_RX(rx_bytes_all);
+
+       AWDATA(tx_pkts_all);
+       AWDATA(tx_bytes_all);
+       AWDATA(queued);
+       AWDATA(completed);
+       AWDATA(xretries);
+       AWDATA(a_aggr);
+       AWDATA(a_queued_hw);
+       AWDATA(a_queued_sw);
+       AWDATA(a_completed);
+       AWDATA(a_retries);
+       AWDATA(a_xretries);
+       AWDATA(fifo_underrun);
+       AWDATA(xtxop);
+       AWDATA(timer_exp);
+       AWDATA(desc_cfg_err);
+       AWDATA(data_underrun);
+       AWDATA(delim_underrun);
+
+       AWDATA_RX(decrypt_crc_err);
+       AWDATA_RX(phy_err);
+       AWDATA_RX(mic_err);
+       AWDATA_RX(pre_delim_crc_err);
+       AWDATA_RX(post_delim_crc_err);
+       AWDATA_RX(decrypt_busy_err);
+
+       AWDATA_RX(phy_err_stats[ATH9K_PHYERR_RADAR]);
+       AWDATA_RX(phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]);
+       AWDATA_RX(phy_err_stats[ATH9K_PHYERR_CCK_TIMING]);
+
+       WARN_ON(i != ATH9K_SSTATS_LEN);
+}
+
+/* End of ethtool get-stats functions */
+
+#endif
+
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -2408,4 +2101,10 @@ struct ieee80211_ops ath9k_ops = {
        .get_stats          = ath9k_get_stats,
        .set_antenna        = ath9k_set_antenna,
        .get_antenna        = ath9k_get_antenna,
+
+#ifdef CONFIG_ATH9K_DEBUGFS
+       .get_et_sset_count  = ath9k_get_et_sset_count,
+       .get_et_stats  = ath9k_get_et_stats,
+       .get_et_strings  = ath9k_get_et_strings,
+#endif
 };
index 29fe52d6997350777afb8660f41910738fffedb4..64cc782587d811cb468ebf79210efc58cd983589 100644 (file)
@@ -20,7 +20,7 @@
 #include "ath9k.h"
 #include "mci.h"
 
-static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+static const u8 ath_mci_duty_cycle[] = { 55, 50, 60, 70, 80, 85, 90, 95, 98 };
 
 static struct ath_mci_profile_info*
 ath_mci_find_profile(struct ath_mci_profile *mci,
@@ -28,11 +28,14 @@ ath_mci_find_profile(struct ath_mci_profile *mci,
 {
        struct ath_mci_profile_info *entry;
 
+       if (list_empty(&mci->info))
+               return NULL;
+
        list_for_each_entry(entry, &mci->info, list) {
                if (entry->conn_handle == info->conn_handle)
-                       break;
+                       return entry;
        }
-       return entry;
+       return NULL;
 }
 
 static bool ath_mci_add_profile(struct ath_common *common,
@@ -49,31 +52,21 @@ static bool ath_mci_add_profile(struct ath_common *common,
            (info->type != MCI_GPM_COEX_PROFILE_VOICE))
                return false;
 
-       entry = ath_mci_find_profile(mci, info);
-
-       if (entry) {
-               memcpy(entry, info, 10);
-       } else {
-               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-               if (!entry)
-                       return false;
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry)
+               return false;
 
-               memcpy(entry, info, 10);
-               INC_PROF(mci, info);
-               list_add_tail(&info->list, &mci->info);
-       }
+       memcpy(entry, info, 10);
+       INC_PROF(mci, info);
+       list_add_tail(&entry->list, &mci->info);
 
        return true;
 }
 
 static void ath_mci_del_profile(struct ath_common *common,
                                struct ath_mci_profile *mci,
-                               struct ath_mci_profile_info *info)
+                               struct ath_mci_profile_info *entry)
 {
-       struct ath_mci_profile_info *entry;
-
-       entry = ath_mci_find_profile(mci, info);
-
        if (!entry)
                return;
 
@@ -86,12 +79,16 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci)
 {
        struct ath_mci_profile_info *info, *tinfo;
 
+       mci->aggr_limit = 0;
+
+       if (list_empty(&mci->info))
+               return;
+
        list_for_each_entry_safe(info, tinfo, &mci->info, list) {
                list_del(&info->list);
                DEC_PROF(mci, info);
                kfree(info);
        }
-       mci->aggr_limit = 0;
 }
 
 static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
@@ -116,42 +113,60 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
        struct ath_mci_profile_info *info;
        u32 num_profile = NUM_PROF(mci);
 
+       if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
+               goto skip_tuning;
+
+       btcoex->duty_cycle = ath_mci_duty_cycle[num_profile];
+
        if (num_profile == 1) {
                info = list_first_entry(&mci->info,
                                        struct ath_mci_profile_info,
                                        list);
-               if (mci->num_sco && info->T == 12) {
-                       mci->aggr_limit = 8;
+               if (mci->num_sco) {
+                       if (info->T == 12)
+                               mci->aggr_limit = 8;
+                       else if (info->T == 6) {
+                               mci->aggr_limit = 6;
+                               btcoex->duty_cycle = 30;
+                       }
                        ath_dbg(common, MCI,
-                               "Single SCO, aggregation limit 2 ms\n");
-               } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
-                          !info->master) {
-                       btcoex->btcoex_period = 60;
+                               "Single SCO, aggregation limit %d 1/4 ms\n",
+                               mci->aggr_limit);
+               } else if (mci->num_pan || mci->num_other_acl) {
+                       /*
+                        * For single PAN/FTP profile, allocate 35% for BT
+                        * to improve WLAN throughput.
+                        */
+                       btcoex->duty_cycle = 35;
+                       btcoex->btcoex_period = 53;
                        ath_dbg(common, MCI,
-                               "Single slave PAN/FTP, bt period 60 ms\n");
-               } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
-                        (info->T > 0 && info->T < 50) &&
-                        (info->A > 1 || info->W > 1)) {
+                               "Single PAN/FTP bt period %d ms dutycycle %d\n",
+                               btcoex->duty_cycle, btcoex->btcoex_period);
+               } else if (mci->num_hid) {
                        btcoex->duty_cycle = 30;
-                       mci->aggr_limit = 8;
+                       mci->aggr_limit = 6;
                        ath_dbg(common, MCI,
                                "Multiple attempt/timeout single HID "
-                               "aggregation limit 2 ms dutycycle 30%%\n");
+                               "aggregation limit 1.5 ms dutycycle 30%%\n");
                }
-       } else if ((num_profile == 2) && (mci->num_hid == 2)) {
-               btcoex->duty_cycle = 30;
-               mci->aggr_limit = 8;
-               ath_dbg(common, MCI,
-                       "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
-       } else if (num_profile > 3) {
+       } else if (num_profile == 2) {
+               if (mci->num_hid == 2)
+                       btcoex->duty_cycle = 30;
                mci->aggr_limit = 6;
                ath_dbg(common, MCI,
-                       "Three or more profiles aggregation limit 1.5 ms\n");
+                       "Two BT profiles aggr limit 1.5 ms dutycycle %d%%\n",
+                       btcoex->duty_cycle);
+       } else if (num_profile >= 3) {
+               mci->aggr_limit = 4;
+               ath_dbg(common, MCI,
+                       "Three or more profiles aggregation limit 1 ms\n");
        }
 
+skip_tuning:
        if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
                if (IS_CHAN_HT(sc->sc_ah->curchan))
                        ath_mci_adjust_aggr_limit(btcoex);
@@ -165,12 +180,11 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
        if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
                return;
 
-       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_BDR_DUTY_CYCLE : 0);
        if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
                btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
 
-       btcoex->btcoex_period *= 1000;
-       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period * 1000 *
                (100 - btcoex->duty_cycle) / 100;
 
        ath9k_hw_btcoex_enable(sc->sc_ah);
@@ -181,20 +195,16 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 payload[4] = {0, 0, 0, 0};
 
        switch (opcode) {
        case MCI_GPM_BT_CAL_REQ:
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL);
+               if (mci_hw->bt_state == MCI_BT_AWAKE) {
+                       ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-               } else {
-                       ath_dbg(common, MCI, "MCI State mismatch: %d\n",
-                               ar9003_mci_state(ah, MCI_STATE_BT, NULL));
                }
-               break;
-       case MCI_GPM_BT_CAL_DONE:
-               ar9003_mci_state(ah, MCI_STATE_BT, NULL);
+               ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
                break;
        case MCI_GPM_BT_CAL_GRANT:
                MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
@@ -207,32 +217,55 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        }
 }
 
+static void ath9k_mci_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc, mci_work);
+
+       ath_mci_update_scheme(sc);
+}
+
 static void ath_mci_process_profile(struct ath_softc *sc,
                                    struct ath_mci_profile_info *info)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info *entry = NULL;
+
+       entry = ath_mci_find_profile(mci, info);
+       if (entry) {
+               /*
+                * Two MCI interrupts are generated while connecting to
+                * headset and A2DP profile, but only one MCI interrupt
+                * is generated with last added profile type while disconnecting
+                * both profiles.
+                * So while adding second profile type decrement
+                * the first one.
+                */
+               if (entry->type != info->type) {
+                       DEC_PROF(mci, entry);
+                       INC_PROF(mci, info);
+               }
+               memcpy(entry, info, 10);
+       }
 
        if (info->start) {
-               if (!ath_mci_add_profile(common, mci, info))
+               if (!entry && !ath_mci_add_profile(common, mci, info))
                        return;
        } else
-               ath_mci_del_profile(common, mci, info);
+               ath_mci_del_profile(common, mci, entry);
 
        btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
        mci->aggr_limit = mci->num_sco ? 6 : 0;
 
-       if (NUM_PROF(mci)) {
+       btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+       if (NUM_PROF(mci))
                btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-               btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
-       } else {
+       else
                btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
                                                        ATH_BTCOEX_STOMP_LOW;
-               btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
-       }
 
-       ath_mci_update_scheme(sc);
+       ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_process_status(struct ath_softc *sc,
@@ -247,8 +280,6 @@ static void ath_mci_process_status(struct ath_softc *sc,
        if (status->is_link)
                return;
 
-       memset(&info, 0, sizeof(struct ath_mci_profile_info));
-
        info.conn_handle = status->conn_handle;
        if (ath_mci_find_profile(mci, &info))
                return;
@@ -268,7 +299,7 @@ static void ath_mci_process_status(struct ath_softc *sc,
        } while (++i < ATH_MCI_MAX_PROFILE);
 
        if (old_num_mgmt != mci->num_mgmt)
-               ath_mci_update_scheme(sc);
+               ieee80211_queue_work(sc->hw, &sc->mci_work);
 }
 
 static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
@@ -277,25 +308,20 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        struct ath_mci_profile_info profile_info;
        struct ath_mci_profile_status profile_status;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       u32 version;
-       u8 major;
-       u8 minor;
+       u8 major, minor;
        u32 seq_num;
 
        switch (opcode) {
        case MCI_GPM_COEX_VERSION_QUERY:
-               version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION,
-                                          NULL);
+               ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION);
                break;
        case MCI_GPM_COEX_VERSION_RESPONSE:
                major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
                minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
-               version = (major << 8) + minor;
-               version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION,
-                                          &version);
+               ar9003_mci_set_bt_version(ah, major, minor);
                break;
        case MCI_GPM_COEX_STATUS_QUERY:
-               ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL);
+               ar9003_mci_send_wlan_channels(ah);
                break;
        case MCI_GPM_COEX_BT_PROFILE_INFO:
                memcpy(&profile_info,
@@ -322,7 +348,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 
                seq_num = *((u32 *)(rx_payload + 12));
                ath_dbg(common, MCI,
-                       "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n",
+                       "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%u\n",
                        profile_status.is_link, profile_status.conn_handle,
                        profile_status.is_critical, seq_num);
 
@@ -362,6 +388,7 @@ int ath_mci_setup(struct ath_softc *sc)
                         mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
                         mci->sched_buf.bf_paddr);
 
+       INIT_WORK(&sc->mci_work, ath9k_mci_work);
        ath_dbg(common, MCI, "MCI Initialized\n");
 
        return 0;
@@ -389,6 +416,7 @@ void ath_mci_intr(struct ath_softc *sc)
        struct ath_mci_coex *mci = &sc->mci_coex;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 mci_int, mci_int_rxmsg;
        u32 offset, subtype, opcode;
        u32 *pgpm;
@@ -397,8 +425,8 @@ void ath_mci_intr(struct ath_softc *sc)
 
        ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
 
-       if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) {
-               ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
+       if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) {
+               ar9003_mci_get_next_gpm_offset(ah, true, NULL);
                return;
        }
 
@@ -417,46 +445,41 @@ void ath_mci_intr(struct ath_softc *sc)
                                        NULL, 0, true, false);
 
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
-               ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL);
+               ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE);
 
                /*
                 * always do this for recovery and 2G/5G toggling and LNA_TRANS
                 */
-               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL);
+               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
 
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) {
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-                           MCI_BT_SLEEP)
-                               ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE,
-                                                NULL);
-               }
+               if ((mci_hw->bt_state == MCI_BT_SLEEP) &&
+                   (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+                    MCI_BT_SLEEP))
+                       ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
 
-               if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) {
-                       if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) !=
-                           MCI_BT_AWAKE)
-                               ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP,
-                                                NULL);
-               }
+               if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
+                   (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
+                    MCI_BT_AWAKE))
+                       mci_hw->bt_state = MCI_BT_SLEEP;
        }
 
        if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
            (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
-               ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL);
+               ar9003_mci_state(ah, MCI_STATE_RECOVER_RX);
                skip_gpm = true;
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
-               offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET,
-                                         NULL);
+               offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET);
        }
 
        if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
@@ -465,8 +488,8 @@ void ath_mci_intr(struct ath_softc *sc)
                while (more_data == MCI_GPM_MORE) {
 
                        pgpm = mci->gpm_buf.bf_addr;
-                       offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
-                                                 &more_data);
+                       offset = ar9003_mci_get_next_gpm_offset(ah, false,
+                                                               &more_data);
 
                        if (offset == MCI_GPM_INVALID)
                                break;
@@ -507,23 +530,17 @@ void ath_mci_intr(struct ath_softc *sc)
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
 
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
-                       int value_dbm = ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_RSSI_POWER, NULL);
+                       int value_dbm = MS(mci_hw->cont_status,
+                                          AR_MCI_CONT_RSSI_POWER);
 
                        mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
 
-                       if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL))
-                               ath_dbg(common, MCI,
-                                       "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
-                                       ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_PRIORITY, NULL),
-                                       value_dbm);
-                       else
-                               ath_dbg(common, MCI,
-                                       "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n",
-                                       ar9003_mci_state(ah,
-                                                MCI_STATE_CONT_PRIORITY, NULL),
-                                       value_dbm);
+                       ath_dbg(common, MCI,
+                               "MCI CONT_INFO: (%s) pri = %d pwr = %d dBm\n",
+                               MS(mci_hw->cont_status, AR_MCI_CONT_TXRX) ?
+                               "tx" : "rx",
+                               MS(mci_hw->cont_status, AR_MCI_CONT_PRIORITY),
+                               value_dbm);
                }
 
                if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
@@ -538,3 +555,14 @@ void ath_mci_intr(struct ath_softc *sc)
                mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
                             AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
 }
+
+void ath_mci_enable(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       if (!common->btcoex_enabled)
+               return;
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
+               sc->sc_ah->imask |= ATH9K_INT_MCI;
+}
index c841444f53c2c91d2a02140c11f5cadf97f421c3..fc14eea034eb640c95d4332849c2646a176aa7e3 100644 (file)
@@ -130,4 +130,13 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci);
 int ath_mci_setup(struct ath_softc *sc);
 void ath_mci_cleanup(struct ath_softc *sc);
 void ath_mci_intr(struct ath_softc *sc);
-#endif
+
+#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
+void ath_mci_enable(struct ath_softc *sc);
+#else
+static inline void ath_mci_enable(struct ath_softc *sc)
+{
+}
+#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
+
+#endif /* MCI_H*/
index a856b51255f4aa0bc233c5af1176e667438324d8..aa0e83ac51f401ef650bcb64e63ec6c359906d9b 100644 (file)
@@ -115,6 +115,9 @@ static void ath_pci_aspm_init(struct ath_common *common)
        int pos;
        u8 aspm;
 
+       if (!ah->is_pciexpress)
+               return;
+
        pos = pci_pcie_cap(pdev);
        if (!pos)
                return;
@@ -138,6 +141,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
                aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
                pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm);
 
+               ath_info(common, "Disabling ASPM since BTCOEX is enabled\n");
                return;
        }
 
@@ -147,6 +151,7 @@ static void ath_pci_aspm_init(struct ath_common *common)
                ah->aspm_enabled = true;
                /* Initialize PCIe PM and SERDES registers. */
                ath9k_hw_configpcipowersave(ah, false);
+               ath_info(common, "ASPM enabled: 0x%x\n", aspm);
        }
 }
 
@@ -246,7 +251,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sc->mem = mem;
 
        /* Will be cleared in ath9k_start() */
-       sc->sc_flags |= SC_OP_INVALID;
+       set_bit(SC_OP_INVALID, &sc->sc_flags);
 
        ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
        if (ret) {
index 92a6c0a87f894167345a6c779e250de8388226ae..e034add9cd5a478a2dd085f5133a18898913b932 100644 (file)
@@ -770,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        struct ieee80211_tx_rate *rates = tx_info->control.rates;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
-       u8 try_per_rate, i = 0, rix, high_rix;
+       u8 try_per_rate, i = 0, rix;
        int is_probe = 0;
 
        if (rate_control_send_low(sta, priv_sta, txrc))
@@ -791,7 +791,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        rate_table = ath_rc_priv->rate_table;
        rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
                                     &is_probe, false);
-       high_rix = rix;
 
        /*
         * If we're in HT mode and both us and our peer supports LDPC.
@@ -839,16 +838,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        try_per_rate = 8;
 
        /*
-        * Use a legacy rate as last retry to ensure that the frame
-        * is tried in both MCS and legacy rates.
+        * If the last rate in the rate series is MCS and has
+        * more than 80% of per thresh, then use a legacy rate
+        * as last retry to ensure that the frame is tried in both
+        * MCS and legacy rate.
         */
-       if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
-           (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
-           (ath_rc_priv->per[high_rix] > 45)))
+       ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+       if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
+           (ath_rc_priv->per[rix] > 45))
                rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
                                &is_probe, true);
-       else
-               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
 
        /* All other rates in the series have RTS enabled */
        ath_rc_rate_set_series(rate_table, &rates[i], txrc,
index 0735aeb3b26cefcd15c2847a1775718d36cecbc6..6a7dd26f2a13770434a071879c9e2a172bd43f62 100644 (file)
 
 #define SKB_CB_ATHBUF(__skb)   (*((struct ath_buf **)__skb->cb))
 
-static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
-                                              int mindelta, int main_rssi_avg,
-                                              int alt_rssi_avg, int pkt_count)
-{
-       return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-               (alt_rssi_avg > main_rssi_avg + maxdelta)) ||
-               (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
-}
-
-static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
-                                       int curr_main_set, int curr_alt_set,
-                                       int alt_rssi_avg, int main_rssi_avg)
-{
-       bool result = false;
-       switch (div_group) {
-       case 0:
-               if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
-                       result = true;
-               break;
-       case 1:
-       case 2:
-               if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
-                       (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
-                               (alt_rssi_avg >= (main_rssi_avg - 5))) ||
-                       ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
-                       (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
-                               (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
-                                                       (alt_rssi_avg >= 4))
-                       result = true;
-               else
-                       result = false;
-               break;
-       }
-
-       return result;
-}
-
 static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
 {
        return sc->ps_enabled &&
@@ -303,7 +266,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
 
        ath_opmode_init(sc);
 
-       ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+       ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
 
        spin_unlock_bh(&sc->rx.rxbuflock);
 }
@@ -322,8 +285,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
        int error = 0;
 
        spin_lock_init(&sc->sc_pcu_lock);
-       sc->sc_flags &= ~SC_OP_RXFLUSH;
        spin_lock_init(&sc->rx.rxbuflock);
+       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 
        common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
                             sc->sc_ah->caps.rx_status_len;
@@ -500,7 +463,7 @@ int ath_startrecv(struct ath_softc *sc)
 
 start_recv:
        ath_opmode_init(sc);
-       ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+       ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
 
        spin_unlock_bh(&sc->rx.rxbuflock);
 
@@ -535,11 +498,11 @@ bool ath_stoprecv(struct ath_softc *sc)
 
 void ath_flushrecv(struct ath_softc *sc)
 {
-       sc->sc_flags |= SC_OP_RXFLUSH;
+       set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ath_rx_tasklet(sc, 1, true);
        ath_rx_tasklet(sc, 1, false);
-       sc->sc_flags &= ~SC_OP_RXFLUSH;
+       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 }
 
 static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
@@ -624,13 +587,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 
        /* Process Beacon and CAB receive in PS state */
        if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc))
-           && mybeacon)
+           && mybeacon) {
                ath_rx_ps_beacon(sc, skb);
-       else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
-                (ieee80211_is_data(hdr->frame_control) ||
-                 ieee80211_is_action(hdr->frame_control)) &&
-                is_multicast_ether_addr(hdr->addr1) &&
-                !ieee80211_has_moredata(hdr->frame_control)) {
+       else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
+                  (ieee80211_is_data(hdr->frame_control) ||
+                   ieee80211_is_action(hdr->frame_control)) &&
+                  is_multicast_ether_addr(hdr->addr1) &&
+                  !ieee80211_has_moredata(hdr->frame_control)) {
                /*
                 * No more broadcast/multicast frames to be received at this
                 * point.
@@ -1068,709 +1031,6 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
                rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
-static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
-                                     struct ath_hw_antcomb_conf ant_conf,
-                                     int main_rssi_avg)
-{
-       antcomb->quick_scan_cnt = 0;
-
-       if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
-               antcomb->rssi_lna2 = main_rssi_avg;
-       else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
-               antcomb->rssi_lna1 = main_rssi_avg;
-
-       switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
-       case 0x10: /* LNA2 A-B */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
-               break;
-       case 0x20: /* LNA1 A-B */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
-               break;
-       case 0x21: /* LNA1 LNA2 */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->second_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               break;
-       case 0x12: /* LNA2 LNA1 */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->second_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               break;
-       case 0x13: /* LNA2 A+B */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
-               break;
-       case 0x23: /* LNA1 A+B */
-               antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-               antcomb->first_quick_scan_conf =
-                       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-               antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
-               break;
-       default:
-               break;
-       }
-}
-
-static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
-                               struct ath_hw_antcomb_conf *div_ant_conf,
-                               int main_rssi_avg, int alt_rssi_avg,
-                               int alt_ratio)
-{
-       /* alt_good */
-       switch (antcomb->quick_scan_cnt) {
-       case 0:
-               /* set alt to main, and alt to first conf */
-               div_ant_conf->main_lna_conf = antcomb->main_conf;
-               div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
-               break;
-       case 1:
-               /* set alt to main, and alt to first conf */
-               div_ant_conf->main_lna_conf = antcomb->main_conf;
-               div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
-               antcomb->rssi_first = main_rssi_avg;
-               antcomb->rssi_second = alt_rssi_avg;
-
-               if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
-                       /* main is LNA1 */
-                       if (ath_is_alt_ant_ratio_better(alt_ratio,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-                                               main_rssi_avg, alt_rssi_avg,
-                                               antcomb->total_pkt_count))
-                               antcomb->first_ratio = true;
-                       else
-                               antcomb->first_ratio = false;
-               } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
-                       if (ath_is_alt_ant_ratio_better(alt_ratio,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-                                               main_rssi_avg, alt_rssi_avg,
-                                               antcomb->total_pkt_count))
-                               antcomb->first_ratio = true;
-                       else
-                               antcomb->first_ratio = false;
-               } else {
-                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-                           (alt_rssi_avg > main_rssi_avg +
-                           ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-                           (alt_rssi_avg > main_rssi_avg)) &&
-                           (antcomb->total_pkt_count > 50))
-                               antcomb->first_ratio = true;
-                       else
-                               antcomb->first_ratio = false;
-               }
-               break;
-       case 2:
-               antcomb->alt_good = false;
-               antcomb->scan_not_start = false;
-               antcomb->scan = false;
-               antcomb->rssi_first = main_rssi_avg;
-               antcomb->rssi_third = alt_rssi_avg;
-
-               if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
-                       antcomb->rssi_lna1 = alt_rssi_avg;
-               else if (antcomb->second_quick_scan_conf ==
-                        ATH_ANT_DIV_COMB_LNA2)
-                       antcomb->rssi_lna2 = alt_rssi_avg;
-               else if (antcomb->second_quick_scan_conf ==
-                        ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
-                       if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
-                               antcomb->rssi_lna2 = main_rssi_avg;
-                       else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
-                               antcomb->rssi_lna1 = main_rssi_avg;
-               }
-
-               if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
-                   ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
-                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
-               else
-                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
-
-               if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
-                       if (ath_is_alt_ant_ratio_better(alt_ratio,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-                                               main_rssi_avg, alt_rssi_avg,
-                                               antcomb->total_pkt_count))
-                               antcomb->second_ratio = true;
-                       else
-                               antcomb->second_ratio = false;
-               } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
-                       if (ath_is_alt_ant_ratio_better(alt_ratio,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
-                                               ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
-                                               main_rssi_avg, alt_rssi_avg,
-                                               antcomb->total_pkt_count))
-                               antcomb->second_ratio = true;
-                       else
-                               antcomb->second_ratio = false;
-               } else {
-                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-                           (alt_rssi_avg > main_rssi_avg +
-                           ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-                           (alt_rssi_avg > main_rssi_avg)) &&
-                           (antcomb->total_pkt_count > 50))
-                               antcomb->second_ratio = true;
-                       else
-                               antcomb->second_ratio = false;
-               }
-
-               /* set alt to the conf with maximun ratio */
-               if (antcomb->first_ratio && antcomb->second_ratio) {
-                       if (antcomb->rssi_second > antcomb->rssi_third) {
-                               /* first alt*/
-                               if ((antcomb->first_quick_scan_conf ==
-                                   ATH_ANT_DIV_COMB_LNA1) ||
-                                   (antcomb->first_quick_scan_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2))
-                                       /* Set alt LNA1 or LNA2*/
-                                       if (div_ant_conf->main_lna_conf ==
-                                           ATH_ANT_DIV_COMB_LNA2)
-                                               div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                                       else
-                                               div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                               else
-                                       /* Set alt to A+B or A-B */
-                                       div_ant_conf->alt_lna_conf =
-                                               antcomb->first_quick_scan_conf;
-                       } else if ((antcomb->second_quick_scan_conf ==
-                                  ATH_ANT_DIV_COMB_LNA1) ||
-                                  (antcomb->second_quick_scan_conf ==
-                                  ATH_ANT_DIV_COMB_LNA2)) {
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       } else {
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                       antcomb->second_quick_scan_conf;
-                       }
-               } else if (antcomb->first_ratio) {
-                       /* first alt */
-                       if ((antcomb->first_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->first_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA2))
-                                       /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                               antcomb->first_quick_scan_conf;
-               } else if (antcomb->second_ratio) {
-                               /* second alt */
-                       if ((antcomb->second_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->second_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA2))
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                               antcomb->second_quick_scan_conf;
-               } else {
-                       /* main is largest */
-                       if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf = antcomb->main_conf;
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
-               struct ath_ant_comb *antcomb, int alt_ratio)
-{
-       if (ant_conf->div_group == 0) {
-               /* Adjust the fast_div_bias based on main and alt lna conf */
-               switch ((ant_conf->main_lna_conf << 4) |
-                               ant_conf->alt_lna_conf) {
-               case 0x01: /* A-B LNA2 */
-                       ant_conf->fast_div_bias = 0x3b;
-                       break;
-               case 0x02: /* A-B LNA1 */
-                       ant_conf->fast_div_bias = 0x3d;
-                       break;
-               case 0x03: /* A-B A+B */
-                       ant_conf->fast_div_bias = 0x1;
-                       break;
-               case 0x10: /* LNA2 A-B */
-                       ant_conf->fast_div_bias = 0x7;
-                       break;
-               case 0x12: /* LNA2 LNA1 */
-                       ant_conf->fast_div_bias = 0x2;
-                       break;
-               case 0x13: /* LNA2 A+B */
-                       ant_conf->fast_div_bias = 0x7;
-                       break;
-               case 0x20: /* LNA1 A-B */
-                       ant_conf->fast_div_bias = 0x6;
-                       break;
-               case 0x21: /* LNA1 LNA2 */
-                       ant_conf->fast_div_bias = 0x0;
-                       break;
-               case 0x23: /* LNA1 A+B */
-                       ant_conf->fast_div_bias = 0x6;
-                       break;
-               case 0x30: /* A+B A-B */
-                       ant_conf->fast_div_bias = 0x1;
-                       break;
-               case 0x31: /* A+B LNA2 */
-                       ant_conf->fast_div_bias = 0x3b;
-                       break;
-               case 0x32: /* A+B LNA1 */
-                       ant_conf->fast_div_bias = 0x3d;
-                       break;
-               default:
-                       break;
-               }
-       } else if (ant_conf->div_group == 1) {
-               /* Adjust the fast_div_bias based on main and alt_lna_conf */
-               switch ((ant_conf->main_lna_conf << 4) |
-                       ant_conf->alt_lna_conf) {
-               case 0x01: /* A-B LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x02: /* A-B LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x03: /* A-B A+B */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x10: /* LNA2 A-B */
-                       if (!(antcomb->scan) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x3f;
-                       else
-                               ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x12: /* LNA2 LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x13: /* LNA2 A+B */
-                       if (!(antcomb->scan) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x3f;
-                       else
-                               ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x20: /* LNA1 A-B */
-                       if (!(antcomb->scan) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x3f;
-                       else
-                               ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x21: /* LNA1 LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x23: /* LNA1 A+B */
-                       if (!(antcomb->scan) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x3f;
-                       else
-                               ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x30: /* A+B A-B */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x31: /* A+B LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x32: /* A+B LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               default:
-                       break;
-               }
-       } else if (ant_conf->div_group == 2) {
-               /* Adjust the fast_div_bias based on main and alt_lna_conf */
-               switch ((ant_conf->main_lna_conf << 4) |
-                               ant_conf->alt_lna_conf) {
-               case 0x01: /* A-B LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x02: /* A-B LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x03: /* A-B A+B */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x10: /* LNA2 A-B */
-                       if (!(antcomb->scan) &&
-                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x1;
-                       else
-                               ant_conf->fast_div_bias = 0x2;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x12: /* LNA2 LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x13: /* LNA2 A+B */
-                       if (!(antcomb->scan) &&
-                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x1;
-                       else
-                               ant_conf->fast_div_bias = 0x2;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x20: /* LNA1 A-B */
-                       if (!(antcomb->scan) &&
-                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x1;
-                       else
-                               ant_conf->fast_div_bias = 0x2;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x21: /* LNA1 LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x23: /* LNA1 A+B */
-                       if (!(antcomb->scan) &&
-                               (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
-                               ant_conf->fast_div_bias = 0x1;
-                       else
-                               ant_conf->fast_div_bias = 0x2;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x30: /* A+B A-B */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x31: /* A+B LNA2 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               case 0x32: /* A+B LNA1 */
-                       ant_conf->fast_div_bias = 0x1;
-                       ant_conf->main_gaintb = 0;
-                       ant_conf->alt_gaintb = 0;
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
-/* Antenna diversity and combining */
-static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
-{
-       struct ath_hw_antcomb_conf div_ant_conf;
-       struct ath_ant_comb *antcomb = &sc->ant_comb;
-       int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
-       int curr_main_set;
-       int main_rssi = rs->rs_rssi_ctl0;
-       int alt_rssi = rs->rs_rssi_ctl1;
-       int rx_ant_conf,  main_ant_conf;
-       bool short_scan = false;
-
-       rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
-                      ATH_ANT_RX_MASK;
-       main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
-                        ATH_ANT_RX_MASK;
-
-       /* Record packet only when both main_rssi and  alt_rssi is positive */
-       if (main_rssi > 0 && alt_rssi > 0) {
-               antcomb->total_pkt_count++;
-               antcomb->main_total_rssi += main_rssi;
-               antcomb->alt_total_rssi  += alt_rssi;
-               if (main_ant_conf == rx_ant_conf)
-                       antcomb->main_recv_cnt++;
-               else
-                       antcomb->alt_recv_cnt++;
-       }
-
-       /* Short scan check */
-       if (antcomb->scan && antcomb->alt_good) {
-               if (time_after(jiffies, antcomb->scan_start_time +
-                   msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
-                       short_scan = true;
-               else
-                       if (antcomb->total_pkt_count ==
-                           ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
-                               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
-                                           antcomb->total_pkt_count);
-                               if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
-                                       short_scan = true;
-                       }
-       }
-
-       if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
-           rs->rs_moreaggr) && !short_scan)
-               return;
-
-       if (antcomb->total_pkt_count) {
-               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
-                            antcomb->total_pkt_count);
-               main_rssi_avg = (antcomb->main_total_rssi /
-                                antcomb->total_pkt_count);
-               alt_rssi_avg = (antcomb->alt_total_rssi /
-                                antcomb->total_pkt_count);
-       }
-
-
-       ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
-       curr_alt_set = div_ant_conf.alt_lna_conf;
-       curr_main_set = div_ant_conf.main_lna_conf;
-
-       antcomb->count++;
-
-       if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
-               if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
-                       ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
-                                                 main_rssi_avg);
-                       antcomb->alt_good = true;
-               } else {
-                       antcomb->alt_good = false;
-               }
-
-               antcomb->count = 0;
-               antcomb->scan = true;
-               antcomb->scan_not_start = true;
-       }
-
-       if (!antcomb->scan) {
-               if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
-                                       alt_ratio, curr_main_set, curr_alt_set,
-                                       alt_rssi_avg, main_rssi_avg)) {
-                       if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
-                               /* Switch main and alt LNA */
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                               div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                       } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       }
-
-                       goto div_comb_done;
-               } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
-                          (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
-                       /* Set alt to another LNA */
-                       if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                       else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-
-                       goto div_comb_done;
-               }
-
-               if ((alt_rssi_avg < (main_rssi_avg +
-                                               div_ant_conf.lna1_lna2_delta)))
-                       goto div_comb_done;
-       }
-
-       if (!antcomb->scan_not_start) {
-               switch (curr_alt_set) {
-               case ATH_ANT_DIV_COMB_LNA2:
-                       antcomb->rssi_lna2 = alt_rssi_avg;
-                       antcomb->rssi_lna1 = main_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A+B */
-                       div_ant_conf.main_lna_conf =
-                               ATH_ANT_DIV_COMB_LNA1;
-                       div_ant_conf.alt_lna_conf  =
-                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1:
-                       antcomb->rssi_lna1 = alt_rssi_avg;
-                       antcomb->rssi_lna2 = main_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A+B */
-                       div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
-                       div_ant_conf.alt_lna_conf  =
-                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
-                       antcomb->rssi_add = alt_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A-B */
-                       div_ant_conf.alt_lna_conf =
-                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
-                       antcomb->rssi_sub = alt_rssi_avg;
-                       antcomb->scan = false;
-                       if (antcomb->rssi_lna2 >
-                           (antcomb->rssi_lna1 +
-                           ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
-                               /* use LNA2 as main LNA */
-                               if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
-                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
-                                       /* set to A+B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                               } else if (antcomb->rssi_sub >
-                                          antcomb->rssi_lna1) {
-                                       /* set to A-B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                               } else {
-                                       /* set to LNA1 */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               }
-                       } else {
-                               /* use LNA1 as main LNA */
-                               if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
-                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
-                                       /* set to A+B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                               } else if (antcomb->rssi_sub >
-                                          antcomb->rssi_lna1) {
-                                       /* set to A-B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                               } else {
-                                       /* set to LNA2 */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                               }
-                       }
-                       break;
-               default:
-                       break;
-               }
-       } else {
-               if (!antcomb->alt_good) {
-                       antcomb->scan_not_start = false;
-                       /* Set alt to another LNA */
-                       if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                       } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       }
-                       goto div_comb_done;
-               }
-       }
-
-       ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
-                                          main_rssi_avg, alt_rssi_avg,
-                                          alt_ratio);
-
-       antcomb->quick_scan_cnt++;
-
-div_comb_done:
-       ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
-       ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
-
-       antcomb->scan_start_time = jiffies;
-       antcomb->total_pkt_count = 0;
-       antcomb->main_total_rssi = 0;
-       antcomb->alt_total_rssi = 0;
-       antcomb->main_recv_cnt = 0;
-       antcomb->alt_recv_cnt = 0;
-}
-
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
        struct ath_buf *bf;
@@ -1804,7 +1064,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 
        do {
                /* If handling rx interrupt and flush is in progress => exit */
-               if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
+               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
                        break;
 
                memset(&rs, 0, sizeof(rs));
@@ -1842,13 +1102,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                else
                        rs.is_mybeacon = false;
 
+               sc->rx.num_pkts++;
                ath_debug_stat_rx(sc, &rs);
 
                /*
                 * If we're asked to flush receive queue, directly
                 * chain it back at the queue without processing it.
                 */
-               if (sc->sc_flags & SC_OP_RXFLUSH) {
+               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
                        RX_STAT_INC(rx_drop_rxflush);
                        goto requeue_drop_frag;
                }
@@ -1969,7 +1230,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                        skb_trim(skb, skb->len - 8);
 
                spin_lock_irqsave(&sc->sc_pm_lock, flags);
-
                if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                     PS_WAIT_FOR_CAB |
                                     PS_WAIT_FOR_PSPOLL_DATA)) ||
index 458f81b4a7cb7406d3e98f0c7d455cec93206749..5046b282a93c5bbe3c9984b5ce9f4dd248860ad7 100644 (file)
@@ -2098,8 +2098,8 @@ enum {
 #define AR_MCI_CONT_STATUS                     0x1848
 #define AR_MCI_CONT_RSSI_POWER                 0x000000FF
 #define AR_MCI_CONT_RSSI_POWER_S               0
-#define AR_MCI_CONT_RRIORITY                   0x0000FF00
-#define AR_MCI_CONT_RRIORITY_S                 8
+#define AR_MCI_CONT_PRIORITY                   0x0000FF00
+#define AR_MCI_CONT_PRIORITY_S                 8
 #define AR_MCI_CONT_TXRX                       0x00010000
 #define AR_MCI_CONT_TXRX_S                     16
 
@@ -2162,10 +2162,6 @@ enum {
 #define AR_BTCOEX_CTRL_SPDT_POLARITY                   0x80000000
 #define AR_BTCOEX_CTRL_SPDT_POLARITY_S                 31
 
-#define AR_BTCOEX_WL_WEIGHTS0                          0x18b0
-#define AR_BTCOEX_WL_WEIGHTS1                          0x18b4
-#define AR_BTCOEX_WL_WEIGHTS2                          0x18b8
-#define AR_BTCOEX_WL_WEIGHTS3                          0x18bc
 #define AR_BTCOEX_MAX_TXPWR(_x)                                (0x18c0 + ((_x) << 2))
 #define AR_BTCOEX_WL_LNA                               0x1940
 #define AR_BTCOEX_RFGAIN_CTRL                          0x1944
@@ -2211,5 +2207,7 @@ enum {
 #define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT      0x00000fff
 #define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S    0
 
+#define AR_GLB_SWREG_DISCONT_MODE         0x2002c
+#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN   0x3
 
 #endif
index 4d571394c7a82523404db2d9ae3ef0ba0af760c6..cafb4a09729a804be6bda2709ff33d96ecb49013 100644 (file)
@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
 /* Aggregation logic */
 /*********************/
 
-static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
        __acquires(&txq->axq_lock)
 {
        spin_lock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
        __releases(&txq->axq_lock)
 {
        spin_unlock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
        __releases(&txq->axq_lock)
 {
        struct sk_buff_head q;
@@ -1165,6 +1165,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 {
        struct ath_atx_tid *txtid;
        struct ath_node *an;
+       u8 density;
 
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
@@ -1172,6 +1173,17 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
                return -EAGAIN;
 
+       /* update ampdu factor/density, they may have changed. This may happen
+        * in HT IBSS when a beacon with HT-info is received after the station
+        * has already been added.
+        */
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                    sta->ht_cap.ampdu_factor);
+               density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
+               an->mpdudensity = density;
+       }
+
        txtid->state |= AGGR_ADDBA_PROGRESS;
        txtid->paused = true;
        *ssn = txtid->seq_start = txtid->seq_next;
@@ -1526,7 +1538,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
        int i;
        u32 npend = 0;
 
-       if (sc->sc_flags & SC_OP_INVALID)
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return true;
 
        ath9k_hw_abort_tx_dma(ah);
@@ -1999,6 +2011,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        int q, padpos, padsize;
+       unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
 
@@ -2017,6 +2030,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                skb_pull(skb, padsize);
        }
 
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_dbg(common, PS,
@@ -2026,6 +2040,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                                        PS_WAIT_FOR_PSPOLL_DATA |
                                        PS_WAIT_FOR_TX_ACK));
        }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        q = skb_get_queue_mapping(skb);
        if (txq == sc->tx.txq_map[q]) {
@@ -2236,46 +2251,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        ath_txq_unlock_complete(sc, txq);
 }
 
-static void ath_tx_complete_poll_work(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                       tx_complete_work.work);
-       struct ath_txq *txq;
-       int i;
-       bool needreset = false;
-#ifdef CONFIG_ATH9K_DEBUGFS
-       sc->tx_complete_poll_work_seen++;
-#endif
-
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i)) {
-                       txq = &sc->tx.txq[i];
-                       ath_txq_lock(sc, txq);
-                       if (txq->axq_depth) {
-                               if (txq->axq_tx_inprogress) {
-                                       needreset = true;
-                                       ath_txq_unlock(sc, txq);
-                                       break;
-                               } else {
-                                       txq->axq_tx_inprogress = true;
-                               }
-                       }
-                       ath_txq_unlock_complete(sc, txq);
-               }
-
-       if (needreset) {
-               ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-                       "tx hung, resetting the chip\n");
-               RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
-               ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-       }
-
-       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
-                       msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
-}
-
-
-
 void ath_tx_tasklet(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
index cd9c9bc186d93099f56b8b912e905255ee7411c9..8b06ca56125eec60bd4b5370b46d978727cc169d 100644 (file)
@@ -1508,7 +1508,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
 
 static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
 {
-       b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+       b43legacyerr(wl, "You must go to http://wireless.kernel.org/en/users/"
                     "Drivers/b43#devicefirmware "
                     "and download the correct firmware (version 3).\n");
 }
index abb48032753b1d1b1a11ec1b1a67feb2a92c53f5..9d5170b6df50ec3f05902856684efab2149b09e8 100644 (file)
@@ -34,3 +34,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
                sdio_chip.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
                usb.o
+brcmfmac-$(CONFIG_BRCMDBG) += \
+               dhd_dbg.o
\ No newline at end of file
index 82f51dbd0d66449a8172b9c385fb00f8562f1d14..49765d34b4e0b43ac947aa360fb58d1fff88aa90 100644 (file)
@@ -44,6 +44,7 @@
 
 #define SDIO_DEVICE_ID_BROADCOM_4329   0x4329
 #define SDIO_DEVICE_ID_BROADCOM_4330   0x4330
+#define SDIO_DEVICE_ID_BROADCOM_4334   0x4334
 
 #define SDIO_FUNC1_BLOCKSIZE           64
 #define SDIO_FUNC2_BLOCKSIZE           512
@@ -52,6 +53,7 @@
 static const struct sdio_device_id brcmf_sdmmc_ids[] = {
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
        { /* end: all zeroes */ },
 };
 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
index 9f637014486e3d84b00a73cfd7fe5f8297761fd5..a11fe54f595091dbec82f57066a2be6bc29bf26c 100644 (file)
@@ -613,6 +613,9 @@ struct brcmf_pub {
        struct work_struct multicast_work;
        u8 macvalue[ETH_ALEN];
        atomic_t pend_8021x_cnt;
+#ifdef DEBUG
+       struct dentry *dbgfs_dir;
+#endif
 };
 
 struct brcmf_if_event {
index 366916494be402a90ffdc5654cc286f075bdc795..537f499cc5d26f1174747443e863f798177b3377 100644 (file)
@@ -36,6 +36,13 @@ struct dngl_stats {
        unsigned long multicast;        /* multicast packets received */
 };
 
+struct brcmf_bus_dcmd {
+       char *name;
+       char *param;
+       int param_len;
+       struct list_head list;
+};
+
 /* interface structure between common and bus layer */
 struct brcmf_bus {
        u8 type;                /* bus type */
@@ -50,6 +57,7 @@ struct brcmf_bus {
        unsigned long tx_realloc;       /* Tx packets realloced for headroom */
        struct dngl_stats dstats;       /* Stats for dongle-based data */
        u8 align;               /* bus alignment requirement */
+       struct list_head dcmd_list;
 
        /* interface functions pointers */
        /* Stop bus module: clear pending frames, disable data flow */
index 236cb9fa460c7fb5d9f2934bf91a91706d7b5362..2621dd3d7dcd9d3b6ac5ca05db587cdd94454011 100644 (file)
@@ -800,13 +800,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
        char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];      /*  Room for
                                 "event_msgs" + '\0' + bitvec  */
        char buf[128], *ptr;
-       u32 dongle_align = drvr->bus_if->align;
-       u32 glom = 0;
        u32 roaming = 1;
        uint bcn_timeout = 3;
        int scan_assoc_time = 40;
        int scan_unassoc_time = 40;
        int i;
+       struct brcmf_bus_dcmd *cmdlst;
+       struct list_head *cur, *q;
 
        mutex_lock(&drvr->proto_block);
 
@@ -827,17 +827,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
        /* Print fw version info */
        brcmf_dbg(ERROR, "Firmware version = %s\n", buf);
 
-       /* Match Host and Dongle rx alignment */
-       brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
-                   sizeof(iovbuf));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
-                                 sizeof(iovbuf));
-
-       /* disable glom option per default */
-       brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
-                                 sizeof(iovbuf));
-
        /* Setup timeout if Beacons are lost and roam is off to report
                 link down */
        brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
@@ -874,6 +863,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
                                                 0, true);
        }
 
+       /* set bus specific command if there is any */
+       list_for_each_safe(cur, q, &drvr->bus_if->dcmd_list) {
+               cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);
+               if (cmdlst->name && cmdlst->param && cmdlst->param_len) {
+                       brcmf_c_mkiovar(cmdlst->name, cmdlst->param,
+                                       cmdlst->param_len, iovbuf,
+                                       sizeof(iovbuf));
+                       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
+                                                iovbuf, sizeof(iovbuf));
+               }
+               list_del(cur);
+               kfree(cmdlst);
+       }
+
        mutex_unlock(&drvr->proto_block);
 
        return 0;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
new file mode 100644 (file)
index 0000000..7f89540
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * 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 <linux/debugfs.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/ieee80211.h>
+#include <linux/module.h>
+
+#include <defs.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "dhd.h"
+#include "dhd_bus.h"
+#include "dhd_dbg.h"
+
+static struct dentry *root_folder;
+
+void brcmf_debugfs_init(void)
+{
+       root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+       if (IS_ERR(root_folder))
+               root_folder = NULL;
+}
+
+void brcmf_debugfs_exit(void)
+{
+       if (!root_folder)
+               return;
+
+       debugfs_remove_recursive(root_folder);
+       root_folder = NULL;
+}
+
+int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+       if (!root_folder)
+               return -ENODEV;
+
+       drvr->dbgfs_dir = debugfs_create_dir(dev_name(drvr->dev), root_folder);
+       return PTR_RET(drvr->dbgfs_dir);
+}
+
+void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+       if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
+               debugfs_remove_recursive(drvr->dbgfs_dir);
+}
+
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
+{
+       return drvr->dbgfs_dir;
+}
+
+static
+ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data,
+                                       size_t count, loff_t *ppos)
+{
+       struct brcmf_sdio_count *sdcnt = f->private_data;
+       char buf[750];
+       int res;
+
+       /* only allow read from start */
+       if (*ppos > 0)
+               return 0;
+
+       res = scnprintf(buf, sizeof(buf),
+                       "intrcount:    %u\nlastintrs:    %u\n"
+                       "pollcnt:      %u\nregfails:     %u\n"
+                       "tx_sderrs:    %u\nfcqueued:     %u\n"
+                       "rxrtx:        %u\nrx_toolong:   %u\n"
+                       "rxc_errors:   %u\nrx_hdrfail:   %u\n"
+                       "rx_badhdr:    %u\nrx_badseq:    %u\n"
+                       "fc_rcvd:      %u\nfc_xoff:      %u\n"
+                       "fc_xon:       %u\nrxglomfail:   %u\n"
+                       "rxglomframes: %u\nrxglompkts:   %u\n"
+                       "f2rxhdrs:     %u\nf2rxdata:     %u\n"
+                       "f2txdata:     %u\nf1regdata:    %u\n"
+                       "tickcnt:      %u\ntx_ctlerrs:   %lu\n"
+                       "tx_ctlpkts:   %lu\nrx_ctlerrs:   %lu\n"
+                       "rx_ctlpkts:   %lu\nrx_readahead: %lu\n",
+                       sdcnt->intrcount, sdcnt->lastintrs,
+                       sdcnt->pollcnt, sdcnt->regfails,
+                       sdcnt->tx_sderrs, sdcnt->fcqueued,
+                       sdcnt->rxrtx, sdcnt->rx_toolong,
+                       sdcnt->rxc_errors, sdcnt->rx_hdrfail,
+                       sdcnt->rx_badhdr, sdcnt->rx_badseq,
+                       sdcnt->fc_rcvd, sdcnt->fc_xoff,
+                       sdcnt->fc_xon, sdcnt->rxglomfail,
+                       sdcnt->rxglomframes, sdcnt->rxglompkts,
+                       sdcnt->f2rxhdrs, sdcnt->f2rxdata,
+                       sdcnt->f2txdata, sdcnt->f1regdata,
+                       sdcnt->tickcnt, sdcnt->tx_ctlerrs,
+                       sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs,
+                       sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt);
+
+       return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_sdio_counter_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = brcmf_debugfs_sdio_counter_read
+};
+
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+                                    struct brcmf_sdio_count *sdcnt)
+{
+       struct dentry *dentry = drvr->dbgfs_dir;
+
+       if (!IS_ERR_OR_NULL(dentry))
+               debugfs_create_file("counters", S_IRUGO, dentry,
+                                   sdcnt, &brcmf_debugfs_sdio_counter_ops);
+}
index a2c4576cf9ff3fa50e303cf03d1c042a40b45f75..b784920532d31b3ae9deb1ca0453244efb010b39 100644 (file)
@@ -76,4 +76,63 @@ do {                                                                 \
 
 extern int brcmf_msg_level;
 
+/*
+ * hold counter variables used in brcmfmac sdio driver.
+ */
+struct brcmf_sdio_count {
+       uint intrcount;         /* Count of device interrupt callbacks */
+       uint lastintrs;         /* Count as of last watchdog timer */
+       uint pollcnt;           /* Count of active polls */
+       uint regfails;          /* Count of R_REG failures */
+       uint tx_sderrs;         /* Count of tx attempts with sd errors */
+       uint fcqueued;          /* Tx packets that got queued */
+       uint rxrtx;             /* Count of rtx requests (NAK to dongle) */
+       uint rx_toolong;        /* Receive frames too long to receive */
+       uint rxc_errors;        /* SDIO errors when reading control frames */
+       uint rx_hdrfail;        /* SDIO errors on header reads */
+       uint rx_badhdr;         /* Bad received headers (roosync?) */
+       uint rx_badseq;         /* Mismatched rx sequence number */
+       uint fc_rcvd;           /* Number of flow-control events received */
+       uint fc_xoff;           /* Number which turned on flow-control */
+       uint fc_xon;            /* Number which turned off flow-control */
+       uint rxglomfail;        /* Failed deglom attempts */
+       uint rxglomframes;      /* Number of glom frames (superframes) */
+       uint rxglompkts;        /* Number of packets from glom frames */
+       uint f2rxhdrs;          /* Number of header reads */
+       uint f2rxdata;          /* Number of frame data reads */
+       uint f2txdata;          /* Number of f2 frame writes */
+       uint f1regdata;         /* Number of f1 register accesses */
+       uint tickcnt;           /* Number of watchdog been schedule */
+       ulong tx_ctlerrs;       /* Err of sending ctrl frames */
+       ulong tx_ctlpkts;       /* Ctrl frames sent to dongle */
+       ulong rx_ctlerrs;       /* Err of processing rx ctrl frames */
+       ulong rx_ctlpkts;       /* Ctrl frames processed from dongle */
+       ulong rx_readahead_cnt; /* packets where header read-ahead was used */
+};
+
+struct brcmf_pub;
+#ifdef DEBUG
+void brcmf_debugfs_init(void);
+void brcmf_debugfs_exit(void);
+int brcmf_debugfs_attach(struct brcmf_pub *drvr);
+void brcmf_debugfs_detach(struct brcmf_pub *drvr);
+struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
+void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
+                                    struct brcmf_sdio_count *sdcnt);
+#else
+static inline void brcmf_debugfs_init(void)
+{
+}
+static inline void brcmf_debugfs_exit(void)
+{
+}
+static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
+{
+       return 0;
+}
+static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
+{
+}
+#endif
+
 #endif                         /* _BRCMF_DBG_H_ */
index 8933f9b31a9a64a7c2c3f5428aba47a4e85d88d5..57bf1d7ee80fc76591621f51ffd4fbdf56a656b7 100644 (file)
@@ -1007,6 +1007,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        drvr->bus_if->drvr = drvr;
        drvr->dev = dev;
 
+       /* create device debugfs folder */
+       brcmf_debugfs_attach(drvr);
+
        /* Attach and link in the protocol */
        ret = brcmf_proto_attach(drvr);
        if (ret != 0) {
@@ -1017,6 +1020,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
        INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
        INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
 
+       INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
+
        return ret;
 
 fail:
@@ -1123,6 +1128,7 @@ void brcmf_detach(struct device *dev)
                brcmf_proto_detach(drvr);
        }
 
+       brcmf_debugfs_detach(drvr);
        bus_if->drvr = NULL;
        kfree(drvr);
 }
@@ -1192,6 +1198,8 @@ exit:
 
 static void brcmf_driver_init(struct work_struct *work)
 {
+       brcmf_debugfs_init();
+
 #ifdef CONFIG_BRCMFMAC_SDIO
        brcmf_sdio_init();
 #endif
@@ -1219,6 +1227,7 @@ static void __exit brcmfmac_module_exit(void)
 #ifdef CONFIG_BRCMFMAC_USB
        brcmf_usb_exit();
 #endif
+       brcmf_debugfs_exit();
 }
 
 module_init(brcmfmac_module_init);
index 1dbf2be478c82e4adcec6d95046dedac13e9d389..5c868bac1c1c86a1c5b730fc549a4bbd92a98996 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/bcma/bcma.h>
+#include <linux/debugfs.h>
+#include <linux/vmalloc.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -48,6 +50,9 @@
 
 #define CBUF_LEN       (128)
 
+/* Device console log buffer state */
+#define CONSOLE_BUFFER_MAX     2024
+
 struct rte_log_le {
        __le32 buf;             /* Can't be pointer on (64-bit) hosts */
        __le32 buf_size;
@@ -281,7 +286,7 @@ struct rte_console {
  * Shared structure between dongle and the host.
  * The structure contains pointers to trap or assert information.
  */
-#define SDPCM_SHARED_VERSION       0x0002
+#define SDPCM_SHARED_VERSION       0x0003
 #define SDPCM_SHARED_VERSION_MASK  0x00FF
 #define SDPCM_SHARED_ASSERT_BUILT  0x0100
 #define SDPCM_SHARED_ASSERT        0x0200
@@ -428,6 +433,29 @@ struct brcmf_console {
        u8 *buf;                /* Log buffer (host copy) */
        uint last;              /* Last buffer read index */
 };
+
+struct brcmf_trap_info {
+       __le32          type;
+       __le32          epc;
+       __le32          cpsr;
+       __le32          spsr;
+       __le32          r0;     /* a1 */
+       __le32          r1;     /* a2 */
+       __le32          r2;     /* a3 */
+       __le32          r3;     /* a4 */
+       __le32          r4;     /* v1 */
+       __le32          r5;     /* v2 */
+       __le32          r6;     /* v3 */
+       __le32          r7;     /* v4 */
+       __le32          r8;     /* v5 */
+       __le32          r9;     /* sb/v6 */
+       __le32          r10;    /* sl/v7 */
+       __le32          r11;    /* fp/v8 */
+       __le32          r12;    /* ip */
+       __le32          r13;    /* sp */
+       __le32          r14;    /* lr */
+       __le32          pc;     /* r15 */
+};
 #endif                         /* DEBUG */
 
 struct sdpcm_shared {
@@ -439,6 +467,7 @@ struct sdpcm_shared {
        u32 console_addr;       /* Address of struct rte_console */
        u32 msgtrace_addr;
        u8 tag[32];
+       u32 brpt_addr;
 };
 
 struct sdpcm_shared_le {
@@ -450,6 +479,7 @@ struct sdpcm_shared_le {
        __le32 console_addr;    /* Address of struct rte_console */
        __le32 msgtrace_addr;
        u8 tag[32];
+       __le32 brpt_addr;
 };
 
 
@@ -502,12 +532,9 @@ struct brcmf_sdio {
        bool intr;              /* Use interrupts */
        bool poll;              /* Use polling */
        bool ipend;             /* Device interrupt is pending */
-       uint intrcount;         /* Count of device interrupt callbacks */
-       uint lastintrs;         /* Count as of last watchdog timer */
        uint spurious;          /* Count of spurious interrupts */
        uint pollrate;          /* Ticks between device polls */
        uint polltick;          /* Tick counter */
-       uint pollcnt;           /* Count of active polls */
 
 #ifdef DEBUG
        uint console_interval;
@@ -515,8 +542,6 @@ struct brcmf_sdio {
        uint console_addr;      /* Console address from shared struct */
 #endif                         /* DEBUG */
 
-       uint regfails;          /* Count of R_REG failures */
-
        uint clkstate;          /* State of sd and backplane clock(s) */
        bool activity;          /* Activity flag for clock down */
        s32 idletime;           /* Control for activity timeout */
@@ -531,33 +556,6 @@ struct brcmf_sdio {
 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
        bool usebufpool;
 
-       /* Some additional counters */
-       uint tx_sderrs;         /* Count of tx attempts with sd errors */
-       uint fcqueued;          /* Tx packets that got queued */
-       uint rxrtx;             /* Count of rtx requests (NAK to dongle) */
-       uint rx_toolong;        /* Receive frames too long to receive */
-       uint rxc_errors;        /* SDIO errors when reading control frames */
-       uint rx_hdrfail;        /* SDIO errors on header reads */
-       uint rx_badhdr;         /* Bad received headers (roosync?) */
-       uint rx_badseq;         /* Mismatched rx sequence number */
-       uint fc_rcvd;           /* Number of flow-control events received */
-       uint fc_xoff;           /* Number which turned on flow-control */
-       uint fc_xon;            /* Number which turned off flow-control */
-       uint rxglomfail;        /* Failed deglom attempts */
-       uint rxglomframes;      /* Number of glom frames (superframes) */
-       uint rxglompkts;        /* Number of packets from glom frames */
-       uint f2rxhdrs;          /* Number of header reads */
-       uint f2rxdata;          /* Number of frame data reads */
-       uint f2txdata;          /* Number of f2 frame writes */
-       uint f1regdata;         /* Number of f1 register accesses */
-       uint tickcnt;           /* Number of watchdog been schedule */
-       unsigned long tx_ctlerrs;       /* Err of sending ctrl frames */
-       unsigned long tx_ctlpkts;       /* Ctrl frames sent to dongle */
-       unsigned long rx_ctlerrs;       /* Err of processing rx ctrl frames */
-       unsigned long rx_ctlpkts;       /* Ctrl frames processed from dongle */
-       unsigned long rx_readahead_cnt; /* Number of packets where header
-                                        * read-ahead was used. */
-
        u8 *ctrl_frame_buf;
        u32 ctrl_frame_len;
        bool ctrl_frame_stat;
@@ -583,6 +581,7 @@ struct brcmf_sdio {
        u32 fw_ptr;
 
        bool txoff;             /* Transmit flow-controlled */
+       struct brcmf_sdio_count sdcnt;
 };
 
 /* clkstate */
@@ -945,7 +944,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
        if (ret == 0)
                w_sdreg32(bus, SMB_INT_ACK,
                          offsetof(struct sdpcmd_regs, tosbmailbox));
-       bus->f1regdata += 2;
+       bus->sdcnt.f1regdata += 2;
 
        /* Dongle recomposed rx frames, accept them again */
        if (hmb_data & HMB_DATA_NAKHANDLED) {
@@ -984,12 +983,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
                                                        HMB_DATA_FCDATA_SHIFT;
 
                if (fcbits & ~bus->flowcontrol)
-                       bus->fc_xoff++;
+                       bus->sdcnt.fc_xoff++;
 
                if (bus->flowcontrol & ~fcbits)
-                       bus->fc_xon++;
+                       bus->sdcnt.fc_xon++;
 
-               bus->fc_rcvd++;
+               bus->sdcnt.fc_rcvd++;
                bus->flowcontrol = fcbits;
        }
 
@@ -1021,7 +1020,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
 
        brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                         SFC_RF_TERM, &err);
-       bus->f1regdata++;
+       bus->sdcnt.f1regdata++;
 
        /* Wait until the packet has been flushed (device/FIFO stable) */
        for (lastrbc = retries = 0xffff; retries > 0; retries--) {
@@ -1029,7 +1028,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
                                      SBSDIO_FUNC1_RFRAMEBCHI, &err);
                lo = brcmf_sdio_regrb(bus->sdiodev,
                                      SBSDIO_FUNC1_RFRAMEBCLO, &err);
-               bus->f1regdata += 2;
+               bus->sdcnt.f1regdata += 2;
 
                if ((hi == 0) && (lo == 0))
                        break;
@@ -1047,11 +1046,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
                brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
 
        if (rtx) {
-               bus->rxrtx++;
+               bus->sdcnt.rxrtx++;
                err = w_sdreg32(bus, SMB_NAK,
                                offsetof(struct sdpcmd_regs, tosbmailbox));
 
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
                if (err == 0)
                        bus->rxskip = true;
        }
@@ -1243,7 +1242,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                  dlen);
                        errcode = -1;
                }
-               bus->f2rxdata++;
+               bus->sdcnt.f2rxdata++;
 
                /* On failure, kill the superframe, allow a couple retries */
                if (errcode < 0) {
@@ -1256,7 +1255,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               bus->rxglomfail++;
+                               bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
                        return 0;
@@ -1312,7 +1311,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                if (rxseq != seq) {
                        brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
                                  seq, rxseq);
-                       bus->rx_badseq++;
+                       bus->sdcnt.rx_badseq++;
                        rxseq = seq;
                }
 
@@ -1376,7 +1375,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               bus->rxglomfail++;
+                               bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
                        bus->nextlen = 0;
@@ -1402,7 +1401,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        if (rxseq != seq) {
                                brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
                                          seq, rxseq);
-                               bus->rx_badseq++;
+                               bus->sdcnt.rx_badseq++;
                                rxseq = seq;
                        }
                        rxseq++;
@@ -1441,8 +1440,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                        down(&bus->sdsem);
                }
 
-               bus->rxglomframes++;
-               bus->rxglompkts += bus->glom.qlen;
+               bus->sdcnt.rxglomframes++;
+               bus->sdcnt.rxglompkts += bus->glom.qlen;
        }
        return num;
 }
@@ -1526,7 +1525,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
                          len, len - doff, bus->sdiodev->bus_if->maxctl);
                bus->sdiodev->bus_if->dstats.rx_errors++;
-               bus->rx_toolong++;
+               bus->sdcnt.rx_toolong++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                goto done;
        }
@@ -1536,13 +1535,13 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                                bus->sdiodev->sbwad,
                                SDIO_FUNC_2,
                                F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
-       bus->f2rxdata++;
+       bus->sdcnt.f2rxdata++;
 
        /* Control frame failures need retransmission */
        if (sdret < 0) {
                brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
                          rdlen, sdret);
-               bus->rxc_errors++;
+               bus->sdcnt.rxc_errors++;
                brcmf_sdbrcm_rxfail(bus, true, true);
                goto done;
        }
@@ -1589,7 +1588,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
        /* Read the entire frame */
        sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                      SDIO_FUNC_2, F2SYNC, *pkt);
-       bus->f2rxdata++;
+       bus->sdcnt.f2rxdata++;
 
        if (sdret < 0) {
                brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
@@ -1630,7 +1629,7 @@ brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
        if ((u16)~(*len ^ check)) {
                brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
                          nextlen, *len, check);
-               bus->rx_badhdr++;
+               bus->sdcnt.rx_badhdr++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                goto fail;
        }
@@ -1746,7 +1745,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                                bus->nextlen = 0;
                        }
 
-                       bus->rx_readahead_cnt++;
+                       bus->sdcnt.rx_readahead_cnt++;
 
                        /* Handle Flow Control */
                        fcbits = SDPCM_FCMASK_VALUE(
@@ -1754,12 +1753,12 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
                        if (bus->flowcontrol != fcbits) {
                                if (~bus->flowcontrol & fcbits)
-                                       bus->fc_xoff++;
+                                       bus->sdcnt.fc_xoff++;
 
                                if (bus->flowcontrol & ~fcbits)
-                                       bus->fc_xon++;
+                                       bus->sdcnt.fc_xon++;
 
-                               bus->fc_rcvd++;
+                               bus->sdcnt.fc_rcvd++;
                                bus->flowcontrol = fcbits;
                        }
 
@@ -1767,7 +1766,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                        if (rxseq != seq) {
                                brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
                                          seq, rxseq);
-                               bus->rx_badseq++;
+                               bus->sdcnt.rx_badseq++;
                                rxseq = seq;
                        }
 
@@ -1814,11 +1813,11 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, bus->rxhdr,
                                              BRCMF_FIRSTREAD);
-               bus->f2rxhdrs++;
+               bus->sdcnt.f2rxhdrs++;
 
                if (sdret < 0) {
                        brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
-                       bus->rx_hdrfail++;
+                       bus->sdcnt.rx_hdrfail++;
                        brcmf_sdbrcm_rxfail(bus, true, true);
                        continue;
                }
@@ -1840,7 +1839,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                if ((u16) ~(len ^ check)) {
                        brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
                                  len, check);
-                       bus->rx_badhdr++;
+                       bus->sdcnt.rx_badhdr++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1861,7 +1860,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                if ((doff < SDPCM_HDRLEN) || (doff > len)) {
                        brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
                                  doff, len, SDPCM_HDRLEN, seq);
-                       bus->rx_badhdr++;
+                       bus->sdcnt.rx_badhdr++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1880,19 +1879,19 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
 
                if (bus->flowcontrol != fcbits) {
                        if (~bus->flowcontrol & fcbits)
-                               bus->fc_xoff++;
+                               bus->sdcnt.fc_xoff++;
 
                        if (bus->flowcontrol & ~fcbits)
-                               bus->fc_xon++;
+                               bus->sdcnt.fc_xon++;
 
-                       bus->fc_rcvd++;
+                       bus->sdcnt.fc_rcvd++;
                        bus->flowcontrol = fcbits;
                }
 
                /* Check and update sequence number */
                if (rxseq != seq) {
                        brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
-                       bus->rx_badseq++;
+                       bus->sdcnt.rx_badseq++;
                        rxseq = seq;
                }
 
@@ -1937,7 +1936,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                        brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
                                  len, rdlen);
                        bus->sdiodev->bus_if->dstats.rx_errors++;
-                       bus->rx_toolong++;
+                       bus->sdcnt.rx_toolong++;
                        brcmf_sdbrcm_rxfail(bus, false, false);
                        continue;
                }
@@ -1960,7 +1959,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
                /* Read the remaining frame data */
                sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, pkt);
-               bus->f2rxdata++;
+               bus->sdcnt.f2rxdata++;
 
                if (sdret < 0) {
                        brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
@@ -2147,18 +2146,18 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
 
        ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                    SDIO_FUNC_2, F2SYNC, pkt);
-       bus->f2txdata++;
+       bus->sdcnt.f2txdata++;
 
        if (ret < 0) {
                /* On failure, abort the command and terminate the frame */
                brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                          ret);
-               bus->tx_sderrs++;
+               bus->sdcnt.tx_sderrs++;
 
                brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
                brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                 SFC_WF_TERM, NULL);
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
@@ -2166,7 +2165,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
                        lo = brcmf_sdio_regrb(bus->sdiodev,
                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->f1regdata += 2;
+                       bus->sdcnt.f1regdata += 2;
                        if ((hi == 0) && (lo == 0))
                                break;
                }
@@ -2224,7 +2223,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                        ret = r_sdreg32(bus, &intstatus,
                                        offsetof(struct sdpcmd_regs,
                                                 intstatus));
-                       bus->f2txdata++;
+                       bus->sdcnt.f2txdata++;
                        if (ret != 0)
                                break;
                        if (intstatus & bus->hostintmask)
@@ -2417,7 +2416,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                bus->ipend = false;
                err = r_sdreg32(bus, &newstatus,
                                offsetof(struct sdpcmd_regs, intstatus));
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
                if (err != 0)
                        newstatus = 0;
                newstatus &= bus->hostintmask;
@@ -2426,7 +2425,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                        err = w_sdreg32(bus, newstatus,
                                        offsetof(struct sdpcmd_regs,
                                                 intstatus));
-                       bus->f1regdata++;
+                       bus->sdcnt.f1regdata++;
                }
        }
 
@@ -2445,7 +2444,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
                err = r_sdreg32(bus, &newstatus,
                                offsetof(struct sdpcmd_regs, intstatus));
-               bus->f1regdata += 2;
+               bus->sdcnt.f1regdata += 2;
                bus->fcstate =
                    !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
                intstatus |= (newstatus & bus->hostintmask);
@@ -2510,13 +2509,13 @@ clkwait:
                                terminate the frame */
                        brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                                  ret);
-                       bus->tx_sderrs++;
+                       bus->sdcnt.tx_sderrs++;
 
                        brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
                        brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                         SFC_WF_TERM, &err);
-                       bus->f1regdata++;
+                       bus->sdcnt.f1regdata++;
 
                        for (i = 0; i < 3; i++) {
                                u8 hi, lo;
@@ -2526,7 +2525,7 @@ clkwait:
                                lo = brcmf_sdio_regrb(bus->sdiodev,
                                                      SBSDIO_FUNC1_WFRAMEBCLO,
                                                      &err);
-                               bus->f1regdata += 2;
+                               bus->sdcnt.f1regdata += 2;
                                if ((hi == 0) && (lo == 0))
                                        break;
                        }
@@ -2657,7 +2656,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        /* Check for existing queue, current flow-control,
                         pending event, or pending clock */
        brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
-       bus->fcqueued++;
+       bus->sdcnt.fcqueued++;
 
        /* Priority based enq */
        spin_lock_bh(&bus->txqlock);
@@ -2845,13 +2844,13 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
                /* On failure, abort the command and terminate the frame */
                brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
                          ret);
-               bus->tx_sderrs++;
+               bus->sdcnt.tx_sderrs++;
 
                brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
 
                brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
                                 SFC_WF_TERM, NULL);
-               bus->f1regdata++;
+               bus->sdcnt.f1regdata++;
 
                for (i = 0; i < 3; i++) {
                        u8 hi, lo;
@@ -2859,7 +2858,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
                        lo = brcmf_sdio_regrb(bus->sdiodev,
                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
-                       bus->f1regdata += 2;
+                       bus->sdcnt.f1regdata += 2;
                        if (hi == 0 && lo == 0)
                                break;
                }
@@ -2976,13 +2975,324 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
        up(&bus->sdsem);
 
        if (ret)
-               bus->tx_ctlerrs++;
+               bus->sdcnt.tx_ctlerrs++;
        else
-               bus->tx_ctlpkts++;
+               bus->sdcnt.tx_ctlpkts++;
 
        return ret ? -EIO : 0;
 }
 
+#ifdef DEBUG
+static inline bool brcmf_sdio_valid_shared_address(u32 addr)
+{
+       return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
+}
+
+static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
+                                struct sdpcm_shared *sh)
+{
+       u32 addr;
+       int rv;
+       u32 shaddr = 0;
+       struct sdpcm_shared_le sh_le;
+       __le32 addr_le;
+
+       shaddr = bus->ramsize - 4;
+
+       /*
+        * Read last word in socram to determine
+        * address of sdpcm_shared structure
+        */
+       rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
+                                  (u8 *)&addr_le, 4);
+       if (rv < 0)
+               return rv;
+
+       addr = le32_to_cpu(addr_le);
+
+       brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+
+       /*
+        * Check if addr is valid.
+        * NVRAM length at the end of memory should have been overwritten.
+        */
+       if (!brcmf_sdio_valid_shared_address(addr)) {
+                       brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n",
+                                 addr);
+                       return -EINVAL;
+       }
+
+       /* Read hndrte_shared structure */
+       rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
+                                  sizeof(struct sdpcm_shared_le));
+       if (rv < 0)
+               return rv;
+
+       /* Endianness */
+       sh->flags = le32_to_cpu(sh_le.flags);
+       sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
+       sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
+       sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
+       sh->assert_line = le32_to_cpu(sh_le.assert_line);
+       sh->console_addr = le32_to_cpu(sh_le.console_addr);
+       sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
+
+       if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
+               brcmf_dbg(ERROR,
+                         "sdpcm_shared version mismatch: dhd %d dongle %d\n",
+                         SDPCM_SHARED_VERSION,
+                         sh->flags & SDPCM_SHARED_VERSION_MASK);
+               return -EPROTO;
+       }
+
+       return 0;
+}
+
+static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
+                                  struct sdpcm_shared *sh, char __user *data,
+                                  size_t count)
+{
+       u32 addr, console_ptr, console_size, console_index;
+       char *conbuf = NULL;
+       __le32 sh_val;
+       int rv;
+       loff_t pos = 0;
+       int nbytes = 0;
+
+       /* obtain console information from device memory */
+       addr = sh->console_addr + offsetof(struct rte_console, log_le);
+       rv = brcmf_sdbrcm_membytes(bus, false, addr,
+                       (u8 *)&sh_val, sizeof(u32));
+       if (rv < 0)
+               return rv;
+       console_ptr = le32_to_cpu(sh_val);
+
+       addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
+       rv = brcmf_sdbrcm_membytes(bus, false, addr,
+                       (u8 *)&sh_val, sizeof(u32));
+       if (rv < 0)
+               return rv;
+       console_size = le32_to_cpu(sh_val);
+
+       addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
+       rv = brcmf_sdbrcm_membytes(bus, false, addr,
+                       (u8 *)&sh_val, sizeof(u32));
+       if (rv < 0)
+               return rv;
+       console_index = le32_to_cpu(sh_val);
+
+       /* allocate buffer for console data */
+       if (console_size <= CONSOLE_BUFFER_MAX)
+               conbuf = vzalloc(console_size+1);
+
+       if (!conbuf)
+               return -ENOMEM;
+
+       /* obtain the console data from device */
+       conbuf[console_size] = '\0';
+       rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
+                                  console_size);
+       if (rv < 0)
+               goto done;
+
+       rv = simple_read_from_buffer(data, count, &pos,
+                                    conbuf + console_index,
+                                    console_size - console_index);
+       if (rv < 0)
+               goto done;
+
+       nbytes = rv;
+       if (console_index > 0) {
+               pos = 0;
+               rv = simple_read_from_buffer(data+nbytes, count, &pos,
+                                            conbuf, console_index - 1);
+               if (rv < 0)
+                       goto done;
+               rv += nbytes;
+       }
+done:
+       vfree(conbuf);
+       return rv;
+}
+
+static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
+                               char __user *data, size_t count)
+{
+       int error, res;
+       char buf[350];
+       struct brcmf_trap_info tr;
+       int nbytes;
+       loff_t pos = 0;
+
+       if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
+               return 0;
+
+       error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
+                                     sizeof(struct brcmf_trap_info));
+       if (error < 0)
+               return error;
+
+       nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
+       if (nbytes < 0)
+               return nbytes;
+
+       res = scnprintf(buf, sizeof(buf),
+                       "dongle trap info: type 0x%x @ epc 0x%08x\n"
+                       "  cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
+                       "  lr   0x%08x pc   0x%08x offset 0x%x\n"
+                       "  r0   0x%08x r1   0x%08x r2 0x%08x r3 0x%08x\n"
+                       "  r4   0x%08x r5   0x%08x r6 0x%08x r7 0x%08x\n",
+                       le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
+                       le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
+                       le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
+                       le32_to_cpu(tr.pc), sh->trap_addr,
+                       le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
+                       le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
+                       le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
+                       le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
+
+       error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
+       if (error < 0)
+               return error;
+
+       nbytes += error;
+       return nbytes;
+}
+
+static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
+                                 struct sdpcm_shared *sh, char __user *data,
+                                 size_t count)
+{
+       int error = 0;
+       char buf[200];
+       char file[80] = "?";
+       char expr[80] = "<???>";
+       int res;
+       loff_t pos = 0;
+
+       if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+               brcmf_dbg(INFO, "firmware not built with -assert\n");
+               return 0;
+       } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
+               brcmf_dbg(INFO, "no assert in dongle\n");
+               return 0;
+       }
+
+       if (sh->assert_file_addr != 0) {
+               error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
+                                             (u8 *)file, 80);
+               if (error < 0)
+                       return error;
+       }
+       if (sh->assert_exp_addr != 0) {
+               error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
+                                             (u8 *)expr, 80);
+               if (error < 0)
+                       return error;
+       }
+
+       res = scnprintf(buf, sizeof(buf),
+                       "dongle assert: %s:%d: assert(%s)\n",
+                       file, sh->assert_line, expr);
+       return simple_read_from_buffer(data, count, &pos, buf, res);
+}
+
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+       int error;
+       struct sdpcm_shared sh;
+
+       down(&bus->sdsem);
+       error = brcmf_sdio_readshared(bus, &sh);
+       up(&bus->sdsem);
+
+       if (error < 0)
+               return error;
+
+       if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
+               brcmf_dbg(INFO, "firmware not built with -assert\n");
+       else if (sh.flags & SDPCM_SHARED_ASSERT)
+               brcmf_dbg(ERROR, "assertion in dongle\n");
+
+       if (sh.flags & SDPCM_SHARED_TRAP)
+               brcmf_dbg(ERROR, "firmware trap in dongle\n");
+
+       return 0;
+}
+
+static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
+                                 size_t count, loff_t *ppos)
+{
+       int error = 0;
+       struct sdpcm_shared sh;
+       int nbytes = 0;
+       loff_t pos = *ppos;
+
+       if (pos != 0)
+               return 0;
+
+       down(&bus->sdsem);
+       error = brcmf_sdio_readshared(bus, &sh);
+       if (error < 0)
+               goto done;
+
+       error = brcmf_sdio_assert_info(bus, &sh, data, count);
+       if (error < 0)
+               goto done;
+
+       nbytes = error;
+       error = brcmf_sdio_trap_info(bus, &sh, data, count);
+       if (error < 0)
+               goto done;
+
+       error += nbytes;
+       *ppos += error;
+done:
+       up(&bus->sdsem);
+       return error;
+}
+
+static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
+                                       size_t count, loff_t *ppos)
+{
+       struct brcmf_sdio *bus = f->private_data;
+       int res;
+
+       res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
+       if (res > 0)
+               *ppos += res;
+       return (ssize_t)res;
+}
+
+static const struct file_operations brcmf_sdio_forensic_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = brcmf_sdio_forensic_read
+};
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+       struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+       struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
+
+       if (IS_ERR_OR_NULL(dentry))
+               return;
+
+       debugfs_create_file("forensics", S_IRUGO, dentry, bus,
+                           &brcmf_sdio_forensic_ops);
+       brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
+}
+#else
+static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
+{
+       return 0;
+}
+
+static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
+{
+}
+#endif /* DEBUG */
+
 static int
 brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
 {
@@ -3009,60 +3319,27 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
                          rxlen, msglen);
        } else if (timeleft == 0) {
                brcmf_dbg(ERROR, "resumed on timeout\n");
+               brcmf_sdbrcm_checkdied(bus);
        } else if (pending) {
                brcmf_dbg(CTL, "cancelled\n");
                return -ERESTARTSYS;
        } else {
                brcmf_dbg(CTL, "resumed for unknown reason?\n");
+               brcmf_sdbrcm_checkdied(bus);
        }
 
        if (rxlen)
-               bus->rx_ctlpkts++;
+               bus->sdcnt.rx_ctlpkts++;
        else
-               bus->rx_ctlerrs++;
+               bus->sdcnt.rx_ctlerrs++;
 
        return rxlen ? (int)rxlen : -ETIMEDOUT;
 }
 
-static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len)
-{
-       int bcmerror = 0;
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       /* Basic sanity checks */
-       if (bus->sdiodev->bus_if->drvr_up) {
-               bcmerror = -EISCONN;
-               goto err;
-       }
-       if (!len) {
-               bcmerror = -EOVERFLOW;
-               goto err;
-       }
-
-       /* Free the old ones and replace with passed variables */
-       kfree(bus->vars);
-
-       bus->vars = kmalloc(len, GFP_ATOMIC);
-       bus->varsz = bus->vars ? len : 0;
-       if (bus->vars == NULL) {
-               bcmerror = -ENOMEM;
-               goto err;
-       }
-
-       /* Copy the passed variables, which should include the
-                terminating double-null */
-       memcpy(bus->vars, arg, bus->varsz);
-err:
-       return bcmerror;
-}
-
 static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
 {
        int bcmerror = 0;
-       u32 varsize;
        u32 varaddr;
-       u8 *vbuffer;
        u32 varsizew;
        __le32 varsizew_le;
 #ifdef DEBUG
@@ -3071,56 +3348,44 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
 
        /* Even if there are no vars are to be written, we still
                 need to set the ramsize. */
-       varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
-       varaddr = (bus->ramsize - 4) - varsize;
+       varaddr = (bus->ramsize - 4) - bus->varsz;
 
        if (bus->vars) {
-               vbuffer = kzalloc(varsize, GFP_ATOMIC);
-               if (!vbuffer)
-                       return -ENOMEM;
-
-               memcpy(vbuffer, bus->vars, bus->varsz);
-
                /* Write the vars list */
-               bcmerror =
-                   brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
+               bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr,
+                                                bus->vars, bus->varsz);
 #ifdef DEBUG
                /* Verify NVRAM bytes */
-               brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
-               nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
-               if (!nvram_ularray) {
-                       kfree(vbuffer);
+               brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n",
+                         bus->varsz);
+               nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC);
+               if (!nvram_ularray)
                        return -ENOMEM;
-               }
 
                /* Upload image to verify downloaded contents. */
-               memset(nvram_ularray, 0xaa, varsize);
+               memset(nvram_ularray, 0xaa, bus->varsz);
 
                /* Read the vars list to temp buffer for comparison */
-               bcmerror =
-                   brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
-                                    varsize);
+               bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr,
+                                                nvram_ularray, bus->varsz);
                if (bcmerror) {
                        brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
-                                 bcmerror, varsize, varaddr);
+                                 bcmerror, bus->varsz, varaddr);
                }
                /* Compare the org NVRAM with the one read from RAM */
-               if (memcmp(vbuffer, nvram_ularray, varsize))
+               if (memcmp(bus->vars, nvram_ularray, bus->varsz))
                        brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
                else
                        brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");
 
                kfree(nvram_ularray);
 #endif                         /* DEBUG */
-
-               kfree(vbuffer);
        }
 
        /* adjust to the user specified RAM */
        brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
        brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
-                 varaddr, varsize);
-       varsize = ((bus->ramsize - 4) - varaddr);
+                 varaddr, bus->varsz);
 
        /*
         * Determine the length token:
@@ -3131,13 +3396,13 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
                varsizew = 0;
                varsizew_le = cpu_to_le32(0);
        } else {
-               varsizew = varsize / 4;
+               varsizew = bus->varsz / 4;
                varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
                varsizew_le = cpu_to_le32(varsizew);
        }
 
        brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
-                 varsize, varsizew);
+                 bus->varsz, varsizew);
 
        /* Write the length token to the last word */
        bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
@@ -3261,13 +3526,21 @@ err:
  * by two NULs.
 */
 
-static uint brcmf_process_nvram_vars(char *varbuf, uint len)
+static int brcmf_process_nvram_vars(struct brcmf_sdio *bus)
 {
+       char *varbuf;
        char *dp;
        bool findNewline;
        int column;
-       uint buf_len, n;
+       int ret = 0;
+       uint buf_len, n, len;
 
+       len = bus->firmware->size;
+       varbuf = vmalloc(len);
+       if (!varbuf)
+               return -ENOMEM;
+
+       memcpy(varbuf, bus->firmware->data, len);
        dp = varbuf;
 
        findNewline = false;
@@ -3296,56 +3569,44 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len)
                column++;
        }
        buf_len = dp - varbuf;
-
        while (dp < varbuf + n)
                *dp++ = 0;
 
-       return buf_len;
+       kfree(bus->vars);
+       /* roundup needed for download to device */
+       bus->varsz = roundup(buf_len + 1, 4);
+       bus->vars = kmalloc(bus->varsz, GFP_KERNEL);
+       if (bus->vars == NULL) {
+               bus->varsz = 0;
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* copy the processed variables and add null termination */
+       memcpy(bus->vars, varbuf, buf_len);
+       bus->vars[buf_len] = 0;
+err:
+       vfree(varbuf);
+       return ret;
 }
 
 static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
 {
-       uint len;
-       char *memblock = NULL;
-       char *bufp;
        int ret;
 
+       if (bus->sdiodev->bus_if->drvr_up)
+               return -EISCONN;
+
        ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
                               &bus->sdiodev->func[2]->dev);
        if (ret) {
                brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
                return ret;
        }
-       bus->fw_ptr = 0;
-
-       memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
-       if (memblock == NULL) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
-
-       if (len > 0 && len < MEMBLOCK) {
-               bufp = (char *)memblock;
-               bufp[len] = 0;
-               len = brcmf_process_nvram_vars(bufp, len);
-               bufp += len;
-               *bufp++ = 0;
-               if (len)
-                       ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
-               if (ret)
-                       brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
-       } else {
-               brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
-               ret = -EIO;
-       }
 
-err:
-       kfree(memblock);
+       ret = brcmf_process_nvram_vars(bus);
 
        release_firmware(bus->firmware);
-       bus->fw_ptr = 0;
 
        return ret;
 }
@@ -3419,7 +3680,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
                return 0;
 
        /* Start the watchdog timer */
-       bus->tickcnt = 0;
+       bus->sdcnt.tickcnt = 0;
        brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
 
        down(&bus->sdsem);
@@ -3512,7 +3773,7 @@ void brcmf_sdbrcm_isr(void *arg)
                return;
        }
        /* Count the interrupt call */
-       bus->intrcount++;
+       bus->sdcnt.intrcount++;
        bus->ipend = true;
 
        /* Shouldn't get this interrupt if we're sleeping? */
@@ -3554,7 +3815,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                bus->polltick = 0;
 
                /* Check device if no interrupts */
-               if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+               if (!bus->intr ||
+                   (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
 
                        if (!bus->dpc_sched) {
                                u8 devpend;
@@ -3569,7 +3831,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                        /* If there is something, make like the ISR and
                                 schedule the DPC */
                        if (intstatus) {
-                               bus->pollcnt++;
+                               bus->sdcnt.pollcnt++;
                                bus->ipend = true;
 
                                bus->dpc_sched = true;
@@ -3581,7 +3843,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                }
 
                /* Update interrupt tracking */
-               bus->lastintrs = bus->intrcount;
+               bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
        }
 #ifdef DEBUG
        /* Poll for console output periodically */
@@ -3623,6 +3885,8 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid)
                return true;
        if (chipid == BCM4330_CHIP_ID)
                return true;
+       if (chipid == BCM4334_CHIP_ID)
+               return true;
        return false;
 }
 
@@ -3793,7 +4057,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)
                if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
                        brcmf_sdbrcm_bus_watchdog(bus);
                        /* Count the tick for reference */
-                       bus->tickcnt++;
+                       bus->sdcnt.tickcnt++;
                } else
                        break;
        }
@@ -3856,6 +4120,10 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
 {
        int ret;
        struct brcmf_sdio *bus;
+       struct brcmf_bus_dcmd *dlst;
+       u32 dngl_txglom;
+       u32 dngl_txglomalign;
+       u8 idx;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3938,8 +4206,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
                goto fail;
        }
 
+       brcmf_sdio_debugfs_create(bus);
        brcmf_dbg(INFO, "completed!!\n");
 
+       /* sdio bus core specific dcmd */
+       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+       dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL);
+       if (dlst) {
+               if (bus->ci->c_inf[idx].rev < 12) {
+                       /* for sdio core rev < 12, disable txgloming */
+                       dngl_txglom = 0;
+                       dlst->name = "bus:txglom";
+                       dlst->param = (char *)&dngl_txglom;
+                       dlst->param_len = sizeof(u32);
+               } else {
+                       /* otherwise, set txglomalign */
+                       dngl_txglomalign = bus->sdiodev->bus_if->align;
+                       dlst->name = "bus:txglomalign";
+                       dlst->param = (char *)&dngl_txglomalign;
+                       dlst->param_len = sizeof(u32);
+               }
+               list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list);
+       }
+
        /* if firmware path present try to download and bring up bus */
        ret = brcmf_bus_start(bus->sdiodev->dev);
        if (ret != 0) {
index f8e1f1c84d08eb6837e013b4c85216a34d24d268..58155e23d220fecc5f985be109901bbfce42070b 100644 (file)
@@ -403,6 +403,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
                ci->c_inf[3].cib = 0x03004211;
                ci->ramsize = 0x48000;
                break;
+       case BCM4334_CHIP_ID:
+               ci->c_inf[0].wrapbase = 0x18100000;
+               ci->c_inf[0].cib = 0x29004211;
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = 0x18002000;
+               ci->c_inf[1].wrapbase = 0x18102000;
+               ci->c_inf[1].cib = 0x0d004211;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = 0x18004000;
+               ci->c_inf[2].wrapbase = 0x18104000;
+               ci->c_inf[2].cib = 0x13080401;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = 0x18003000;
+               ci->c_inf[3].wrapbase = 0x18103000;
+               ci->c_inf[3].cib = 0x07004211;
+               ci->ramsize = 0x80000;
+               break;
        default:
                brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
                return -ENODEV;
index 6d8b7213643aa320dbb05edc026a4510620ef747..3c6f9b1e8d059176a26775d73f546254e14d22ed 100644 (file)
@@ -631,9 +631,8 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
        cc = sii->icbus->drv_cc.core;
 
        /* mask and set */
-       if (mask || val) {
+       if (mask || val)
                bcma_maskset32(cc, regoff, ~mask, val);
-       }
 
        /* readback */
        w = bcma_read32(cc, regoff);
index d9f04a683bdb30566c2385f9905a63affe478806..d6fa9829af9a58a7154de19b434ea5786def48dc 100644 (file)
@@ -193,7 +193,7 @@ extern void ai_detach(struct si_pub *sih);
 extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
 extern void ai_clkctl_init(struct si_pub *sih);
 extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
-extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
+extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode);
 extern bool ai_deviceremoved(struct si_pub *sih);
 
 extern void ai_pci_down(struct si_pub *sih);
index 95b5902bc4b3a3241f68cde20434b8592ba71ebc..01b190a25d947766ac2565ace38b6c9c096e7261 100644 (file)
@@ -735,10 +735,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                 * a candidate for aggregation
                 */
                p = pktq_ppeek(&qi->q, prec);
-               /* tx_info must be checked with current p */
-               tx_info = IEEE80211_SKB_CB(p);
-
                if (p) {
+                       tx_info = IEEE80211_SKB_CB(p);
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
                            ((u8) (p->priority) == tid)) {
                                plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
@@ -759,6 +757,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                                        p = NULL;
                                        continue;
                                }
+                               /* next packet fit for aggregation so dequeue */
                                p = brcmu_pktq_pdeq(&qi->q, prec);
                        } else {
                                p = NULL;
index eb77ac3cfb6b8cb227062a352552300681a32e43..2d365d3486df9722e5c1642aaf3252fd9c311ad3 100644 (file)
@@ -15,7 +15,9 @@
  */
 
 #include <linux/types.h>
+#include <net/cfg80211.h>
 #include <net/mac80211.h>
+#include <net/regulatory.h>
 
 #include <defs.h>
 #include "pub.h"
 #include "main.h"
 #include "stf.h"
 #include "channel.h"
+#include "mac80211_if.h"
 
 /* QDB() macro takes a dB value and converts to a quarter dB value */
 #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
 
-#define  LOCALE_CHAN_01_11      (1<<0)
-#define  LOCALE_CHAN_12_13      (1<<1)
-#define  LOCALE_CHAN_14                 (1<<2)
-#define  LOCALE_SET_5G_LOW_JP1   (1<<3)        /* 34-48, step 2 */
-#define  LOCALE_SET_5G_LOW_JP2   (1<<4)        /* 34-46, step 4 */
-#define  LOCALE_SET_5G_LOW1      (1<<5)        /* 36-48, step 4 */
-#define  LOCALE_SET_5G_LOW2      (1<<6)        /* 52 */
-#define  LOCALE_SET_5G_LOW3      (1<<7)        /* 56-64, step 4 */
-#define  LOCALE_SET_5G_MID1      (1<<8)        /* 100-116, step 4 */
-#define  LOCALE_SET_5G_MID2     (1<<9) /* 120-124, step 4 */
-#define  LOCALE_SET_5G_MID3      (1<<10)       /* 128 */
-#define  LOCALE_SET_5G_HIGH1     (1<<11)       /* 132-140, step 4 */
-#define  LOCALE_SET_5G_HIGH2     (1<<12)       /* 149-161, step 4 */
-#define  LOCALE_SET_5G_HIGH3     (1<<13)       /* 165 */
-#define  LOCALE_CHAN_52_140_ALL  (1<<14)
-#define  LOCALE_SET_5G_HIGH4     (1<<15)       /* 184-216 */
-
-#define  LOCALE_CHAN_36_64     (LOCALE_SET_5G_LOW1 | \
-                                LOCALE_SET_5G_LOW2 | \
-                                LOCALE_SET_5G_LOW3)
-#define  LOCALE_CHAN_52_64     (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define  LOCALE_CHAN_100_124   (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
-#define  LOCALE_CHAN_100_140   (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
-                                 LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
-#define  LOCALE_CHAN_149_165   (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
-#define  LOCALE_CHAN_184_216   LOCALE_SET_5G_HIGH4
-
-#define  LOCALE_CHAN_01_14     (LOCALE_CHAN_01_11 | \
-                                LOCALE_CHAN_12_13 | \
-                                LOCALE_CHAN_14)
-
-#define  LOCALE_RADAR_SET_NONE           0
-#define  LOCALE_RADAR_SET_1              1
-
-#define  LOCALE_RESTRICTED_NONE                  0
-#define  LOCALE_RESTRICTED_SET_2G_SHORT   1
-#define  LOCALE_RESTRICTED_CHAN_165       2
-#define  LOCALE_CHAN_ALL_5G              3
-#define  LOCALE_RESTRICTED_JAPAN_LEGACY   4
-#define  LOCALE_RESTRICTED_11D_2G        5
-#define  LOCALE_RESTRICTED_11D_5G        6
-#define  LOCALE_RESTRICTED_LOW_HI        7
-#define  LOCALE_RESTRICTED_12_13_14      8
-
-#define LOCALE_2G_IDX_i                        0
-#define LOCALE_5G_IDX_11               0
 #define LOCALE_MIMO_IDX_bn             0
 #define LOCALE_MIMO_IDX_11n            0
 
-/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
-#define BRCMS_MAXPWR_TBL_SIZE          6
 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
 #define BRCMS_MAXPWR_MIMO_TBL_SIZE     14
 
-/* power level in group of 2.4GHz band channels:
- * maxpwr[0] - CCK  channels [1]
- * maxpwr[1] - CCK  channels [2-10]
- * maxpwr[2] - CCK  channels [11-14]
- * maxpwr[3] - OFDM channels [1]
- * maxpwr[4] - OFDM channels [2-10]
- * maxpwr[5] - OFDM channels [11-14]
- */
-
 /* maxpwr mapping to 5GHz band channels:
  * maxpwr[0] - channels [34-48]
  * maxpwr[1] - channels [52-60]
 
 #define LC(id) LOCALE_MIMO_IDX_ ## id
 
-#define LC_2G(id)      LOCALE_2G_IDX_ ## id
-
-#define LC_5G(id)      LOCALE_5G_IDX_ ## id
-
-#define LOCALES(band2, band5, mimo2, mimo5) \
-               {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
-
-/* macro to get 2.4 GHz channel group index for tx power */
-#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
-#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
+#define LOCALES(mimo2, mimo5) \
+               {LC(mimo2), LC(mimo5)}
 
 /* macro to get 5 GHz channel group index for tx power */
 #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
                                 (((c) < 100) ? 2 : \
                                 (((c) < 149) ? 3 : 4))))
 
-#define ISDFS_EU(fl)           (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
-
-struct brcms_cm_band {
-       /* struct locale_info flags */
-       u8 locale_flags;
-       /* List of valid channels in the country */
-       struct brcms_chanvec valid_channels;
-       /* List of restricted use channels */
-       const struct brcms_chanvec *restricted_channels;
-       /* List of radar sensitive channels */
-       const struct brcms_chanvec *radar_channels;
-       u8 PAD[8];
+#define BRCM_2GHZ_2412_2462    REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+#define BRCM_2GHZ_2467_2472    REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+                                        NL80211_RRF_PASSIVE_SCAN | \
+                                        NL80211_RRF_NO_IBSS)
+
+#define BRCM_5GHZ_5180_5240    REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+                                        NL80211_RRF_PASSIVE_SCAN | \
+                                        NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5260_5320    REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+                                        NL80211_RRF_PASSIVE_SCAN | \
+                                        NL80211_RRF_DFS | \
+                                        NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5500_5700    REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+                                        NL80211_RRF_PASSIVE_SCAN | \
+                                        NL80211_RRF_DFS | \
+                                        NL80211_RRF_NO_IBSS)
+#define BRCM_5GHZ_5745_5825    REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+                                        NL80211_RRF_PASSIVE_SCAN | \
+                                        NL80211_RRF_NO_IBSS)
+
+static const struct ieee80211_regdomain brcms_regdom_x2 = {
+       .n_reg_rules = 7,
+       .alpha2 = "X2",
+       .reg_rules = {
+               BRCM_2GHZ_2412_2462,
+               BRCM_2GHZ_2467_2472,
+               BRCM_5GHZ_5180_5240,
+               BRCM_5GHZ_5260_5320,
+               BRCM_5GHZ_5500_5700,
+               BRCM_5GHZ_5745_5825,
+       }
 };
 
  /* locale per-channel tx power limits for MIMO frames
@@ -141,337 +98,23 @@ struct locale_mimo_info {
        s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
        /* tx 40 MHz power limits, qdBm units */
        s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
-       u8 flags;
 };
 
 /* Country names and abbreviations with locale defined from ISO 3166 */
 struct country_info {
-       const u8 locale_2G;     /* 2.4G band locale */
-       const u8 locale_5G;     /* 5G band locale */
        const u8 locale_mimo_2G;        /* 2.4G mimo info */
        const u8 locale_mimo_5G;        /* 5G mimo info */
 };
 
+struct brcms_regd {
+       struct country_info country;
+       const struct ieee80211_regdomain *regdomain;
+};
+
 struct brcms_cm_info {
        struct brcms_pub *pub;
        struct brcms_c_info *wlc;
-       char srom_ccode[BRCM_CNTRY_BUF_SZ];     /* Country Code in SROM */
-       uint srom_regrev;       /* Regulatory Rev for the SROM ccode */
-       const struct country_info *country;     /* current country def */
-       char ccode[BRCM_CNTRY_BUF_SZ];  /* current internal Country Code */
-       uint regrev;            /* current Regulatory Revision */
-       char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */
-       /* per-band state (one per phy/radio) */
-       struct brcms_cm_band bandstate[MAXBANDS];
-       /* quiet channels currently for radar sensitivity or 11h support */
-       /* channels on which we cannot transmit */
-       struct brcms_chanvec quiet_channels;
-};
-
-/* locale channel and power info. */
-struct locale_info {
-       u32 valid_channels;
-       /* List of radar sensitive channels */
-       u8 radar_channels;
-       /* List of channels used only if APs are detected */
-       u8 restricted_channels;
-       /* Max tx pwr in qdBm for each sub-band */
-       s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
-       /* Country IE advertised max tx pwr in dBm per sub-band */
-       s8 pub_maxpwr[BAND_5G_PWR_LVLS];
-       u8 flags;
-};
-
-/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
-
-/*
- * Some common channel sets
- */
-
-/* No channels */
-static const struct brcms_chanvec chanvec_none = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 2.4 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_2G = {
-       {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* All 5 GHz HW channels */
-static const struct brcms_chanvec chanvec_all_5G = {
-       {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
-        0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
-        0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
-        0x11, 0x11, 0x11, 0x01}
-};
-
-/*
- * Radar channel sets
- */
-
-/* Channels 52 - 64, 100 - 140 */
-static const struct brcms_chanvec radar_set1 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,  /* 52 - 60 */
-        0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,  /* 64, 100 - 124 */
-        0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 128 - 140 */
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/*
- * Restricted channel sets
- */
-
-/* Channels 34, 38, 42, 46 */
-static const struct brcms_chanvec restricted_set_japan_legacy = {
-       {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12, 13 */
-static const struct brcms_chanvec restricted_set_2g_short = {
-       {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channel 165 */
-static const struct brcms_chanvec restricted_chan_165 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 36 - 48 & 149 - 165 */
-static const struct brcms_chanvec restricted_low_hi = {
-       {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* Channels 12 - 14 */
-static const struct brcms_chanvec restricted_set_12_13_14 = {
-       {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-/* global memory to provide working buffer for expanded locale */
-
-static const struct brcms_chanvec *g_table_radar_set[] = {
-       &chanvec_none,
-       &radar_set1
-};
-
-static const struct brcms_chanvec *g_table_restricted_chan[] = {
-       &chanvec_none,          /* restricted_set_none */
-       &restricted_set_2g_short,
-       &restricted_chan_165,
-       &chanvec_all_5G,
-       &restricted_set_japan_legacy,
-       &chanvec_all_2G,        /* restricted_set_11d_2G */
-       &chanvec_all_5G,        /* restricted_set_11d_5G */
-       &restricted_low_hi,
-       &restricted_set_12_13_14
-};
-
-static const struct brcms_chanvec locale_2g_01_11 = {
-       {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_12_13 = {
-       {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_2g_14 = {
-       {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP1 = {
-       {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW_JP2 = {
-       {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW1 = {
-       {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW2 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_LOW3 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID1 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID2 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_MID3 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH1 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH2 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH3 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_52_140_ALL = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
-        0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
-        0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00}
-};
-
-static const struct brcms_chanvec locale_5g_HIGH4 = {
-       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
-        0x11, 0x11, 0x11, 0x11}
-};
-
-static const struct brcms_chanvec *g_table_locale_base[] = {
-       &locale_2g_01_11,
-       &locale_2g_12_13,
-       &locale_2g_14,
-       &locale_5g_LOW_JP1,
-       &locale_5g_LOW_JP2,
-       &locale_5g_LOW1,
-       &locale_5g_LOW2,
-       &locale_5g_LOW3,
-       &locale_5g_MID1,
-       &locale_5g_MID2,
-       &locale_5g_MID3,
-       &locale_5g_HIGH1,
-       &locale_5g_HIGH2,
-       &locale_5g_HIGH3,
-       &locale_5g_52_140_ALL,
-       &locale_5g_HIGH4
-};
-
-static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
-                                   const struct brcms_chanvec *channels)
-{
-       u8 i;
-       for (i = 0; i < sizeof(struct brcms_chanvec); i++)
-               target->vec[i] |= channels->vec[i];
-}
-
-static void brcms_c_locale_get_channels(const struct locale_info *locale,
-                                   struct brcms_chanvec *channels)
-{
-       u8 i;
-
-       memset(channels, 0, sizeof(struct brcms_chanvec));
-
-       for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
-               if (locale->valid_channels & (1 << i))
-                       brcms_c_locale_add_channels(channels,
-                                               g_table_locale_base[i]);
-       }
-}
-
-/*
- * Locale Definitions - 2.4 GHz
- */
-static const struct locale_info locale_i = {   /* locale i. channel 1 - 13 */
-       LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13,
-       LOCALE_RADAR_SET_NONE,
-       LOCALE_RESTRICTED_SET_2G_SHORT,
-       {QDB(19), QDB(19), QDB(19),
-        QDB(19), QDB(19), QDB(19)},
-       {20, 20, 20, 0},
-       BRCMS_EIRP
-};
-
-/*
- * Locale Definitions - 5 GHz
- */
-static const struct locale_info locale_11 = {
-       /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */
-       LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165,
-       LOCALE_RADAR_SET_1,
-       LOCALE_RESTRICTED_NONE,
-       {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)},
-       {23, 23, 23, 30, 30},
-       BRCMS_EIRP | BRCMS_DFS_EU
-};
-
-static const struct locale_info *g_locale_2g_table[] = {
-       &locale_i
-};
-
-static const struct locale_info *g_locale_5g_table[] = {
-       &locale_11
+       const struct brcms_regd *world_regd;
 };
 
 /*
@@ -484,7 +127,6 @@ static const struct locale_mimo_info locale_bn = {
        {0, 0, QDB(13), QDB(13), QDB(13),
         QDB(13), QDB(13), QDB(13), QDB(13), QDB(13),
         QDB(13), 0, 0},
-       0
 };
 
 static const struct locale_mimo_info *g_mimo_2g_table[] = {
@@ -497,114 +139,20 @@ static const struct locale_mimo_info *g_mimo_2g_table[] = {
 static const struct locale_mimo_info locale_11n = {
        { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)},
        {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)},
-       0
 };
 
 static const struct locale_mimo_info *g_mimo_5g_table[] = {
        &locale_11n
 };
 
-static const struct {
-       char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
-       struct country_info country;
-} cntry_locales[] = {
+static const struct brcms_regd cntry_locales[] = {
+       /* Worldwide RoW 2, must always be at index 0 */
        {
-       "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */
-};
-
-#ifdef SUPPORT_40MHZ
-/* 20MHz channel info for 40MHz pairing support */
-struct chan20_info {
-       u8 sb;
-       u8 adj_sbs;
+               .country = LOCALES(bn, 11n),
+               .regdomain = &brcms_regdom_x2,
+       },
 };
 
-/* indicates adjacent channels that are allowed for a 40 Mhz channel and
- * those that permitted by the HT
- */
-struct chan20_info chan20_info[] = {
-       /* 11b/11g */
-/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)},
-/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 11 */ {12, (CH_LOWER_SB)},
-/* 12 */ {13, (CH_LOWER_SB)},
-/* 13 */ {14, (CH_LOWER_SB)},
-
-/* 11a japan high */
-/* 14 */ {34, (CH_UPPER_SB)},
-/* 15 */ {38, (CH_LOWER_SB)},
-/* 16 */ {42, (CH_LOWER_SB)},
-/* 17 */ {46, (CH_LOWER_SB)},
-
-/* 11a usa low */
-/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)},
-
-/* 11a Europe */
-/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 36 */ {140, (CH_LOWER_SB)},
-
-/* 11a usa high, ref5 only */
-/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */
-/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)},
-/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)},
-/* 41 */ {165, (CH_LOWER_SB)},
-
-/* 11a japan */
-/* 42 */ {184, (CH_UPPER_SB)},
-/* 43 */ {188, (CH_LOWER_SB)},
-/* 44 */ {192, (CH_UPPER_SB)},
-/* 45 */ {196, (CH_LOWER_SB)},
-/* 46 */ {200, (CH_UPPER_SB)},
-/* 47 */ {204, (CH_LOWER_SB)},
-/* 48 */ {208, (CH_UPPER_SB)},
-/* 49 */ {212, (CH_LOWER_SB)},
-/* 50 */ {216, (CH_LOWER_SB)}
-};
-#endif                         /* SUPPORT_40MHZ */
-
-static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
-{
-       if (locale_idx >= ARRAY_SIZE(g_locale_2g_table))
-               return NULL; /* error condition */
-
-       return g_locale_2g_table[locale_idx];
-}
-
-static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
-{
-       if (locale_idx >= ARRAY_SIZE(g_locale_5g_table))
-               return NULL; /* error condition */
-
-       return g_locale_5g_table[locale_idx];
-}
-
 static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
 {
        if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
@@ -621,13 +169,6 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
        return g_mimo_5g_table[locale_idx];
 }
 
-static int
-brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
-                         char *mapped_ccode, uint *mapped_regrev)
-{
-       return false;
-}
-
 /*
  * Indicates whether the country provided is valid to pass
  * to cfg80211 or not.
@@ -662,155 +203,24 @@ static bool brcms_c_country_valid(const char *ccode)
        return true;
 }
 
-/* Lookup a country info structure from a null terminated country
- * abbreviation and regrev directly with no translation.
- */
-static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev)
+static const struct brcms_regd *brcms_world_regd(const char *regdom, int len)
 {
-       uint size, i;
-
-       /* Should just return 0 for single locale driver. */
-       /* Keep it this way in case we add more locales. (for now anyway) */
-
-       /*
-        * all other country def arrays are for regrev == 0, so if
-        * regrev is non-zero, fail
-        */
-       if (regrev > 0)
-               return NULL;
-
-       /* find matched table entry from country code */
-       size = ARRAY_SIZE(cntry_locales);
-       for (i = 0; i < size; i++) {
-               if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
-                       return &cntry_locales[i].country;
-       }
-       return NULL;
-}
-
-static const struct country_info *
-brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
-                       char *mapped_ccode, uint *mapped_regrev)
-{
-       struct brcms_c_info *wlc = wlc_cm->wlc;
-       const struct country_info *country;
-       uint srom_regrev = wlc_cm->srom_regrev;
-       const char *srom_ccode = wlc_cm->srom_ccode;
-       int mapped;
-
-       /* check for currently supported ccode size */
-       if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for "
-                         "match\n", wlc->pub->unit, __func__, ccode);
-               return NULL;
-       }
-
-       /* default mapping is the given ccode and regrev 0 */
-       strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
-       *mapped_regrev = 0;
-
-       /* If the desired country code matches the srom country code,
-        * then the mapped country is the srom regulatory rev.
-        * Otherwise look for an aggregate mapping.
-        */
-       if (!strcmp(srom_ccode, ccode)) {
-               *mapped_regrev = srom_regrev;
-               mapped = 0;
-               wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__);
-       } else {
-               mapped =
-                   brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode,
-                                             mapped_regrev);
-       }
-
-       /* find the matching built-in country definition */
-       country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-
-       /* if there is not an exact rev match, default to rev zero */
-       if (country == NULL && *mapped_regrev != 0) {
-               *mapped_regrev = 0;
-               country =
-                   brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev);
-       }
-
-       return country;
-}
-
-/* Lookup a country info structure from a null terminated country code
- * The lookup is case sensitive.
- */
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
-{
-       const struct country_info *country;
-       char mapped_ccode[BRCM_CNTRY_BUF_SZ];
-       uint mapped_regrev;
-
-       /*
-        * map the country code to a built-in country code, regrev, and
-        * country_info struct
-        */
-       country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
-                                         &mapped_regrev);
-
-       return country;
-}
-
-/*
- * reset the quiet channels vector to the union
- * of the restricted and radar channel sets
- */
-static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
-{
-       struct brcms_c_info *wlc = wlc_cm->wlc;
-       uint i, j;
-       struct brcms_band *band;
-       const struct brcms_chanvec *chanvec;
-
-       memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
-
-       band = wlc->band;
-       for (i = 0; i < wlc->pub->_nbands;
-            i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
-               /* initialize quiet channels for restricted channels */
-               chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
-               for (j = 0; j < sizeof(struct brcms_chanvec); j++)
-                       wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
+       const struct brcms_regd *regd = NULL;
+       int i;
 
+       for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) {
+               if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) {
+                       regd = &cntry_locales[i];
+                       break;
+               }
        }
-}
-
-/* Is the channel valid for the current locale and current band? */
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
-{
-       struct brcms_c_info *wlc = wlc_cm->wlc;
 
-       return ((val < MAXCHANNEL) &&
-               isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
-                     val));
+       return regd;
 }
 
-/* Is the channel valid for the current locale and specified band? */
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
-                                           uint bandunit, uint val)
-{
-       return ((val < MAXCHANNEL)
-               && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
-}
-
-/* Is the channel valid for the current locale? (but don't consider channels not
- *   available due to bandlocking)
- */
-static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
+static const struct brcms_regd *brcms_default_world_regd(void)
 {
-       struct brcms_c_info *wlc = wlc_cm->wlc;
-
-       return brcms_c_valid_channel20(wlc->cmi, val) ||
-               (!wlc->bandlocked
-                && brcms_c_valid_channel20_in_band(wlc->cmi,
-                                                   OTHERBANDUNIT(wlc), val));
+       return &cntry_locales[0];
 }
 
 /* JP, J1 - J10 are Japan ccodes */
@@ -820,12 +230,6 @@ static bool brcms_c_japan_ccode(const char *ccode)
                (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
 }
 
-/* Returns true if currently set country is Japan or variant */
-static bool brcms_c_japan(struct brcms_c_info *wlc)
-{
-       return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
-}
-
 static void
 brcms_c_channel_min_txpower_limits_with_local_constraint(
                struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
@@ -901,140 +305,16 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(
 
 }
 
-/* Update the radio state (enable/disable) and tx power targets
- * based on a new set of channel/regulatory information
- */
-static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
-{
-       struct brcms_c_info *wlc = wlc_cm->wlc;
-       uint chan;
-       struct txpwr_limits txpwr;
-
-       /* search for the existence of any valid channel */
-       for (chan = 0; chan < MAXCHANNEL; chan++) {
-               if (brcms_c_valid_channel20_db(wlc->cmi, chan))
-                       break;
-       }
-       if (chan == MAXCHANNEL)
-               chan = INVCHANNEL;
-
-       /*
-        * based on the channel search above, set or
-        * clear WL_RADIO_COUNTRY_DISABLE.
-        */
-       if (chan == INVCHANNEL) {
-               /*
-                * country/locale with no valid channels, set
-                * the radio disable bit
-                */
-               mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
-               wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
-                         "nbands %d bandlocked %d\n", wlc->pub->unit,
-                         __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
-                         wlc->bandlocked);
-       } else if (mboolisset(wlc->pub->radio_disabled,
-                             WL_RADIO_COUNTRY_DISABLE)) {
-               /*
-                * country/locale with valid channel, clear
-                * the radio disable bit
-                */
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
-       }
-
-       /*
-        * Now that the country abbreviation is set, if the radio supports 2G,
-        * then set channel 14 restrictions based on the new locale.
-        */
-       if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
-               wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
-                                                    brcms_c_japan(wlc) ? true :
-                                                    false);
-
-       if (wlc->pub->up && chan != INVCHANNEL) {
-               brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
-               brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
-                       &txpwr, BRCMS_TXPWR_MAX);
-               wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
-       }
-}
-
-static int
-brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
-                     const struct country_info *country)
-{
-       struct brcms_c_info *wlc = wlc_cm->wlc;
-       uint i, j;
-       struct brcms_band *band;
-       const struct locale_info *li;
-       struct brcms_chanvec sup_chan;
-       const struct locale_mimo_info *li_mimo;
-
-       band = wlc->band;
-       for (i = 0; i < wlc->pub->_nbands;
-            i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
-               li = (band->bandtype == BRCM_BAND_5G) ?
-                   brcms_c_get_locale_5g(country->locale_5G) :
-                   brcms_c_get_locale_2g(country->locale_2G);
-               wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
-               li_mimo = (band->bandtype == BRCM_BAND_5G) ?
-                   brcms_c_get_mimo_5g(country->locale_mimo_5G) :
-                   brcms_c_get_mimo_2g(country->locale_mimo_2G);
-
-               /* merge the mimo non-mimo locale flags */
-               wlc_cm->bandstate[band->bandunit].locale_flags |=
-                   li_mimo->flags;
-
-               wlc_cm->bandstate[band->bandunit].restricted_channels =
-                   g_table_restricted_chan[li->restricted_channels];
-               wlc_cm->bandstate[band->bandunit].radar_channels =
-                   g_table_radar_set[li->radar_channels];
-
-               /*
-                * set the channel availability, masking out the channels
-                * that may not be supported on this phy.
-                */
-               wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
-                                             &sup_chan);
-               brcms_c_locale_get_channels(li,
-                                       &wlc_cm->bandstate[band->bandunit].
-                                       valid_channels);
-               for (j = 0; j < sizeof(struct brcms_chanvec); j++)
-                       wlc_cm->bandstate[band->bandunit].valid_channels.
-                           vec[j] &= sup_chan.vec[j];
-       }
-
-       brcms_c_quiet_channels_reset(wlc_cm);
-       brcms_c_channels_commit(wlc_cm);
-
-       return 0;
-}
-
 /*
  * set the driver's current country and regulatory information
  * using a country code as the source. Look up built in country
  * information found with the country code.
  */
 static void
-brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
-                      const char *country_abbrev,
-                      const char *ccode, uint regrev,
-                      const struct country_info *country)
+brcms_c_set_country(struct brcms_cm_info *wlc_cm,
+                   const struct brcms_regd *regd)
 {
-       const struct locale_info *locale;
        struct brcms_c_info *wlc = wlc_cm->wlc;
-       char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
-
-       /* save current country state */
-       wlc_cm->country = country;
-
-       memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
-       strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
-               BRCM_CNTRY_BUF_SZ - 1);
-
-       strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
-       strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
-       wlc_cm->regrev = regrev;
 
        if ((wlc->pub->_n_enab & SUPPORT_11N) !=
            wlc->protection->nmode_user)
@@ -1042,75 +322,19 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
 
        brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
        brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
-       /* set or restore gmode as required by regulatory */
-       locale = brcms_c_get_locale_2g(country->locale_2G);
-       if (locale && (locale->flags & BRCMS_NO_OFDM))
-               brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
-       else
-               brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
-       brcms_c_channels_init(wlc_cm, country);
+       brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
        return;
 }
 
-static int
-brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
-                       const char *country_abbrev,
-                       const char *ccode, int regrev)
-{
-       const struct country_info *country;
-       char mapped_ccode[BRCM_CNTRY_BUF_SZ];
-       uint mapped_regrev;
-
-       /* if regrev is -1, lookup the mapped country code,
-        * otherwise use the ccode and regrev directly
-        */
-       if (regrev == -1) {
-               /*
-                * map the country code to a built-in country
-                * code, regrev, and country_info
-                */
-               country =
-                   brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
-                                       &mapped_regrev);
-       } else {
-               /* find the matching built-in country definition */
-               country = brcms_c_country_lookup_direct(ccode, regrev);
-               strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
-               mapped_regrev = regrev;
-       }
-
-       if (country == NULL)
-               return -EINVAL;
-
-       /* set the driver state for the country */
-       brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
-                              mapped_regrev, country);
-
-       return 0;
-}
-
-/*
- * set the driver's current country and regulatory information using
- * a country code as the source. Lookup built in country information
- * found with the country code.
- */
-static int
-brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
-{
-       char country_abbrev[BRCM_CNTRY_BUF_SZ];
-       strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
-       return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
-}
-
 struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
 {
        struct brcms_cm_info *wlc_cm;
-       char country_abbrev[BRCM_CNTRY_BUF_SZ];
-       const struct country_info *country;
        struct brcms_pub *pub = wlc->pub;
        struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
+       const char *ccode = sprom->alpha2;
+       int ccode_len = sizeof(sprom->alpha2);
 
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
@@ -1122,24 +346,27 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
        wlc->cmi = wlc_cm;
 
        /* store the country code for passing up as a regulatory hint */
-       if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
-               strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
+       wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);
+       if (brcms_c_country_valid(ccode))
+               strncpy(wlc->pub->srom_ccode, ccode, ccode_len);
 
        /*
-        * internal country information which must match
-        * regulatory constraints in firmware
+        * If no custom world domain is found in the SROM, use the
+        * default "X2" domain.
         */
-       memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
-       strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
-       country = brcms_c_country_lookup(wlc, country_abbrev);
+       if (!wlc_cm->world_regd) {
+               wlc_cm->world_regd = brcms_default_world_regd();
+               ccode = wlc_cm->world_regd->regdomain->alpha2;
+               ccode_len = BRCM_CNTRY_BUF_SZ - 1;
+       }
 
        /* save default country for exiting 11d regulatory mode */
-       strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+       strncpy(wlc->country_default, ccode, ccode_len);
 
        /* initialize autocountry_default to driver default */
-       strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+       strncpy(wlc->autocountry_default, ccode, ccode_len);
 
-       brcms_c_set_countrycode(wlc_cm, country_abbrev);
+       brcms_c_set_country(wlc_cm, wlc_cm->world_regd);
 
        return wlc_cm;
 }
@@ -1149,31 +376,15 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
        kfree(wlc_cm);
 }
 
-u8
-brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
-                                    uint bandunit)
-{
-       return wlc_cm->bandstate[bandunit].locale_flags;
-}
-
-static bool
-brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
-{
-       return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
-               CHSPEC_IS40(chspec) ?
-               (isset(wlc_cm->quiet_channels.vec,
-                      lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
-                isset(wlc_cm->quiet_channels.vec,
-                      upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
-               isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
-}
-
 void
 brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                         u8 local_constraint_qdbm)
 {
        struct brcms_c_info *wlc = wlc_cm->wlc;
+       struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
+       const struct ieee80211_reg_rule *reg_rule;
        struct txpwr_limits txpwr;
+       int ret;
 
        brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
 
@@ -1181,8 +392,15 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                wlc_cm, &txpwr, local_constraint_qdbm
        );
 
+       /* set or restore gmode as required by regulatory */
+       ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, &reg_rule);
+       if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM))
+               brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
+       else
+               brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+
        brcms_b_set_chanspec(wlc->hw, chanspec,
-                             (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
+                             !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
                              &txpwr);
 }
 
@@ -1191,15 +409,14 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                       struct txpwr_limits *txpwr)
 {
        struct brcms_c_info *wlc = wlc_cm->wlc;
+       struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
        uint i;
        uint chan;
        int maxpwr;
        int delta;
        const struct country_info *country;
        struct brcms_band *band;
-       const struct locale_info *li;
        int conducted_max = BRCMS_TXPWR_MAX;
-       int conducted_ofdm_max = BRCMS_TXPWR_MAX;
        const struct locale_mimo_info *li_mimo;
        int maxpwr20, maxpwr40;
        int maxpwr_idx;
@@ -1207,67 +424,35 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
 
        memset(txpwr, 0, sizeof(struct txpwr_limits));
 
-       if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) {
-               country = brcms_c_country_lookup(wlc, wlc->autocountry_default);
-               if (country == NULL)
-                       return;
-       } else {
-               country = wlc_cm->country;
-       }
+       if (WARN_ON(!ch))
+               return;
+
+       country = &wlc_cm->world_regd->country;
 
        chan = CHSPEC_CHANNEL(chanspec);
        band = wlc->bandstate[chspec_bandunit(chanspec)];
-       li = (band->bandtype == BRCM_BAND_5G) ?
-           brcms_c_get_locale_5g(country->locale_5G) :
-           brcms_c_get_locale_2g(country->locale_2G);
-
        li_mimo = (band->bandtype == BRCM_BAND_5G) ?
            brcms_c_get_mimo_5g(country->locale_mimo_5G) :
            brcms_c_get_mimo_2g(country->locale_mimo_2G);
 
-       if (li->flags & BRCMS_EIRP) {
-               delta = band->antgain;
-       } else {
-               delta = 0;
-               if (band->antgain > QDB(6))
-                       delta = band->antgain - QDB(6); /* Excess over 6 dB */
-       }
+       delta = band->antgain;
 
-       if (li == &locale_i) {
+       if (band->bandtype == BRCM_BAND_2G)
                conducted_max = QDB(22);
-               conducted_ofdm_max = QDB(22);
-       }
+
+       maxpwr = QDB(ch->max_power) - delta;
+       maxpwr = max(maxpwr, 0);
+       maxpwr = min(maxpwr, conducted_max);
 
        /* CCK txpwr limits for 2.4G band */
        if (band->bandtype == BRCM_BAND_2G) {
-               maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
-
-               maxpwr = maxpwr - delta;
-               maxpwr = max(maxpwr, 0);
-               maxpwr = min(maxpwr, conducted_max);
-
                for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
                        txpwr->cck[i] = (u8) maxpwr;
        }
 
-       /* OFDM txpwr limits for 2.4G or 5G bands */
-       if (band->bandtype == BRCM_BAND_2G)
-               maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
-       else
-               maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
-
-       maxpwr = maxpwr - delta;
-       maxpwr = max(maxpwr, 0);
-       maxpwr = min(maxpwr, conducted_ofdm_max);
-
-       /* Keep OFDM lmit below CCK limit */
-       if (band->bandtype == BRCM_BAND_2G)
-               maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
-
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
+       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
                txpwr->ofdm[i] = (u8) maxpwr;
 
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
                /*
                 * OFDM 40 MHz SISO has the same power as the corresponding
                 * MCS0-7 rate unless overriden by the locale specific code.
@@ -1282,14 +467,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                txpwr->ofdm_40_cdd[i] = 0;
        }
 
-       /* MIMO/HT specific limits */
-       if (li_mimo->flags & BRCMS_EIRP) {
-               delta = band->antgain;
-       } else {
-               delta = 0;
-               if (band->antgain > QDB(6))
-                       delta = band->antgain - QDB(6); /* Excess over 6 dB */
-       }
+       delta = 0;
+       if (band->antgain > QDB(6))
+               delta = band->antgain - QDB(6); /* Excess over 6 dB */
 
        if (band->bandtype == BRCM_BAND_2G)
                maxpwr_idx = (chan - 1);
@@ -1431,8 +611,7 @@ static bool brcms_c_chspec_malformed(u16 chanspec)
  * and they are also a legal HT combination
  */
 static bool
-brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
-                          bool dualband)
+brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
 {
        struct brcms_c_info *wlc = wlc_cm->wlc;
        u8 channel = CHSPEC_CHANNEL(chspec);
@@ -1448,59 +627,166 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
            chspec_bandunit(chspec))
                return false;
 
-       /* Check a 20Mhz channel */
-       if (CHSPEC_IS20(chspec)) {
-               if (dualband)
-                       return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
-                                                         channel);
-               else
-                       return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
-                                                      channel);
+       return true;
+}
+
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+       return brcms_c_valid_chanspec_ext(wlc_cm, chspec);
+}
+
+static bool brcms_is_radar_freq(u16 center_freq)
+{
+       return center_freq >= 5260 && center_freq <= 5700;
+}
+
+static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       int i;
+
+       sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+       if (!sband)
+               return;
+
+       for (i = 0; i < sband->n_channels; i++) {
+               ch = &sband->channels[i];
+
+               if (!brcms_is_radar_freq(ch->center_freq))
+                       continue;
+
+               /*
+                * All channels in this range should be passive and have
+                * DFS enabled.
+                */
+               if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+                       ch->flags |= IEEE80211_CHAN_RADAR |
+                                    IEEE80211_CHAN_NO_IBSS |
+                                    IEEE80211_CHAN_PASSIVE_SCAN;
        }
-#ifdef SUPPORT_40MHZ
-       /*
-        * We know we are now checking a 40MHZ channel, so we should
-        * only be here for NPHYS
-        */
-       if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
-               u8 upper_sideband = 0, idx;
-               u8 num_ch20_entries =
-                   sizeof(chan20_info) / sizeof(struct chan20_info);
-
-               if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
-                       return false;
-
-               if (dualband) {
-                       if (!brcms_c_valid_channel20_db(wlc->cmi,
-                                                       lower_20_sb(channel)) ||
-                           !brcms_c_valid_channel20_db(wlc->cmi,
-                                                       upper_20_sb(channel)))
-                               return false;
-               } else {
-                       if (!brcms_c_valid_channel20(wlc->cmi,
-                                                    lower_20_sb(channel)) ||
-                           !brcms_c_valid_channel20(wlc->cmi,
-                                                    upper_20_sb(channel)))
-                               return false;
+}
+
+static void
+brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
+                               enum nl80211_reg_initiator initiator)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       const struct ieee80211_reg_rule *rule;
+       int band, i, ret;
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               sband = wiphy->bands[band];
+               if (!sband)
+                       continue;
+
+               for (i = 0; i < sband->n_channels; i++) {
+                       ch = &sband->channels[i];
+
+                       if (ch->flags &
+                           (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))
+                               continue;
+
+                       if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                               ret = freq_reg_info(wiphy, ch->center_freq,
+                                                   0, &rule);
+                               if (ret)
+                                       continue;
+
+                               if (!(rule->flags & NL80211_RRF_NO_IBSS))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+                               if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
+                                       ch->flags &=
+                                               ~IEEE80211_CHAN_PASSIVE_SCAN;
+                       } else if (ch->beacon_found) {
+                               ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+                                              IEEE80211_CHAN_PASSIVE_SCAN);
+                       }
                }
+       }
+}
 
-               /* find the lower sideband info in the sideband array */
-               for (idx = 0; idx < num_ch20_entries; idx++) {
-                       if (chan20_info[idx].sb == lower_20_sb(channel))
-                               upper_sideband = chan20_info[idx].adj_sbs;
+static int brcms_reg_notifier(struct wiphy *wiphy,
+                             struct regulatory_request *request)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct brcms_info *wl = hw->priv;
+       struct brcms_c_info *wlc = wl->wlc;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       int band, i;
+       bool ch_found = false;
+
+       brcms_reg_apply_radar_flags(wiphy);
+
+       if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
+               brcms_reg_apply_beaconing_flags(wiphy, request->initiator);
+
+       /* Disable radio if all channels disallowed by regulatory */
+       for (band = 0; !ch_found && band < IEEE80211_NUM_BANDS; band++) {
+               sband = wiphy->bands[band];
+               if (!sband)
+                       continue;
+
+               for (i = 0; !ch_found && i < sband->n_channels; i++) {
+                       ch = &sband->channels[i];
+
+                       if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+                               ch_found = true;
                }
-               /* check that the lower sideband allows an upper sideband */
-               if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) ==
-                   (CH_UPPER_SB | CH_EWA_VALID))
-                       return true;
-               return false;
        }
-#endif                         /* 40 MHZ */
 
-       return false;
+       if (ch_found) {
+               mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+       } else {
+               mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+               wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n",
+                         wlc->pub->unit, __func__, request->alpha2);
+       }
+
+       if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+               wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
+                                       brcms_c_japan_ccode(request->alpha2));
+
+       return 0;
 }
 
-bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
+void brcms_c_regd_init(struct brcms_c_info *wlc)
 {
-       return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
+       struct wiphy *wiphy = wlc->wiphy;
+       const struct brcms_regd *regd = wlc->cmi->world_regd;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       struct brcms_chanvec sup_chan;
+       struct brcms_band *band;
+       int band_idx, i;
+
+       /* Disable any channels not supported by the phy */
+       for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
+               if (band_idx == IEEE80211_BAND_2GHZ)
+                       band = wlc->bandstate[BAND_2G_INDEX];
+               else
+                       band = wlc->bandstate[BAND_5G_INDEX];
+
+               /* skip if band not initialized */
+               if (band->pi == NULL)
+                       continue;
+
+               wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+                                             &sup_chan);
+
+               sband = wiphy->bands[band_idx];
+               for (i = 0; i < sband->n_channels; i++) {
+                       ch = &sband->channels[i];
+                       if (!isset(sup_chan.vec, ch->hw_value))
+                               ch->flags |= IEEE80211_CHAN_DISABLED;
+               }
+       }
+
+       wlc->wiphy->reg_notifier = brcms_reg_notifier;
+       wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+                            WIPHY_FLAG_STRICT_REGULATORY;
+       wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
+       brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
 }
index 808cb4fbfbe70329fdcb6206d678f0479ee310ad..006483a0abe6452d022600666b5ddf9ad5d28248 100644 (file)
@@ -37,9 +37,6 @@ brcms_c_channel_mgr_attach(struct brcms_c_info *wlc);
 
 extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm);
 
-extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
-                                          uint bandunit);
-
 extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
                                      u16 chspec);
 
@@ -49,5 +46,6 @@ extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
 extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
                                     u16 chanspec,
                                     u8 local_constraint_qdbm);
+extern void brcms_c_regd_init(struct brcms_c_info *wlc);
 
 #endif                         /* _WLC_CHANNEL_H */
index 50f92a0b7c41408c0b4a416d9ffe82c69e3a70fd..2d5a404126908ea39fe75e0f155ea335e82f31e1 100644 (file)
@@ -721,14 +721,6 @@ static const struct ieee80211_ops brcms_ops = {
        .flush = brcms_ops_flush,
 };
 
-/*
- * is called in brcms_bcma_probe() context, therefore no locking required.
- */
-static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
-{
-       return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
-}
-
 void brcms_dpc(unsigned long data)
 {
        struct brcms_info *wl;
@@ -1058,6 +1050,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
                goto fail;
        }
 
+       brcms_c_regd_init(wl->wlc);
+
        memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
        if (WARN_ON(!is_valid_ether_addr(perm)))
                goto fail;
@@ -1068,9 +1062,9 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
                wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
                          "%d\n", __func__, err);
 
-       if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode))
-               wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
-                         __func__, err);
+       if (wl->pub->srom_ccode[0] &&
+           regulatory_hint(wl->wiphy, wl->pub->srom_ccode))
+               wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__);
 
        n_adapters_found++;
        return wl;
index 19db4052c44c419324545072834d915f0339a361..8776fbc8dcf1de7cf3dfd1e8da0764a6dec15862 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/pci_ids.h>
 #include <linux/if_ether.h>
+#include <net/cfg80211.h>
 #include <net/mac80211.h>
 #include <brcm_hw_ids.h>
 #include <aiutils.h>
@@ -3139,20 +3140,6 @@ void brcms_c_reset(struct brcms_c_info *wlc)
        brcms_b_reset(wlc->hw);
 }
 
-/* Return the channel the driver should initialize during brcms_c_init.
- * the channel may have to be changed from the currently configured channel
- * if other configurations are in conflict (bandlocked, 11n mode disabled,
- * invalid channel for current country, etc.)
- */
-static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
-{
-       u16 chanspec =
-           1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
-           WL_CHANSPEC_BAND_2G;
-
-       return chanspec;
-}
-
 void brcms_c_init_scb(struct scb *scb)
 {
        int i;
@@ -5129,6 +5116,8 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
 /* make interface operational */
 int brcms_c_up(struct brcms_c_info *wlc)
 {
+       struct ieee80211_channel *ch;
+
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
        /* HW is turned off so don't try to access it */
@@ -5195,8 +5184,9 @@ int brcms_c_up(struct brcms_c_info *wlc)
        wlc->pub->up = true;
 
        if (wlc->bandinit_pending) {
+               ch = wlc->pub->ieee_hw->conf.channel;
                brcms_c_suspend_mac_and_wait(wlc);
-               brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec);
+               brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));
                wlc->bandinit_pending = false;
                brcms_c_enable_mac(wlc);
        }
@@ -5397,11 +5387,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
        else
                return -EINVAL;
 
-       /* Legacy or bust when no OFDM is supported by regulatory */
-       if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) &
-            BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B))
-               return -EINVAL;
-
        /* update configuration value */
        if (config)
                brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
@@ -8201,19 +8186,12 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
 void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 {
        struct bcma_device *core = wlc->hw->d11core;
+       struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
        u16 chanspec;
 
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
-       /*
-        * This will happen if a big-hammer was executed. In
-        * that case, we want to go back to the channel that
-        * we were on and not new channel
-        */
-       if (wlc->pub->associated)
-               chanspec = wlc->home_chanspec;
-       else
-               chanspec = brcms_c_init_chanspec(wlc);
+       chanspec = ch20mhz_chspec(ch->hw_value);
 
        brcms_b_init(wlc->hw, chanspec);
 
index 13b261517cce53d130235b43ce62bbfbe01e00ee..3667181464184bc3293f9241f8ccc10d3d9323ab 100644 (file)
@@ -14358,7 +14358,7 @@ void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
 
        wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
 
-       if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
+       if (pi->sh && (pi->sh->_rifs_phy != rifs))
                pi->sh->_rifs_phy = rifs;
 }
 
index b45ab34cdfdc0693676fae614359b2bafaa5c526..3e6405e06ac028687e1d12627874491e969d6e94 100644 (file)
@@ -43,6 +43,8 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
 /* Free the driver packet. Free the tag if present */
 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
 {
+       if (!skb)
+               return;
        WARN_ON(skb->next);
        if (skb->destructor)
                /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
index 333193f20e1cfeb9071ee483bc30f6f272564300..bcc79b4e3267ba1434c3c0bfdec1b2de6f50d18b 100644 (file)
@@ -37,5 +37,6 @@
 #define BCM4329_CHIP_ID                0x4329
 #define BCM4330_CHIP_ID                0x4330
 #define BCM4331_CHIP_ID                0x4331
+#define BCM4334_CHIP_ID                0x4334
 
 #endif                         /* _BRCM_HW_IDS_H_ */
index 0036737fe8e3fb54be0b780ba66508d7fc869d57..254b8922327690127013f848b487fb372fa21c93 100644 (file)
@@ -2701,6 +2701,20 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
        memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
 }
 
+static void ipw_read_eeprom(struct ipw_priv *priv)
+{
+       int i;
+       __le16 *eeprom = (__le16 *) priv->eeprom;
+
+       IPW_DEBUG_TRACE(">>\n");
+
+       /* read entire contents of eeprom into private buffer */
+       for (i = 0; i < 128; i++)
+               eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
+
+       IPW_DEBUG_TRACE("<<\n");
+}
+
 /*
  * Either the device driver (i.e. the host) or the firmware can
  * load eeprom data into the designated region in SRAM.  If neither
@@ -2712,14 +2726,9 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
 static void ipw_eeprom_init_sram(struct ipw_priv *priv)
 {
        int i;
-       __le16 *eeprom = (__le16 *) priv->eeprom;
 
        IPW_DEBUG_TRACE(">>\n");
 
-       /* read entire contents of eeprom into private buffer */
-       for (i = 0; i < 128; i++)
-               eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
        /*
           If the data looks correct, then copy it to our private
           copy.  Otherwise let the firmware know to perform the operation
@@ -3643,8 +3652,10 @@ static int ipw_load(struct ipw_priv *priv)
        /* ack fw init done interrupt */
        ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
-       /* read eeprom data and initialize the eeprom region of sram */
+       /* read eeprom data */
        priv->eeprom_delay = 1;
+       ipw_read_eeprom(priv);
+       /* initialize the eeprom region of sram */
        ipw_eeprom_init_sram(priv);
 
        /* enable interrupts */
index ff5d689e13f34884222b58fe06291140db1f9682..34f61a0581a22cf78054063ced014aa05cd72f38 100644 (file)
@@ -5724,7 +5724,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
        hw->wiphy->flags |=
-           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS;
+           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
+           WIPHY_FLAG_IBSS_RSN;
 
        /*
         * For now, disable PS by default because it affects
@@ -5873,6 +5874,16 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
+       /*
+        * To support IBSS RSN, don't program group keys in IBSS, the
+        * hardware will then not attempt to decrypt the frames.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               D_MAC80211("leave - ad-hoc group key\n");
+               return -EOPNOTSUPP;
+       }
+
        sta_id = il_sta_id_or_broadcast(il, sta);
        if (sta_id == IL_INVALID_STATION)
                return -EINVAL;
index 5d4807c2b56d80aaafe47089a2498b29856ba40c..0f8a7703eea3c493486bc09b049a77f6a89a7a9b 100644 (file)
@@ -4717,10 +4717,11 @@ il_check_stuck_queue(struct il_priv *il, int cnt)
        struct il_tx_queue *txq = &il->txq[cnt];
        struct il_queue *q = &txq->q;
        unsigned long timeout;
+       unsigned long now = jiffies;
        int ret;
 
        if (q->read_ptr == q->write_ptr) {
-               txq->time_stamp = jiffies;
+               txq->time_stamp = now;
                return 0;
        }
 
@@ -4728,9 +4729,9 @@ il_check_stuck_queue(struct il_priv *il, int cnt)
            txq->time_stamp +
            msecs_to_jiffies(il->cfg->wd_timeout);
 
-       if (time_after(jiffies, timeout)) {
+       if (time_after(now, timeout)) {
                IL_ERR("Queue %d stuck for %u ms.\n", q->id,
-                      il->cfg->wd_timeout);
+                      jiffies_to_msecs(now - txq->time_stamp));
                ret = il_force_reset(il, false);
                return (ret == -EAGAIN) ? 0 : 1;
        }
index 2463c06264387230759f14801239610a4fe4eb58..727fbb5db9da0b41b10b6132267d4b91f533f852 100644 (file)
@@ -6,6 +6,7 @@ config IWLWIFI
        select LEDS_CLASS
        select LEDS_TRIGGERS
        select MAC80211_LEDS
+       select IWLDVM
        ---help---
          Select to build the driver supporting the:
 
@@ -41,6 +42,10 @@ config IWLWIFI
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
          module will be called iwlwifi.
 
+config IWLDVM
+       tristate "Intel Wireless WiFi"
+       depends on IWLWIFI
+
 menu "Debugging Options"
        depends on IWLWIFI
 
index d615eacbf050be320d803c74fec0ace223abae73..170ec330d2a9928532376fc1a1767f9d91c0bf1a 100644 (file)
@@ -1,27 +1,19 @@
-# WIFI
+# common
 obj-$(CONFIG_IWLWIFI)  += iwlwifi.o
-iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
-iwlwifi-objs           += iwl-ucode.o iwl-agn-tx.o iwl-debug.o
-iwlwifi-objs           += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
-iwlwifi-objs           += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
-
-iwlwifi-objs           += iwl-eeprom.o iwl-power.o
-iwlwifi-objs           += iwl-scan.o iwl-led.o
-iwlwifi-objs           += iwl-agn-rxon.o iwl-agn-devices.o
-iwlwifi-objs           += iwl-5000.o
-iwlwifi-objs           += iwl-6000.o
-iwlwifi-objs           += iwl-1000.o
-iwlwifi-objs           += iwl-2000.o
-iwlwifi-objs           += iwl-pci.o
+iwlwifi-objs           += iwl-io.o
 iwlwifi-objs           += iwl-drv.o
+iwlwifi-objs           += iwl-debug.o
 iwlwifi-objs           += iwl-notif-wait.o
-iwlwifi-objs           += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
-
+iwlwifi-objs           += iwl-eeprom-read.o iwl-eeprom-parse.o
+iwlwifi-objs           += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
+iwlwifi-objs           += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
 
-iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
-iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o
+iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
 
-CFLAGS_iwl-devtrace.o := -I$(src)
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)
 
-ccflags-y += -D__CHECK_ENDIAN__
+
+obj-$(CONFIG_IWLDVM)   += dvm/
+
+CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/dvm/Makefile b/drivers/net/wireless/iwlwifi/dvm/Makefile
new file mode 100644 (file)
index 0000000..5ff76b2
--- /dev/null
@@ -0,0 +1,13 @@
+# DVM
+obj-$(CONFIG_IWLDVM)   += iwldvm.o
+iwldvm-objs            += main.o rs.o mac80211.o ucode.o tx.o
+iwldvm-objs            += lib.o calib.o tt.o sta.o rx.o
+
+iwldvm-objs            += power.o
+iwldvm-objs            += scan.o led.o
+iwldvm-objs            += rxon.o devices.o
+
+iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
+iwldvm-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += testmode.o
+
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
new file mode 100644 (file)
index 0000000..9bb16bd
--- /dev/null
@@ -0,0 +1,529 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_agn_h__
+#define __iwl_agn_h__
+
+#include "iwl-config.h"
+
+#include "dev.h"
+
+/* The first 11 queues (0-10) are used otherwise */
+#define IWLAGN_FIRST_AMPDU_QUEUE       11
+
+/* AUX (TX during scan dwell) queue */
+#define IWL_AUX_QUEUE          10
+
+/* device operations */
+extern struct iwl_lib_ops iwl1000_lib;
+extern struct iwl_lib_ops iwl2000_lib;
+extern struct iwl_lib_ops iwl2030_lib;
+extern struct iwl_lib_ops iwl5000_lib;
+extern struct iwl_lib_ops iwl5150_lib;
+extern struct iwl_lib_ops iwl6000_lib;
+extern struct iwl_lib_ops iwl6030_lib;
+
+
+#define TIME_UNIT              1024
+
+/*****************************************************
+* DRIVER STATUS FUNCTIONS
+******************************************************/
+#define STATUS_RF_KILL_HW      0
+#define STATUS_CT_KILL         1
+#define STATUS_ALIVE           2
+#define STATUS_READY           3
+#define STATUS_EXIT_PENDING    5
+#define STATUS_STATISTICS      6
+#define STATUS_SCANNING                7
+#define STATUS_SCAN_ABORTING   8
+#define STATUS_SCAN_HW         9
+#define STATUS_FW_ERROR                10
+#define STATUS_CHANNEL_SWITCH_PENDING 11
+#define STATUS_SCAN_COMPLETE   12
+#define STATUS_POWER_PMI       13
+#define STATUS_SCAN_ROC_EXPIRED 14
+
+struct iwl_ucode_capabilities;
+
+extern struct ieee80211_ops iwlagn_hw_ops;
+
+static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
+{
+       hdr->op_code = cmd;
+       hdr->first_group = 0;
+       hdr->groups_num = 1;
+       hdr->data_valid = 1;
+}
+
+void iwl_down(struct iwl_priv *priv);
+void iwl_cancel_deferred_work(struct iwl_priv *priv);
+void iwlagn_prepare_restart(struct iwl_priv *priv);
+int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
+                                struct iwl_rx_cmd_buffer *rxb,
+                                struct iwl_device_cmd *cmd);
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv);
+
+void iwlagn_lift_passive_no_rx(struct iwl_priv *priv);
+
+/* MAC80211 */
+struct ieee80211_hw *iwl_alloc_all(void);
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                             const struct iwl_ucode_capabilities *capa);
+void iwlagn_mac_unregister(struct iwl_priv *priv);
+
+/* commands */
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+                        u32 flags, u16 len, const void *data);
+
+/* RXON */
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx);
+int iwlagn_set_pan_params(struct iwl_priv *priv);
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed);
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_bss_conf *bss_conf,
+                            u32 changes);
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+                       struct iwl_rxon_context *ctx);
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx);
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           enum ieee80211_band band,
+                           struct ieee80211_vif *vif);
+
+/* uCode */
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+void iwl_send_prio_tbl(struct iwl_priv *priv);
+int iwl_init_alive_start(struct iwl_priv *priv);
+int iwl_run_init_ucode(struct iwl_priv *priv);
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
+                             enum iwl_ucode_type ucode_type);
+int iwl_send_calib_results(struct iwl_priv *priv);
+int iwl_calib_set(struct iwl_priv *priv,
+                 const struct iwl_calib_hdr *cmd, int len);
+void iwl_calib_free_results(struct iwl_priv *priv);
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display);
+int iwlagn_hw_valid_rtc_data_addr(u32 addr);
+
+/* lib */
+int iwlagn_send_tx_power(struct iwl_priv *priv);
+void iwlagn_temperature(struct iwl_priv *priv);
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+int iwl_send_statistics_request(struct iwl_priv *priv,
+                               u8 flags, bool clear);
+
+static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
+                       struct iwl_priv *priv, enum ieee80211_band band)
+{
+       return priv->hw->wiphy->bands[band];
+}
+
+#ifdef CONFIG_PM_SLEEP
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                        struct cfg80211_wowlan *wowlan);
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
+#endif
+
+/* rx */
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
+void iwl_setup_rx_handlers(struct iwl_priv *priv);
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
+
+
+/* tx */
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u8 buf_size);
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid);
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                  struct iwl_rx_cmd_buffer *rxb,
+                                  struct iwl_device_cmd *cmd);
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
+
+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_SUCCESS:
+       case TX_STATUS_DIRECT_DONE:
+               return IEEE80211_TX_STAT_ACK;
+       case TX_STATUS_FAIL_DEST_PS:
+       case TX_STATUS_FAIL_PASSIVE_NO_RX:
+               return IEEE80211_TX_STAT_TX_FILTERED;
+       default:
+               return 0;
+       }
+}
+
+static inline bool iwl_is_tx_success(u32 status)
+{
+       status &= TX_STATUS_MSK;
+       return (status == TX_STATUS_SUCCESS) ||
+              (status == TX_STATUS_DIRECT_DONE);
+}
+
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
+
+/* scan */
+void iwlagn_post_scan(struct iwl_priv *priv);
+void iwlagn_disable_roc(struct iwl_priv *priv);
+int iwl_force_rf_reset(struct iwl_priv *priv, bool external);
+void iwl_init_scan_params(struct iwl_priv *priv);
+int iwl_scan_cancel(struct iwl_priv *priv);
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_force_scan_end(struct iwl_priv *priv);
+void iwl_internal_short_hw_scan(struct iwl_priv *priv);
+void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
+void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
+int __must_check iwl_scan_initiate(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  enum iwl_scan_type scan_type,
+                                  enum ieee80211_band band);
+
+void iwl_scan_roc_expired(struct iwl_priv *priv);
+void iwl_scan_offchannel_skb(struct iwl_priv *priv);
+void iwl_scan_offchannel_skb_status(struct iwl_priv *priv);
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_ACTIVE_QUIET_TIME       cpu_to_le16(10)  /* msec */
+#define IWL_PLCP_QUIET_THRESH       cpu_to_le16(1)  /* packets */
+
+#define IWL_SCAN_CHECK_WATCHDOG                (HZ * 15)
+
+
+/* bt coex */
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_cmd_buffer *rxb,
+                                 struct iwl_device_cmd *cmd);
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
+
+static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
+{
+       return priv->cfg->bt_params &&
+              priv->cfg->bt_params->advanced_bt_coexist;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status);
+const char *iwl_get_agg_tx_fail_reason(u16 status);
+#else
+static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
+static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
+#endif
+
+
+/* station management */
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add);
+#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
+#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
+#define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
+                                           being activated */
+#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
+                               (this is for the IBSS BSSID stations) */
+#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
+
+
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx);
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
+int iwl_send_add_sta(struct iwl_priv *priv,
+                    struct iwl_addsta_cmd *sta, u8 flags);
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r);
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr);
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+                           const u8 *addr);
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                   const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
+
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                   struct iwl_link_quality_cmd *lq, u8 flags, bool init);
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                     struct ieee80211_sta *sta);
+
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap);
+
+static inline int iwl_sta_id(struct ieee80211_sta *sta)
+{
+       if (WARN_ON(!sta))
+               return IWL_INVALID_STATION;
+
+       return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
+}
+
+int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx);
+int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                            const u8 *addr, u8 *sta_id_r);
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
+                              struct ieee80211_key_conf *key);
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_key_conf *key);
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx);
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                       struct ieee80211_key_conf *key,
+                       struct ieee80211_sta *sta);
+int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          struct ieee80211_key_conf *key,
+                          struct ieee80211_sta *sta);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+                        struct ieee80211_vif *vif,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid);
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+int iwl_update_bcast_station(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx);
+int iwl_update_bcast_stations(struct iwl_priv *priv);
+
+/* rate */
+static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
+{
+       return BIT(ant_idx) << RATE_MCS_ANT_POS;
+}
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+       return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
+}
+
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
+{
+       return cpu_to_le32(flags|(u32)rate);
+}
+
+extern int iwl_alive_start(struct iwl_priv *priv);
+
+/* testmode support */
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+
+extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data,
+                                  int len);
+extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw,
+                                   struct sk_buff *skb,
+                                   struct netlink_callback *cb,
+                                   void *data, int len);
+extern void iwl_testmode_init(struct iwl_priv *priv);
+extern void iwl_testmode_free(struct iwl_priv *priv);
+
+#else
+
+static inline
+int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+       return -ENOSYS;
+}
+
+static inline
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+                     struct netlink_callback *cb,
+                     void *data, int len)
+{
+       return -ENOSYS;
+}
+
+static inline void iwl_testmode_init(struct iwl_priv *priv)
+{
+}
+
+static inline void iwl_testmode_free(struct iwl_priv *priv)
+{
+}
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            enum iwl_rxon_context_id ctxid);
+#else
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                                          enum iwl_rxon_context_id ctxid)
+{
+}
+#endif
+
+/* status checks */
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+       /* The adapter is 'ready' if READY EXIT_PENDING is not set */
+       return test_bit(STATUS_READY, &priv->status) &&
+              !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+       return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+       return test_bit(STATUS_RF_KILL_HW, &priv->status);
+}
+
+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)
+{
+       if (iwl_is_rfkill(priv))
+               return 0;
+
+       return iwl_is_ready(priv);
+}
+
+static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
+{
+       if (state)
+               set_bit(STATUS_POWER_PMI, &priv->status);
+       else
+               clear_bit(STATUS_POWER_PMI, &priv->status);
+       iwl_trans_set_pmi(priv->trans, state);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
+void iwl_dbgfs_unregister(struct iwl_priv *priv);
+#else
+static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+{
+       return 0;
+}
+static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
+{
+}
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
+do {                                                                   \
+       if (!iwl_is_rfkill((m)))                                        \
+               IWL_ERR(m, fmt, ##args);                                \
+       else                                                            \
+               __iwl_err((m)->dev, true,                               \
+                         !iwl_have_debug_level(IWL_DL_RADIO),          \
+                         fmt, ##args);                                 \
+} while (0)
+#else
+#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
+do {                                                                   \
+       if (!iwl_is_rfkill((m)))                                        \
+               IWL_ERR(m, fmt, ##args);                                \
+       else                                                            \
+               __iwl_err((m)->dev, true, true, fmt, ##args);   \
+} while (0)
+#endif                         /* CONFIG_IWLWIFI_DEBUG */
+
+extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
+
+static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
+{
+       const char *s = iwl_dvm_cmd_strings[cmd];
+       if (s)
+               return s;
+       return "UNKNOWN";
+}
+#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c
new file mode 100644 (file)
index 0000000..f2dd671
--- /dev/null
@@ -0,0 +1,1114 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include "iwl-trans.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+/*****************************************************************************
+ * INIT calibrations framework
+ *****************************************************************************/
+
+/* Opaque calibration results */
+struct iwl_calib_result {
+       struct list_head list;
+       size_t cmd_len;
+       struct iwl_calib_hdr hdr;
+       /* data follows */
+};
+
+struct statistics_general_data {
+       u32 beacon_silence_rssi_a;
+       u32 beacon_silence_rssi_b;
+       u32 beacon_silence_rssi_c;
+       u32 beacon_energy_a;
+       u32 beacon_energy_b;
+       u32 beacon_energy_c;
+};
+
+int iwl_send_calib_results(struct iwl_priv *priv)
+{
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_PHY_CALIBRATION_CMD,
+               .flags = CMD_SYNC,
+       };
+       struct iwl_calib_result *res;
+
+       list_for_each_entry(res, &priv->calib_results, list) {
+               int ret;
+
+               hcmd.len[0] = res->cmd_len;
+               hcmd.data[0] = &res->hdr;
+               hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+               ret = iwl_dvm_send_cmd(priv, &hcmd);
+               if (ret) {
+                       IWL_ERR(priv, "Error %d on calib cmd %d\n",
+                               ret, res->hdr.op_code);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+int iwl_calib_set(struct iwl_priv *priv,
+                 const struct iwl_calib_hdr *cmd, int len)
+{
+       struct iwl_calib_result *res, *tmp;
+
+       res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
+                     GFP_ATOMIC);
+       if (!res)
+               return -ENOMEM;
+       memcpy(&res->hdr, cmd, len);
+       res->cmd_len = len;
+
+       list_for_each_entry(tmp, &priv->calib_results, list) {
+               if (tmp->hdr.op_code == res->hdr.op_code) {
+                       list_replace(&tmp->list, &res->list);
+                       kfree(tmp);
+                       return 0;
+               }
+       }
+
+       /* wasn't in list already */
+       list_add_tail(&res->list, &priv->calib_results);
+
+       return 0;
+}
+
+void iwl_calib_free_results(struct iwl_priv *priv)
+{
+       struct iwl_calib_result *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
+               list_del(&res->list);
+               kfree(res);
+       }
+}
+
+/*****************************************************************************
+ * RUNTIME calibrations framework
+ *****************************************************************************/
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ *   but then determines that they are either noise, or transmissions
+ *   from a distant wireless network (also "noise", really) that get
+ *   "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ *   enough to receive all of our own network traffic, but not so
+ *   high that our DSP gets too busy trying to lock onto non-network
+ *   activity/noise. */
+static int iwl_sens_energy_cck(struct iwl_priv *priv,
+                                  u32 norm_fa,
+                                  u32 rx_enable_time,
+                                  struct statistics_general_data *rx_info)
+{
+       u32 max_nrg_cck = 0;
+       int i = 0;
+       u8 max_silence_rssi = 0;
+       u32 silence_ref = 0;
+       u8 silence_rssi_a = 0;
+       u8 silence_rssi_b = 0;
+       u8 silence_rssi_c = 0;
+       u32 val;
+
+       /* "false_alarms" values below are cross-multiplications to assess the
+        *   numbers of false alarms within the measured period of actual Rx
+        *   (Rx is off when we're txing), vs the min/max expected false alarms
+        *   (some should be expected if rx is sensitive enough) in a
+        *   hypothetical listening period of 200 time units (TU), 204.8 msec:
+        *
+        * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+        *
+        * */
+       u32 false_alarms = norm_fa * 200 * 1024;
+       u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+       u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       data = &(priv->sensitivity_data);
+
+       data->nrg_auto_corr_silence_diff = 0;
+
+       /* Find max silence rssi among all 3 receivers.
+        * This is background noise, which may include transmissions from other
+        *    networks, measured during silence before our network's beacon */
+       silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+                           ALL_BAND_FILTER) >> 8);
+       silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+                           ALL_BAND_FILTER) >> 8);
+       silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+                           ALL_BAND_FILTER) >> 8);
+
+       val = max(silence_rssi_b, silence_rssi_c);
+       max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+       /* Store silence rssi in 20-beacon history table */
+       data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+       data->nrg_silence_idx++;
+       if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+               data->nrg_silence_idx = 0;
+
+       /* Find max silence rssi across 20 beacon history */
+       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+               val = data->nrg_silence_rssi[i];
+               silence_ref = max(silence_ref, val);
+       }
+       IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
+                       silence_rssi_a, silence_rssi_b, silence_rssi_c,
+                       silence_ref);
+
+       /* Find max rx energy (min value!) among all 3 receivers,
+        *   measured during beacon frame.
+        * Save it in 10-beacon history table. */
+       i = data->nrg_energy_idx;
+       val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+       data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+       data->nrg_energy_idx++;
+       if (data->nrg_energy_idx >= 10)
+               data->nrg_energy_idx = 0;
+
+       /* Find min rx energy (max value) across 10 beacon history.
+        * This is the minimum signal level that we want to receive well.
+        * Add backoff (margin so we don't miss slightly lower energy frames).
+        * This establishes an upper bound (min value) for energy threshold. */
+       max_nrg_cck = data->nrg_value[0];
+       for (i = 1; i < 10; i++)
+               max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+       max_nrg_cck += 6;
+
+       IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+                       rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+                       rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+       /* Count number of consecutive beacons with fewer-than-desired
+        *   false alarms. */
+       if (false_alarms < min_false_alarms)
+               data->num_in_cck_no_fa++;
+       else
+               data->num_in_cck_no_fa = 0;
+       IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
+                       data->num_in_cck_no_fa);
+
+       /* If we got too many false alarms this time, reduce sensitivity */
+       if ((false_alarms > max_false_alarms) &&
+               (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
+               IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
+                    false_alarms, max_false_alarms);
+               IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
+               data->nrg_curr_state = IWL_FA_TOO_MANY;
+               /* Store for "fewer than desired" on later beacon */
+               data->nrg_silence_ref = silence_ref;
+
+               /* increase energy threshold (reduce nrg value)
+                *   to decrease sensitivity */
+               data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
+       /* Else if we got fewer than desired, increase sensitivity */
+       } else if (false_alarms < min_false_alarms) {
+               data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+               /* Compare silence level with silence level for most recent
+                *   healthy number or too many false alarms */
+               data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+                                                  (s32)silence_ref;
+
+               IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u, silence diff %d\n",
+                        false_alarms, min_false_alarms,
+                        data->nrg_auto_corr_silence_diff);
+
+               /* Increase value to increase sensitivity, but only if:
+                * 1a) previous beacon did *not* have *too many* false alarms
+                * 1b) AND there's a significant difference in Rx levels
+                *      from a previous beacon with too many, or healthy # FAs
+                * OR 2) We've seen a lot of beacons (100) with too few
+                *       false alarms */
+               if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+                       ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+                       (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+                       IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n");
+                       /* Increase nrg value to increase sensitivity */
+                       val = data->nrg_th_cck + NRG_STEP_CCK;
+                       data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
+               } else {
+                       IWL_DEBUG_CALIB(priv, "... but not changing sensitivity\n");
+               }
+
+       /* Else we got a healthy number of false alarms, keep status quo */
+       } else {
+               IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
+               data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+               /* Store for use in "fewer than desired" with later beacon */
+               data->nrg_silence_ref = silence_ref;
+
+               /* If previous beacon had too many false alarms,
+                *   give it some extra margin by reducing sensitivity again
+                *   (but don't go below measured energy of desired Rx) */
+               if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+                       IWL_DEBUG_CALIB(priv, "... increasing margin\n");
+                       if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
+                               data->nrg_th_cck -= NRG_MARGIN;
+                       else
+                               data->nrg_th_cck = max_nrg_cck;
+               }
+       }
+
+       /* Make sure the energy threshold does not go above the measured
+        * energy of the desired Rx signals (reduced by backoff margin),
+        * or else we might start missing Rx frames.
+        * Lower value is higher energy, so we use max()!
+        */
+       data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+       IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
+
+       data->nrg_prev_state = data->nrg_curr_state;
+
+       /* Auto-correlation CCK algorithm */
+       if (false_alarms > min_false_alarms) {
+
+               /* increase auto_corr values to decrease sensitivity
+                * so the DSP won't be disturbed by the noise
+                */
+               if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+                       data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+               else {
+                       val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+                       data->auto_corr_cck =
+                               min((u32)ranges->auto_corr_max_cck, val);
+               }
+               val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck_mrc =
+                       min((u32)ranges->auto_corr_max_cck_mrc, val);
+       } else if ((false_alarms < min_false_alarms) &&
+          ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+          (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+               /* Decrease auto_corr values to increase sensitivity */
+               val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck =
+                       max((u32)ranges->auto_corr_min_cck, val);
+               val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck_mrc =
+                       max((u32)ranges->auto_corr_min_cck_mrc, val);
+       }
+
+       return 0;
+}
+
+
+static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
+                                      u32 norm_fa,
+                                      u32 rx_enable_time)
+{
+       u32 val;
+       u32 false_alarms = norm_fa * 200 * 1024;
+       u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+       u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       data = &(priv->sensitivity_data);
+
+       /* If we got too many false alarms this time, reduce sensitivity */
+       if (false_alarms > max_false_alarms) {
+
+               IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u)\n",
+                            false_alarms, max_false_alarms);
+
+               val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm =
+                       min((u32)ranges->auto_corr_max_ofdm, val);
+
+               val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc =
+                       min((u32)ranges->auto_corr_max_ofdm_mrc, val);
+
+               val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_x1 =
+                       min((u32)ranges->auto_corr_max_ofdm_x1, val);
+
+               val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc_x1 =
+                       min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
+       }
+
+       /* Else if we got fewer than desired, increase sensitivity */
+       else if (false_alarms < min_false_alarms) {
+
+               IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u\n",
+                            false_alarms, min_false_alarms);
+
+               val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm =
+                       max((u32)ranges->auto_corr_min_ofdm, val);
+
+               val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc =
+                       max((u32)ranges->auto_corr_min_ofdm_mrc, val);
+
+               val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_x1 =
+                       max((u32)ranges->auto_corr_min_ofdm_x1, val);
+
+               val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc_x1 =
+                       max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
+       } else {
+               IWL_DEBUG_CALIB(priv, "min FA %u < norm FA %u < max FA %u OK\n",
+                        min_false_alarms, false_alarms, max_false_alarms);
+       }
+       return 0;
+}
+
+static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
+                               struct iwl_sensitivity_data *data,
+                               __le16 *tbl)
+{
+       tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm);
+       tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+       tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+       tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+       tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_cck);
+       tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+       tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
+                               cpu_to_le16((u16)data->nrg_th_cck);
+       tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+                               cpu_to_le16((u16)data->nrg_th_ofdm);
+
+       tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16(data->barker_corr_th_min);
+       tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16(data->barker_corr_th_min_mrc);
+       tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
+                               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,
+                       data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+                       data->nrg_th_ofdm);
+
+       IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
+                       data->auto_corr_cck, data->auto_corr_cck_mrc,
+                       data->nrg_th_cck);
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_sensitivity_write(struct iwl_priv *priv)
+{
+       struct iwl_sensitivity_cmd cmd;
+       struct iwl_sensitivity_data *data = NULL;
+       struct iwl_host_cmd cmd_out = {
+               .id = SENSITIVITY_CMD,
+               .len = { sizeof(struct iwl_sensitivity_cmd), },
+               .flags = CMD_ASYNC,
+               .data = { &cmd, },
+       };
+
+       data = &(priv->sensitivity_data);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
+
+       /* Update uCode's "work" table, and copy it to DSP */
+       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+       /* Don't send command to uCode if nothing has changed */
+       if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+                   sizeof(u16)*HD_TABLE_SIZE)) {
+               IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
+               return 0;
+       }
+
+       /* Copy table for comparison next time */
+       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+              sizeof(u16)*HD_TABLE_SIZE);
+
+       return iwl_dvm_send_cmd(priv, &cmd_out);
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
+{
+       struct iwl_enhance_sensitivity_cmd cmd;
+       struct iwl_sensitivity_data *data = NULL;
+       struct iwl_host_cmd cmd_out = {
+               .id = SENSITIVITY_CMD,
+               .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
+               .flags = CMD_ASYNC,
+               .data = { &cmd, },
+       };
+
+       data = &(priv->sensitivity_data);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
+
+       if (priv->cfg->base_params->hd_v2) {
+               cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+                       HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
+               cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+                       HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
+               cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+                       HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
+       } else {
+               cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
+                       HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
+               cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
+                       HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
+               cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
+                       HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
+               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
+                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
+               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
+                       HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
+       }
+
+       /* Update uCode's "work" table, and copy it to DSP */
+       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+       /* Don't send command to uCode if nothing has changed */
+       if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]),
+                   sizeof(u16)*HD_TABLE_SIZE) &&
+           !memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
+                   &(priv->enhance_sensitivity_tbl[0]),
+                   sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
+               IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
+               return 0;
+       }
+
+       /* Copy table for comparison next time */
+       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]),
+              sizeof(u16)*HD_TABLE_SIZE);
+       memcpy(&(priv->enhance_sensitivity_tbl[0]),
+              &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
+              sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
+
+       return iwl_dvm_send_cmd(priv, &cmd_out);
+}
+
+void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+       int ret = 0;
+       int i;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
+               return;
+
+       IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n");
+
+       /* Clear driver's sensitivity algo data */
+       data = &(priv->sensitivity_data);
+
+       if (ranges == NULL)
+               return;
+
+       memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+       data->num_in_cck_no_fa = 0;
+       data->nrg_curr_state = IWL_FA_TOO_MANY;
+       data->nrg_prev_state = IWL_FA_TOO_MANY;
+       data->nrg_silence_ref = 0;
+       data->nrg_silence_idx = 0;
+       data->nrg_energy_idx = 0;
+
+       for (i = 0; i < 10; i++)
+               data->nrg_value[i] = 0;
+
+       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+               data->nrg_silence_rssi[i] = 0;
+
+       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;
+       data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+       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;
+       data->last_bad_plcp_cnt_cck = 0;
+       data->last_fa_cnt_cck = 0;
+
+       if (priv->fw->enhance_sensitivity_table)
+               ret |= iwl_enhance_sensitivity_write(priv);
+       else
+               ret |= iwl_sensitivity_write(priv);
+       IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
+}
+
+void iwl_sensitivity_calibration(struct iwl_priv *priv)
+{
+       u32 rx_enable_time;
+       u32 fa_cck;
+       u32 fa_ofdm;
+       u32 bad_plcp_cck;
+       u32 bad_plcp_ofdm;
+       u32 norm_fa_ofdm;
+       u32 norm_fa_cck;
+       struct iwl_sensitivity_data *data = NULL;
+       struct statistics_rx_non_phy *rx_info;
+       struct statistics_rx_phy *ofdm, *cck;
+       struct statistics_general_data statis;
+
+       if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
+               return;
+
+       data = &(priv->sensitivity_data);
+
+       if (!iwl_is_any_associated(priv)) {
+               IWL_DEBUG_CALIB(priv, "<< - not associated\n");
+               return;
+       }
+
+       spin_lock_bh(&priv->statistics.lock);
+       rx_info = &priv->statistics.rx_non_phy;
+       ofdm = &priv->statistics.rx_ofdm;
+       cck = &priv->statistics.rx_cck;
+       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+               IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
+               spin_unlock_bh(&priv->statistics.lock);
+               return;
+       }
+
+       /* Extract Statistics: */
+       rx_enable_time = le32_to_cpu(rx_info->channel_load);
+       fa_cck = le32_to_cpu(cck->false_alarm_cnt);
+       fa_ofdm = le32_to_cpu(ofdm->false_alarm_cnt);
+       bad_plcp_cck = le32_to_cpu(cck->plcp_err);
+       bad_plcp_ofdm = le32_to_cpu(ofdm->plcp_err);
+
+       statis.beacon_silence_rssi_a =
+                       le32_to_cpu(rx_info->beacon_silence_rssi_a);
+       statis.beacon_silence_rssi_b =
+                       le32_to_cpu(rx_info->beacon_silence_rssi_b);
+       statis.beacon_silence_rssi_c =
+                       le32_to_cpu(rx_info->beacon_silence_rssi_c);
+       statis.beacon_energy_a =
+                       le32_to_cpu(rx_info->beacon_energy_a);
+       statis.beacon_energy_b =
+                       le32_to_cpu(rx_info->beacon_energy_b);
+       statis.beacon_energy_c =
+                       le32_to_cpu(rx_info->beacon_energy_c);
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
+
+       if (!rx_enable_time) {
+               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
+               return;
+       }
+
+       /* These statistics increase monotonically, and do not reset
+        *   at each beacon.  Calculate difference from last value, or just
+        *   use the new statistics value if it has reset or wrapped around. */
+       if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+               data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+       else {
+               bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+               data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+       }
+
+       if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+               data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+       else {
+               bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+               data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+       }
+
+       if (data->last_fa_cnt_ofdm > fa_ofdm)
+               data->last_fa_cnt_ofdm = fa_ofdm;
+       else {
+               fa_ofdm -= data->last_fa_cnt_ofdm;
+               data->last_fa_cnt_ofdm += fa_ofdm;
+       }
+
+       if (data->last_fa_cnt_cck > fa_cck)
+               data->last_fa_cnt_cck = fa_cck;
+       else {
+               fa_cck -= data->last_fa_cnt_cck;
+               data->last_fa_cnt_cck += fa_cck;
+       }
+
+       /* Total aborted signal locks */
+       norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+       norm_fa_cck = fa_cck + bad_plcp_cck;
+
+       IWL_DEBUG_CALIB(priv, "cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
+                       bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+       iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+       iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+       if (priv->fw->enhance_sensitivity_table)
+               iwl_enhance_sensitivity_write(priv);
+       else
+               iwl_sensitivity_write(priv);
+}
+
+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;
+}
+
+/**
+ * Run disconnected antenna algorithm to find out which antennas are
+ * disconnected.
+ */
+static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
+                                    struct iwl_chain_noise_data *data)
+{
+       u32 active_chains = 0;
+       u32 max_average_sig;
+       u16 max_average_sig_antenna_i;
+       u8 num_tx_chains;
+       u8 first_chain;
+       u16 i = 0;
+
+       average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
+       average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
+       average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
+
+       if (average_sig[0] >= average_sig[1]) {
+               max_average_sig = average_sig[0];
+               max_average_sig_antenna_i = 0;
+               active_chains = (1 << max_average_sig_antenna_i);
+       } else {
+               max_average_sig = average_sig[1];
+               max_average_sig_antenna_i = 1;
+               active_chains = (1 << max_average_sig_antenna_i);
+       }
+
+       if (average_sig[2] >= max_average_sig) {
+               max_average_sig = average_sig[2];
+               max_average_sig_antenna_i = 2;
+               active_chains = (1 << max_average_sig_antenna_i);
+       }
+
+       IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
+                    average_sig[0], average_sig[1], average_sig[2]);
+       IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
+                    max_average_sig, max_average_sig_antenna_i);
+
+       /* Compare signal strengths for all 3 receivers. */
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               if (i != max_average_sig_antenna_i) {
+                       s32 rssi_delta = (max_average_sig - average_sig[i]);
+
+                       /* If signal is very weak, compared with
+                        * strongest, mark it as disconnected. */
+                       if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+                               data->disconn_array[i] = 1;
+                       else
+                               active_chains |= (1 << i);
+                       IWL_DEBUG_CALIB(priv, "i = %d  rssiDelta = %d  "
+                            "disconn_array[i] = %d\n",
+                            i, rssi_delta, data->disconn_array[i]);
+               }
+       }
+
+       /*
+        * The above algorithm sometimes fails when the ucode
+        * reports 0 for all chains. It's not clear why that
+        * happens to start with, but it is then causing trouble
+        * because this can make us enable more chains than the
+        * hardware really has.
+        *
+        * To be safe, simply mask out any chains that we know
+        * are not on the device.
+        */
+       active_chains &= priv->eeprom_data->valid_rx_ant;
+
+       num_tx_chains = 0;
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               /* loops on all the bits of
+                * priv->hw_setting.valid_tx_ant */
+               u8 ant_msk = (1 << i);
+               if (!(priv->eeprom_data->valid_tx_ant & ant_msk))
+                       continue;
+
+               num_tx_chains++;
+               if (data->disconn_array[i] == 0)
+                       /* there is a Tx antenna connected */
+                       break;
+               if (num_tx_chains == priv->hw_params.tx_chains_num &&
+                   data->disconn_array[i]) {
+                       /*
+                        * If all chains are disconnected
+                        * connect the first valid tx chain
+                        */
+                       first_chain =
+                               find_first_chain(priv->eeprom_data->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;
+               }
+       }
+
+       if (active_chains != priv->eeprom_data->valid_rx_ant &&
+           active_chains != priv->chain_noise_data.active_chains)
+               IWL_DEBUG_CALIB(priv,
+                               "Detected that not all antennas are connected! "
+                               "Connected: %#x, valid: %#x.\n",
+                               active_chains,
+                               priv->eeprom_data->valid_rx_ant);
+
+       /* Save for use within RXON, TX, SCAN commands, etc. */
+       data->active_chains = active_chains;
+       IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
+                       active_chains);
+}
+
+static void iwlagn_gain_computation(struct iwl_priv *priv,
+                                   u32 average_noise[NUM_RX_CHAINS],
+                                   u8 default_chain)
+{
+       int i;
+       s32 delta_g;
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+       /*
+        * 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 = (priv->cfg->base_params->chain_noise_scale *
+                       ((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] =
+                       min(abs(delta_g),
+                       (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+               if (delta_g < 0)
+                       /*
+                        * set negative sign ...
+                        * note to Intel developers:  This is uCode API format,
+                        *   not the format of any internal device registers.
+                        *   Do not change this format for e.g. 6050 or similar
+                        *   devices.  Change format only if more resolution
+                        *   (i.e. more than 2 bits magnitude) is needed.
+                        */
+                       data->delta_gain_code[i] |= (1 << 2);
+       }
+
+       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
+                       data->delta_gain_code[1], data->delta_gain_code[2]);
+
+       if (!data->radio_write) {
+               struct iwl_calib_chain_noise_gain_cmd cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               iwl_set_calib_hdr(&cmd.hdr,
+                       priv->phy_calib_chain_noise_gain_cmd);
+               cmd.delta_gain_1 = data->delta_gain_code[1];
+               cmd.delta_gain_2 = data->delta_gain_code[2];
+               iwl_dvm_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                       CMD_ASYNC, sizeof(cmd), &cmd);
+
+               data->radio_write = 1;
+               data->state = IWL_CHAIN_NOISE_CALIBRATED;
+       }
+}
+
+/*
+ * Accumulate 16 beacons of signal and noise statistics for each of
+ *   3 receivers/antennas/rx-chains, then figure out:
+ * 1)  Which antennas are connected.
+ * 2)  Differential rx gain settings to balance the 3 receivers.
+ */
+void iwl_chain_noise_calibration(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = NULL;
+
+       u32 chain_noise_a;
+       u32 chain_noise_b;
+       u32 chain_noise_c;
+       u32 chain_sig_a;
+       u32 chain_sig_b;
+       u32 chain_sig_c;
+       u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+       u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+       u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+       u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+       u16 i = 0;
+       u16 rxon_chnum = INITIALIZATION_VALUE;
+       u16 stat_chnum = INITIALIZATION_VALUE;
+       u8 rxon_band24;
+       u8 stat_band24;
+       struct statistics_rx_non_phy *rx_info;
+
+       /*
+        * MULTI-FIXME:
+        * When we support multiple interfaces on different channels,
+        * this must be modified/fixed.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+       if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
+               return;
+
+       data = &(priv->chain_noise_data);
+
+       /*
+        * 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");
+               return;
+       }
+
+       spin_lock_bh(&priv->statistics.lock);
+
+       rx_info = &priv->statistics.rx_non_phy;
+
+       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+               IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
+               spin_unlock_bh(&priv->statistics.lock);
+               return;
+       }
+
+       rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
+       rxon_chnum = le16_to_cpu(ctx->staging.channel);
+       stat_band24 =
+               !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+       stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
+
+       /* Make sure we accumulate data for just the associated channel
+        *   (even if scanning). */
+       if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
+               IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
+                               rxon_chnum, rxon_band24);
+               spin_unlock_bh(&priv->statistics.lock);
+               return;
+       }
+
+       /*
+        *  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) &
+                               IN_BAND_FILTER;
+       chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+                               IN_BAND_FILTER;
+
+       chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+       chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+       chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       data->beacon_count++;
+
+       data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+       data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+       data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+       data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+       data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+       data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+       IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
+                       rxon_chnum, rxon_band24, data->beacon_count);
+       IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
+                       chain_sig_a, chain_sig_b, chain_sig_c);
+       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 "chain_noise_num_beacons", determine:
+        * 1)  Disconnected antennas (using signal strengths)
+        * 2)  Differential gain (using silence noise) to balance receivers */
+       if (data->beacon_count != IWL_CAL_NUM_BEACONS)
+               return;
+
+       /* Analyze signal for disconnected antenna */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               /* Disable disconnected antenna algorithm for advanced
+                  bt coex, assuming valid antennas are connected */
+               data->active_chains = priv->eeprom_data->valid_rx_ant;
+               for (i = 0; i < NUM_RX_CHAINS; i++)
+                       if (!(data->active_chains & (1<<i)))
+                               data->disconn_array[i] = 1;
+       } else
+               iwl_find_disconn_antenna(priv, average_sig, data);
+
+       /* Analyze noise for rx balance */
+       average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
+       average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
+       average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
+
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               if (!(data->disconn_array[i]) &&
+                  (average_noise[i] <= min_average_noise)) {
+                       /* This means that chain i is active and has
+                        * lower noise values so far: */
+                       min_average_noise = average_noise[i];
+                       min_average_noise_antenna_i = i;
+               }
+       }
+
+       IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
+                       average_noise[0], average_noise[1],
+                       average_noise[2]);
+
+       IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
+                       min_average_noise, min_average_noise_antenna_i);
+
+       iwlagn_gain_computation(
+               priv, average_noise,
+               find_first_chain(priv->eeprom_data->valid_rx_ant));
+
+       /* Some power changes may have been made during the calibration.
+        * Update and commit the RXON
+        */
+       iwl_update_chain_flags(priv);
+
+       data->state = IWL_CHAIN_NOISE_DONE;
+       iwl_power_update_mode(priv, false);
+}
+
+void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+       int i;
+       memset(&(priv->sensitivity_data), 0,
+              sizeof(struct iwl_sensitivity_data));
+       memset(&(priv->chain_noise_data), 0,
+              sizeof(struct iwl_chain_noise_data));
+       for (i = 0; i < NUM_RX_CHAINS; i++)
+               priv->chain_noise_data.delta_gain_code[i] =
+                               CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+
+       /* Ask for statistics now, the uCode will send notification
+        * periodically after association */
+       iwl_send_statistics_request(priv, CMD_ASYNC, true);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h
new file mode 100644 (file)
index 0000000..2349f39
--- /dev/null
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_calib_h__
+#define __iwl_calib_h__
+
+#include "dev.h"
+#include "commands.h"
+
+void iwl_chain_noise_calibration(struct iwl_priv *priv);
+void iwl_sensitivity_calibration(struct iwl_priv *priv);
+
+void iwl_init_sensitivity(struct iwl_priv *priv);
+void iwl_reset_run_time_calib(struct iwl_priv *priv);
+
+#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
new file mode 100644 (file)
index 0000000..64811cd
--- /dev/null
@@ -0,0 +1,3958 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (commands.h) only for uCode API definitions.
+ * Please use iwl-xxxx-hw.h for hardware-related definitions.
+ * Please use dev.h for driver implementation definitions.
+ */
+
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+#include <linux/ieee80211.h>
+#include <linux/types.h>
+
+
+enum {
+       REPLY_ALIVE = 0x1,
+       REPLY_ERROR = 0x2,
+       REPLY_ECHO = 0x3,               /* test command */
+
+       /* RXON and QOS commands */
+       REPLY_RXON = 0x10,
+       REPLY_RXON_ASSOC = 0x11,
+       REPLY_QOS_PARAM = 0x13,
+       REPLY_RXON_TIMING = 0x14,
+
+       /* Multi-Station support */
+       REPLY_ADD_STA = 0x18,
+       REPLY_REMOVE_STA = 0x19,
+       REPLY_REMOVE_ALL_STA = 0x1a,    /* not used */
+       REPLY_TXFIFO_FLUSH = 0x1e,
+
+       /* Security */
+       REPLY_WEPKEY = 0x20,
+
+       /* RX, TX, LEDs */
+       REPLY_TX = 0x1c,
+       REPLY_LEDS_CMD = 0x48,
+       REPLY_TX_LINK_QUALITY_CMD = 0x4e,
+
+       /* WiMAX coexistence */
+       COEX_PRIORITY_TABLE_CMD = 0x5a,
+       COEX_MEDIUM_NOTIFICATION = 0x5b,
+       COEX_EVENT_CMD = 0x5c,
+
+       /* Calibration */
+       TEMPERATURE_NOTIFICATION = 0x62,
+       CALIBRATION_CFG_CMD = 0x65,
+       CALIBRATION_RES_NOTIFICATION = 0x66,
+       CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+
+       /* 802.11h related */
+       REPLY_QUIET_CMD = 0x71,         /* not used */
+       REPLY_CHANNEL_SWITCH = 0x72,
+       CHANNEL_SWITCH_NOTIFICATION = 0x73,
+       REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+       SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+       /* Power Management */
+       POWER_TABLE_CMD = 0x77,
+       PM_SLEEP_NOTIFICATION = 0x7A,
+       PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+       /* Scan commands and notifications */
+       REPLY_SCAN_CMD = 0x80,
+       REPLY_SCAN_ABORT_CMD = 0x81,
+       SCAN_START_NOTIFICATION = 0x82,
+       SCAN_RESULTS_NOTIFICATION = 0x83,
+       SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+       /* IBSS/AP commands */
+       BEACON_NOTIFICATION = 0x90,
+       REPLY_TX_BEACON = 0x91,
+       WHO_IS_AWAKE_NOTIFICATION = 0x94,       /* not used */
+
+       /* Miscellaneous commands */
+       REPLY_TX_POWER_DBM_CMD = 0x95,
+       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,
+       MEASURE_ABORT_NOTIFICATION = 0x99,      /* not used */
+
+       /* Bluetooth device coexistence config command */
+       REPLY_BT_CONFIG = 0x9b,
+
+       /* Statistics */
+       REPLY_STATISTICS_CMD = 0x9c,
+       STATISTICS_NOTIFICATION = 0x9d,
+
+       /* RF-KILL commands and notifications */
+       REPLY_CARD_STATE_CMD = 0xa0,
+       CARD_STATE_NOTIFICATION = 0xa1,
+
+       /* Missed beacons notification */
+       MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+       REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+       SENSITIVITY_CMD = 0xa8,
+       REPLY_PHY_CALIBRATION_CMD = 0xb0,
+       REPLY_RX_PHY_CMD = 0xc0,
+       REPLY_RX_MPDU_CMD = 0xc1,
+       REPLY_RX = 0xc3,
+       REPLY_COMPRESSED_BA = 0xc5,
+
+       /* BT Coex */
+       REPLY_BT_COEX_PRIO_TABLE = 0xcc,
+       REPLY_BT_COEX_PROT_ENV = 0xcd,
+       REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
+
+       /* PAN commands */
+       REPLY_WIPAN_PARAMS = 0xb2,
+       REPLY_WIPAN_RXON = 0xb3,        /* use REPLY_RXON structure */
+       REPLY_WIPAN_RXON_TIMING = 0xb4, /* use REPLY_RXON_TIMING structure */
+       REPLY_WIPAN_RXON_ASSOC = 0xb6,  /* use REPLY_RXON_ASSOC structure */
+       REPLY_WIPAN_QOS_PARAM = 0xb7,   /* use REPLY_QOS_PARAM structure */
+       REPLY_WIPAN_WEPKEY = 0xb8,      /* use REPLY_WEPKEY structure */
+       REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
+       REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
+       REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd,
+
+       REPLY_WOWLAN_PATTERNS = 0xe0,
+       REPLY_WOWLAN_WAKEUP_FILTER = 0xe1,
+       REPLY_WOWLAN_TSC_RSC_PARAMS = 0xe2,
+       REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
+       REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
+       REPLY_WOWLAN_GET_STATUS = 0xe5,
+       REPLY_D3_CONFIG = 0xd3,
+
+       REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, rate_n_flags, txpower
+ *
+ *****************************************************************************/
+
+/**
+ * iwlagn rate_n_flags bit fields
+ *
+ * rate_n_flags format is used in following iwlagn commands:
+ *  REPLY_RX (response only)
+ *  REPLY_RX_MPDU (response only)
+ *  REPLY_TX (both command and response)
+ *  REPLY_TX_LINK_QUALITY_CMD
+ *
+ * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
+ *  2-0:  0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *
+ *  4-3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *        2)  Triple stream (MIMO)
+ *
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
+ *
+ * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ *
+ * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
+ *  6-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_SPATIAL_POS 3
+#define RATE_MCS_SPATIAL_MSK 0x18
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
+#define RATE_MCS_RATE_MSK 0xff
+
+/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_HT40_POS 11
+#define RATE_MCS_HT40_MSK 0x800
+
+/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+/**
+ * rate_n_flags Tx antenna masks
+ * 4965 has 2 transmitters
+ * 5100 has 1 transmitter B
+ * 5150 has 1 transmitter A
+ * 5300 has 3 transmitters
+ * 5350 has 3 transmitters
+ * bit14:16
+ */
+#define RATE_MCS_ANT_POS       14
+#define RATE_MCS_ANT_A_MSK     0x04000
+#define RATE_MCS_ANT_B_MSK     0x08000
+#define RATE_MCS_ANT_C_MSK     0x10000
+#define RATE_MCS_ANT_AB_MSK    (RATE_MCS_ANT_A_MSK | RATE_MCS_ANT_B_MSK)
+#define RATE_MCS_ANT_ABC_MSK   (RATE_MCS_ANT_AB_MSK | RATE_MCS_ANT_C_MSK)
+#define RATE_ANT_NUM 3
+
+#define POWER_TABLE_NUM_ENTRIES                        33
+#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
+
+/**
+ * struct tx_power_dual_stream
+ *
+ * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Same format as iwl_tx_power_dual_stream, but __le32
+ */
+struct tx_power_dual_stream {
+       __le32 dw;
+} __packed;
+
+/**
+ * Command REPLY_TX_POWER_DBM_CMD = 0x98
+ * struct iwlagn_tx_power_dbm_cmd
+ */
+#define IWLAGN_TX_POWER_AUTO 0x7f
+#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
+
+struct iwlagn_tx_power_dbm_cmd {
+       s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
+       u8 flags;
+       s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
+       u8 reserved;
+} __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;
+} __packed;
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK cpu_to_le32(0x1)
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *     Its header format is:
+ *
+ *     __le32 log_size;     log capacity (in number of entries)
+ *     __le32 type;         (1) timestamp with each entry, (0) no timestamp
+ *     __le32 wraps;        # times uCode has wrapped to top of circular buffer
+ *      __le32 write_index;  next circular buffer entry that uCode would fill
+ *
+ *     The header is followed by the circular buffer of log entries.  Entries
+ *     with timestamps have the following format:
+ *
+ *     __le32 event_id;     range 0 - 1500
+ *     __le32 timestamp;    low 32 bits of TSF (of network, if associated)
+ *     __le32 data;         event_id-specific data value
+ *
+ *     Entries without timestamps contain only event_id and data.
+ *
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.  For agn, the format
+ *     of the error log is defined by struct iwl_error_event_table.
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table {
+       u32 valid;              /* (nonzero) valid, (0) log is empty */
+       u32 error_id;           /* type of error */
+       u32 pc;                 /* program counter */
+       u32 blink1;             /* branch link */
+       u32 blink2;             /* branch link */
+       u32 ilink1;             /* interrupt link */
+       u32 ilink2;             /* interrupt link */
+       u32 data1;              /* error-specific data */
+       u32 data2;              /* error-specific data */
+       u32 line;               /* source code line of error */
+       u32 bcon_time;          /* beacon timer */
+       u32 tsf_low;            /* network timestamp function timer */
+       u32 tsf_hi;             /* network timestamp function timer */
+       u32 gp1;                /* GP1 timer register */
+       u32 gp2;                /* GP2 timer register */
+       u32 gp3;                /* GP3 timer register */
+       u32 ucode_ver;          /* uCode version */
+       u32 hw_ver;             /* HW Silicon version */
+       u32 brd_ver;            /* HW board version */
+       u32 log_pc;             /* log program counter */
+       u32 frame_ptr;          /* frame pointer */
+       u32 stack_ptr;          /* stack pointer */
+       u32 hcmd;               /* last host command header */
+       u32 isr0;               /* isr status register LMPM_NIC_ISR0:
+                                * rxtx_flag */
+       u32 isr1;               /* isr status register LMPM_NIC_ISR1:
+                                * host_flag */
+       u32 isr2;               /* isr status register LMPM_NIC_ISR2:
+                                * enc_flag */
+       u32 isr3;               /* isr status register LMPM_NIC_ISR3:
+                                * time_flag */
+       u32 isr4;               /* isr status register LMPM_NIC_ISR4:
+                                * wico interrupt */
+       u32 isr_pref;           /* isr status register LMPM_NIC_PREF_STAT */
+       u32 wait_event;         /* wait event() caller address */
+       u32 l2p_control;        /* L2pControlField */
+       u32 l2p_duration;       /* L2pDurationField */
+       u32 l2p_mhvalid;        /* L2pMhValidBits */
+       u32 l2p_addr_match;     /* L2pAddrMatchStat */
+       u32 lmpm_pmg_sel;       /* indicate which clocks are turned on
+                                * (LMPM_PMG_SEL) */
+       u32 u_timestamp;        /* indicate when the date and time of the
+                                * compilation */
+       u32 flow_handler;       /* FH read/write pointers, RX credit */
+} __packed;
+
+struct iwl_alive_resp {
+       u8 ucode_minor;
+       u8 ucode_major;
+       __le16 reserved1;
+       u8 sw_rev[8];
+       u8 ver_type;
+       u8 ver_subtype;                 /* not "9" for runtime alive */
+       __le16 reserved2;
+       __le32 log_event_table_ptr;     /* SRAM address for event log */
+       __le32 error_event_table_ptr;   /* SRAM address for error log */
+       __le32 timestamp;
+       __le32 is_valid;
+} __packed;
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+       __le32 error_type;
+       u8 cmd_id;
+       u8 reserved1;
+       __le16 bad_cmd_seq_num;
+       __le32 error_info;
+       __le64 timestamp;
+} __packed;
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+       RXON_DEV_TYPE_AP = 1,
+       RXON_DEV_TYPE_ESS = 3,
+       RXON_DEV_TYPE_IBSS = 4,
+       RXON_DEV_TYPE_SNIFFER = 6,
+       RXON_DEV_TYPE_CP = 7,
+       RXON_DEV_TYPE_2STA = 8,
+       RXON_DEV_TYPE_P2P = 9,
+};
+
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK         cpu_to_le16(0x1 << 0)
+#define RXON_RX_CHAIN_DRIVER_FORCE_POS         (0)
+#define RXON_RX_CHAIN_VALID_MSK                        cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_VALID_POS                        (1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK            cpu_to_le16(0x7 << 4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS            (4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK       cpu_to_le16(0x7 << 7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS       (7)
+#define RXON_RX_CHAIN_CNT_MSK                  cpu_to_le16(0x3 << 10)
+#define RXON_RX_CHAIN_CNT_POS                  (10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK             cpu_to_le16(0x3 << 12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS             (12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK           cpu_to_le16(0x1 << 14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS           (14)
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
+
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS          (22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK       cpu_to_le32(0x1 << 22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS         (23)
+
+#define RXON_FLG_HT_PROT_MSK                   cpu_to_le32(0x1 << 23)
+#define RXON_FLG_HT40_PROT_MSK                 cpu_to_le32(0x2 << 23)
+
+#define RXON_FLG_CHANNEL_MODE_POS              (25)
+#define RXON_FLG_CHANNEL_MODE_MSK              cpu_to_le32(0x3 << 25)
+
+/* channel mode */
+enum {
+       CHANNEL_MODE_LEGACY = 0,
+       CHANNEL_MODE_PURE_40 = 1,
+       CHANNEL_MODE_MIXED = 2,
+       CHANNEL_MODE_RESERVED = 3,
+};
+#define RXON_FLG_CHANNEL_MODE_LEGACY   cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_PURE_40  cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
+#define RXON_FLG_CHANNEL_MODE_MIXED    cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
+
+/* CTS to self (if spec allows) flag */
+#define RXON_FLG_SELF_CTS_EN                   cpu_to_le32(0x1<<30)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+
+struct iwl_rxon_cmd {
+       u8 node_addr[6];
+       __le16 reserved1;
+       u8 bssid_addr[6];
+       __le16 reserved2;
+       u8 wlap_bssid_addr[6];
+       __le16 reserved3;
+       u8 dev_type;
+       u8 air_propagation;
+       __le16 rx_chain;
+       u8 ofdm_basic_rates;
+       u8 cck_basic_rates;
+       __le16 assoc_id;
+       __le32 flags;
+       __le32 filter_flags;
+       __le16 channel;
+       u8 ofdm_ht_single_stream_basic_rates;
+       u8 ofdm_ht_dual_stream_basic_rates;
+       u8 ofdm_ht_triple_stream_basic_rates;
+       u8 reserved5;
+       __le16 acquisition_data;
+       __le16 reserved6;
+} __packed;
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl_rxon_assoc_cmd {
+       __le32 flags;
+       __le32 filter_flags;
+       u8 ofdm_basic_rates;
+       u8 cck_basic_rates;
+       __le16 reserved1;
+       u8 ofdm_ht_single_stream_basic_rates;
+       u8 ofdm_ht_dual_stream_basic_rates;
+       u8 ofdm_ht_triple_stream_basic_rates;
+       u8 reserved2;
+       __le16 rx_chain_select_flags;
+       __le16 acquisition_data;
+       __le32 reserved3;
+} __packed;
+
+#define IWL_CONN_MAX_LISTEN_INTERVAL   10
+#define IWL_MAX_UCODE_BEACON_INTERVAL  4 /* 4096 */
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl_rxon_time_cmd {
+       __le64 timestamp;
+       __le16 beacon_interval;
+       __le16 atim_window;
+       __le32 beacon_init_val;
+       __le16 listen_interval;
+       u8 dtim_period;
+       u8 delta_cp_bss_tbtts;
+} __packed;
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+/**
+ * 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];
+} __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];
+} __packed;
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+       __le16 band;
+       __le16 channel;
+       __le32 status;          /* 0 - OK, 1 - fail */
+} __packed;
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl_ac_qos {
+       __le16 cw_min;
+       __le16 cw_max;
+       u8 aifsn;
+       u8 reserved1;
+       __le16 edca_txop;
+} __packed;
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK  cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK          cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK    cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl_qosparam_cmd {
+       __le32 qos_flags;
+       struct iwl_ac_qos ac[AC_NUM];
+} __packed;
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define        IWL_AP_ID               0
+#define        IWL_AP_ID_PAN           1
+#define        IWL_STA_ID              2
+#define IWLAGN_PAN_BCAST_ID    14
+#define IWLAGN_BROADCAST_ID    15
+#define        IWLAGN_STATION_COUNT    16
+
+#define        IWL_INVALID_STATION     255
+#define IWL_MAX_TID_COUNT      8
+#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
+
+#define STA_FLG_TX_RATE_MSK            cpu_to_le32(1 << 2)
+#define STA_FLG_PWR_SAVE_MSK           cpu_to_le32(1 << 8)
+#define STA_FLG_PAN_STATION            cpu_to_le32(1 << 13)
+#define STA_FLG_RTS_MIMO_PROT_MSK      cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK       cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS       (19)
+#define STA_FLG_MAX_AGG_SIZE_MSK       cpu_to_le32(3 << 19)
+#define STA_FLG_HT40_EN_MSK            cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK           cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS   (23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK   cpu_to_le32(7 << 23)
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK         0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK        cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC     cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP                cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP       cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP       cpu_to_le16(0x0003)
+
+#define STA_KEY_FLG_KEYID_POS  8
+#define STA_KEY_FLG_INVALID    cpu_to_le16(0x0800)
+/* wep key is either from global key (0) or from station info array (1) */
+#define STA_KEY_FLG_MAP_KEY_MSK        cpu_to_le16(0x0008)
+
+/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
+#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
+#define STA_KEY_MAX_NUM                8
+#define STA_KEY_MAX_NUM_PAN    16
+/* must not match WEP_INVALID_OFFSET */
+#define IWLAGN_HW_KEY_DEFAULT  0xfe
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define        STA_MODIFY_KEY_MASK             0x01
+#define        STA_MODIFY_TID_DISABLE_TX       0x02
+#define        STA_MODIFY_TX_RATE_MSK          0x04
+#define STA_MODIFY_ADDBA_TID_MSK       0x08
+#define STA_MODIFY_DELBA_TID_MSK       0x10
+#define STA_MODIFY_SLEEP_TX_COUNT_MSK  0x20
+
+/* Receiver address (actually, Rx station's index into station table),
+ * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
+#define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
+
+/* agn */
+struct iwl_keyinfo {
+       __le16 key_flags;
+       u8 tkip_rx_tsc_byte2;   /* TSC[2] for key mix ph1 detection */
+       u8 reserved1;
+       __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
+       u8 key_offset;
+       u8 reserved2;
+       u8 key[16];             /* 16-byte unicast decryption key */
+       __le64 tx_secur_seq_cnt;
+       __le64 hw_tkip_mic_rx_key;
+       __le64 hw_tkip_mic_tx_key;
+} __packed;
+
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+       u8 addr[ETH_ALEN];
+       __le16 reserved1;
+       u8 sta_id;
+       u8 modify_mask;
+       __le16 reserved2;
+} __packed;
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (agn devices uses
+ * REPLY_TX_LINK_QUALITY_CMD,
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+
+struct iwl_addsta_cmd {
+       u8 mode;                /* 1: modify existing, 0: add new station */
+       u8 reserved[3];
+       struct sta_id_modify sta;
+       struct iwl_keyinfo key;
+       __le32 station_flags;           /* STA_FLG_* */
+       __le32 station_flags_msk;       /* STA_FLG_* */
+
+       /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+        * corresponding to bit (e.g. bit 5 controls TID 5).
+        * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+       __le16 tid_disable_tx;
+       __le16 legacy_reserved;
+
+       /* TID for which to add block-ack support.
+        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+       u8 add_immediate_ba_tid;
+
+       /* TID for which to remove block-ack support.
+        * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+       u8 remove_immediate_ba_tid;
+
+       /* Starting Sequence Number for added block-ack support.
+        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+       __le16 add_immediate_ba_ssn;
+
+       /*
+        * Number of packets OK to transmit to station even though
+        * it is asleep -- used to synchronise PS-poll and u-APSD
+        * responses while ucode keeps track of STA sleep state.
+        */
+       __le16 sleep_tx_count;
+
+       __le16 reserved2;
+} __packed;
+
+
+#define ADD_STA_SUCCESS_MSK            0x1
+#define ADD_STA_NO_ROOM_IN_TABLE       0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE  0x4
+#define ADD_STA_MODIFY_NON_EXIST_STA   0x8
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+       u8 status;      /* ADD_STA_* */
+} __packed;
+
+#define REM_STA_SUCCESS_MSK              0x1
+/*
+ *  REPLY_REM_STA = 0x19 (response)
+ */
+struct iwl_rem_sta_resp {
+       u8 status;
+} __packed;
+
+/*
+ *  REPLY_REM_STA = 0x19 (command)
+ */
+struct iwl_rem_sta_cmd {
+       u8 num_sta;     /* number of removed stations */
+       u8 reserved[3];
+       u8 addr[ETH_ALEN]; /* MAC addr of the first station */
+       u8 reserved2[2];
+} __packed;
+
+
+/* WiFi queues mask */
+#define IWL_SCD_BK_MSK                 cpu_to_le32(BIT(0))
+#define IWL_SCD_BE_MSK                 cpu_to_le32(BIT(1))
+#define IWL_SCD_VI_MSK                 cpu_to_le32(BIT(2))
+#define IWL_SCD_VO_MSK                 cpu_to_le32(BIT(3))
+#define IWL_SCD_MGMT_MSK               cpu_to_le32(BIT(3))
+
+/* PAN queues mask */
+#define IWL_PAN_SCD_BK_MSK             cpu_to_le32(BIT(4))
+#define IWL_PAN_SCD_BE_MSK             cpu_to_le32(BIT(5))
+#define IWL_PAN_SCD_VI_MSK             cpu_to_le32(BIT(6))
+#define IWL_PAN_SCD_VO_MSK             cpu_to_le32(BIT(7))
+#define IWL_PAN_SCD_MGMT_MSK           cpu_to_le32(BIT(7))
+#define IWL_PAN_SCD_MULTICAST_MSK      cpu_to_le32(BIT(8))
+
+#define IWL_AGG_TX_QUEUE_MSK           cpu_to_le32(0xffc00)
+
+#define IWL_DROP_SINGLE                0
+#define IWL_DROP_ALL           (BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN))
+
+/*
+ * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
+ *
+ * When using full FIFO flush this command checks the scheduler HW block WR/RD
+ * pointers to check if all the frames were transferred by DMA into the
+ * relevant TX FIFO queue. Only when the DMA is finished and the queue is
+ * empty the command can finish.
+ * This command is used to flush the TXFIFO from transmit commands, it may
+ * operate on single or multiple queues, the command queue can't be flushed by
+ * this command. The command response is returned when all the queue flush
+ * operations are done. Each TX command flushed return response with the FLUSH
+ * status set in the TX response status. When FIFO flush operation is used,
+ * the flush operation ends when both the scheduler DMA done and TXFIFO empty
+ * are set.
+ *
+ * @fifo_control: bit mask for which queues to flush
+ * @flush_control: flush controls
+ *     0: Dump single MSDU
+ *     1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
+ *     2: Dump all FIFO
+ */
+struct iwl_txfifo_flush_cmd {
+       __le32 fifo_control;
+       __le16 flush_control;
+       __le16 reserved;
+} __packed;
+
+/*
+ * REPLY_WEP_KEY = 0x20
+ */
+struct iwl_wep_key {
+       u8 key_index;
+       u8 key_offset;
+       u8 reserved1[2];
+       u8 key_size;
+       u8 reserved2[3];
+       u8 key[16];
+} __packed;
+
+struct iwl_wep_cmd {
+       u8 num_keys;
+       u8 global_key_type;
+       u8 flags;
+       u8 reserved;
+       struct iwl_wep_key key[0];
+} __packed;
+
+#define WEP_KEY_WEP_TYPE 1
+#define WEP_KEYS_MAX 4
+#define WEP_INVALID_OFFSET 0xff
+#define WEP_KEY_LEN_64 5
+#define WEP_KEY_LEN_128 13
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+#define RX_RES_STATUS_NO_CRC32_ERROR   cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW  cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK   cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK           cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK    cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK       cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK           0xf0
+#define RX_RES_PHY_FLAGS_ANTENNA_POS           4
+
+#define RX_RES_STATUS_SEC_TYPE_MSK     (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE    (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP     (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP    (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP    (0x3 << 8)
+#define        RX_RES_STATUS_SEC_TYPE_ERR      (0x7 << 8)
+
+#define RX_RES_STATUS_STATION_FOUND    (1<<6)
+#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT      (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK       (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC      (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK     (0x2 << 11)
+
+#define RX_MPDU_RES_STATUS_ICV_OK      (0x20)
+#define RX_MPDU_RES_STATUS_MIC_OK      (0x40)
+#define RX_MPDU_RES_STATUS_TTAK_OK     (1 << 7)
+#define RX_MPDU_RES_STATUS_DEC_DONE_MSK        (0x800)
+
+
+#define IWLAGN_RX_RES_PHY_CNT 8
+#define IWLAGN_RX_RES_AGC_IDX     1
+#define IWLAGN_RX_RES_RSSI_AB_IDX 2
+#define IWLAGN_RX_RES_RSSI_C_IDX  3
+#define IWLAGN_OFDM_AGC_MSK 0xfe00
+#define IWLAGN_OFDM_AGC_BIT_POS 9
+#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
+#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
+#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
+#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
+#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
+
+struct iwlagn_non_cfg_phy {
+       __le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT];  /* up to 8 phy entries */
+} __packed;
+
+
+/*
+ * REPLY_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+struct iwl_rx_phy_res {
+       u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+       u8 cfg_phy_cnt;         /* configurable DSP phy data byte count */
+       u8 stat_id;             /* configurable DSP phy data set ID */
+       u8 reserved1;
+       __le64 timestamp;       /* TSF at on air rise */
+       __le32 beacon_time_stamp; /* beacon at on-air rise */
+       __le16 phy_flags;       /* general phy flags: band, modulation, ... */
+       __le16 channel;         /* channel number */
+       u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
+       __le32 rate_n_flags;    /* RATE_MCS_* */
+       __le16 byte_count;      /* frame's byte-count */
+       __le16 frame_time;      /* frame's time on the air */
+} __packed;
+
+struct iwl_rx_mpdu_res_start {
+       __le16 byte_count;
+       __le16 reserved;
+} __packed;
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device (see comments for
+ * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
+ * are preparing to transmit, the device pulls the Tx command over the PCI
+ * bus via one of the device's Tx DMA channels, to fill an internal FIFO
+ * from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
+ * handle reception of block-acks; uCode updates the host driver via
+ * REPLY_COMPRESSED_BA.
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_TX_LINK_QUALITY_CMD (agn).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/*
+ * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
+ * before this frame. if CTS-to-self required check
+ * RXON_FLG_SELF_CTS_EN status.
+ */
+#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
+
+/* For agn devices:
+ * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
+
+/* Tx antenna selection field; reserved (0) for agn devices. */
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_IGNORE_BT cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
+
+/* accelerate aggregation support
+ * 0 - no CCMP encryption; 1 - CCMP encryption */
+#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
+
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP         0x01
+#define TX_CMD_SEC_CCM         0x02
+#define TX_CMD_SEC_TKIP                0x03
+#define TX_CMD_SEC_MSK         0x03
+#define TX_CMD_SEC_SHIFT       6
+#define TX_CMD_SEC_KEY128      0x08
+
+/*
+ * security overhead sizes
+ */
+#define WEP_IV_LEN 4
+#define WEP_ICV_LEN 4
+#define CCMP_MIC_LEN 8
+#define TKIP_ICV_LEN 4
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+
+/*
+ * 4965 uCode updates these Tx attempt count values in host DRAM.
+ * Used for managing Tx retries when expecting block-acks.
+ * Driver should set these fields to 0.
+ */
+struct iwl_dram_scratch {
+       u8 try_cnt;             /* Tx attempts */
+       u8 bt_kill_cnt;         /* Tx attempts blocked by Bluetooth device */
+       __le16 reserved;
+} __packed;
+
+struct iwl_tx_cmd {
+       /*
+        * MPDU byte count:
+        * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+        * + 8 byte IV for CCM or TKIP (not used for WEP)
+        * + Data payload
+        * + 8-byte MIC (not used for CCM/WEP)
+        * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+        *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+        * Range: 14-2342 bytes.
+        */
+       __le16 len;
+
+       /*
+        * MPDU or MSDU byte count for next frame.
+        * Used for fragmentation and bursting, but not 11n aggregation.
+        * Same as "len", but for next frame.  Set to 0 if not applicable.
+        */
+       __le16 next_frame_len;
+
+       __le32 tx_flags;        /* TX_CMD_FLG_* */
+
+       /* uCode may modify this field of the Tx command (in host DRAM!).
+        * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
+       struct iwl_dram_scratch scratch;
+
+       /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
+       __le32 rate_n_flags;    /* RATE_MCS_* */
+
+       /* Index of destination station in uCode's station table */
+       u8 sta_id;
+
+       /* Type of security encryption:  CCM or TKIP */
+       u8 sec_ctl;             /* TX_CMD_SEC_* */
+
+       /*
+        * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
+        * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
+        * data frames, this field may be used to selectively reduce initial
+        * rate (via non-0 value) for special frames (e.g. management), while
+        * still supporting rate scaling for all frames.
+        */
+       u8 initial_rate_index;
+       u8 reserved;
+       u8 key[16];
+       __le16 next_frame_flags;
+       __le16 reserved2;
+       union {
+               __le32 life_time;
+               __le32 attempt;
+       } stop_time;
+
+       /* Host DRAM physical address pointer to "scratch" in this command.
+        * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
+       __le32 dram_lsb_ptr;
+       u8 dram_msb_ptr;
+
+       u8 rts_retry_limit;     /*byte 50 */
+       u8 data_retry_limit;    /*byte 51 */
+       u8 tid_tspec;
+       union {
+               __le16 pm_frame_timeout;
+               __le16 attempt_duration;
+       } timeout;
+
+       /*
+        * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+        * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+        */
+       __le16 driver_txop;
+
+       /*
+        * MAC header goes here, followed by 2 bytes padding if MAC header
+        * length is 26 or 30 bytes, followed by payload data
+        */
+       u8 payload[0];
+       struct ieee80211_hdr hdr[0];
+} __packed;
+
+/*
+ * TX command response is sent after *agn* transmission attempts.
+ *
+ * both postpone and abort status are expected behavior from uCode. there is
+ * no special operation required from driver; except for RFKILL_FLUSH,
+ * which required tx flush host command to flush all the tx frames in queues
+ */
+enum {
+       TX_STATUS_SUCCESS = 0x01,
+       TX_STATUS_DIRECT_DONE = 0x02,
+       /* postpone TX */
+       TX_STATUS_POSTPONE_DELAY = 0x40,
+       TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+       TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+       TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+       TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+       /* abort TX */
+       TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
+       TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+       TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+       TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+       TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+       TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
+       TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+       TX_STATUS_FAIL_DEST_PS = 0x88,
+       TX_STATUS_FAIL_HOST_ABORTED = 0x89,
+       TX_STATUS_FAIL_BT_RETRY = 0x8a,
+       TX_STATUS_FAIL_STA_INVALID = 0x8b,
+       TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+       TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+       TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
+       TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+       TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
+       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define        TX_PACKET_MODE_REGULAR          0x0000
+#define        TX_PACKET_MODE_BURST_SEQ        0x0100
+#define        TX_PACKET_MODE_BURST_FIRST      0x0200
+
+enum {
+       TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+       TX_STATUS_MSK = 0x000000ff,             /* bits 0:7 */
+       TX_STATUS_DELAY_MSK = 0x00000040,
+       TX_STATUS_ABORT_MSK = 0x00000080,
+       TX_PACKET_MODE_MSK = 0x0000ff00,        /* bits 8:15 */
+       TX_FIFO_NUMBER_MSK = 0x00070000,        /* bits 16:18 */
+       TX_RESERVED = 0x00780000,               /* bits 19:22 */
+       TX_POWER_PA_DETECT_MSK = 0x7f800000,    /* bits 23:30 */
+       TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation status
+ ******************************* */
+
+enum {
+       AGG_TX_STATE_TRANSMITTED = 0x00,
+       AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+       AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+       AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+       AGG_TX_STATE_ABORT_MSK = 0x08,
+       AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+       AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+       AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+       AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+       AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+       AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+       AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+       AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATUS_MSK      0x00000fff      /* bits 0:11 */
+#define AGG_TX_TRY_MSK         0x0000f000      /* bits 12:15 */
+
+#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+                                    AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+                                    AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)  No aggregation (frame_count == 1).  This reports Tx results for
+ *     a single frame.  Multiple attempts, at various bit rates, may have
+ *     been made for this frame.
+ *
+ * 2)  Aggregation (frame_count > 1).  This reports Tx results for
+ *     2 or more frames that used block-acknowledge.  All frames were
+ *     transmitted at same rate.  Rate scaling may have been used if first
+ *     frame in this new agg block failed in previous agg block(s).
+ *
+ *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
+ *     block-ack has not been received by the time the agn device records
+ *     this status.
+ *     This status relates to reasons the tx might have been blocked or aborted
+ *     within the sending station (this agn device), rather than whether it was
+ *     received successfully by the destination station.
+ */
+struct agg_tx_status {
+       __le16 status;
+       __le16 sequence;
+} __packed;
+
+/*
+ * definitions for initial rate index field
+ * bits [3:0] initial rate index
+ * bits [6:4] rate table color, used for the initial rate
+ * bit-7 invalid rate indication
+ *   i.e. rate was not chosen from rate table
+ *   or rate table color was changed during frame retries
+ * refer tlc rate info
+ */
+
+#define IWL50_TX_RES_INIT_RATE_INDEX_POS       0
+#define IWL50_TX_RES_INIT_RATE_INDEX_MSK       0x0f
+#define IWL50_TX_RES_RATE_TABLE_COLOR_POS      4
+#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK      0x70
+#define IWL50_TX_RES_INV_RATE_INDEX_MSK        0x80
+
+/* refer to ra_tid */
+#define IWLAGN_TX_RES_TID_POS  0
+#define IWLAGN_TX_RES_TID_MSK  0x0f
+#define IWLAGN_TX_RES_RA_POS   4
+#define IWLAGN_TX_RES_RA_MSK   0xf0
+
+struct iwlagn_tx_resp {
+       u8 frame_count;         /* 1 no aggregation, >1 aggregation */
+       u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
+       u8 failure_rts;         /* # failures due to unsuccessful RTS */
+       u8 failure_frame;       /* # failures due to no ACK (unused for agg) */
+
+       /* For non-agg:  Rate at which frame was successful.
+        * For agg:  Rate at which all frames were transmitted. */
+       __le32 rate_n_flags;    /* RATE_MCS_*  */
+
+       /* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+        * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
+       __le16 wireless_media_time;     /* uSecs */
+
+       u8 pa_status;           /* RF power amplifier measurement (not used) */
+       u8 pa_integ_res_a[3];
+       u8 pa_integ_res_b[3];
+       u8 pa_integ_res_C[3];
+
+       __le32 tfd_info;
+       __le16 seq_ctl;
+       __le16 byte_cnt;
+       u8 tlc_info;
+       u8 ra_tid;              /* tid (0:3), sta_id (4:7) */
+       __le16 frame_ctrl;
+       /*
+        * For non-agg:  frame status TX_STATUS_*
+        * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+        *           fields follow this one, up to frame_count.
+        *           Bit fields:
+        *           11- 0:  AGG_TX_STATE_* status code
+        *           15-12:  Retry count for 1st frame in aggregation (retries
+        *                   occur if tx failed for this frame when it was a
+        *                   member of a previous aggregation block).  If rate
+        *                   scaling is used, retry count indicates the rate
+        *                   table entry used for all frames in the new agg.
+        *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
+        */
+       struct agg_tx_status status;    /* TX status (in aggregation -
+                                        * status of 1st frame) */
+} __packed;
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ *
+ * Reports Block-Acknowledge from recipient station
+ */
+struct iwl_compressed_ba_resp {
+       __le32 sta_addr_lo32;
+       __le16 sta_addr_hi16;
+       __le16 reserved;
+
+       /* Index of recipient (BA-sending) station in uCode's station table */
+       u8 sta_id;
+       u8 tid;
+       __le16 seq_ctl;
+       __le64 bitmap;
+       __le16 scd_flow;
+       __le16 scd_ssn;
+       u8 txed;        /* number of frames sent */
+       u8 txed_2_done; /* number of frames acked */
+} __packed;
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ *
+ */
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK   (1 << 0)
+
+/* # of EDCA prioritized tx fifos */
+#define  LINK_QUAL_AC_NUM AC_NUM
+
+/* # entries in rate scale table to support Tx retries */
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+/* Tx antenna selection values */
+#define  LINK_QUAL_ANT_A_MSK (1 << 0)
+#define  LINK_QUAL_ANT_B_MSK (1 << 1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+
+/**
+ * struct iwl_link_qual_general_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_general_params {
+       u8 flags;
+
+       /* No entries at or above this (driver chosen) index contain MIMO */
+       u8 mimo_delimiter;
+
+       /* Best single antenna to use for single stream (legacy, SISO). */
+       u8 single_stream_ant_msk;       /* LINK_QUAL_ANT_* */
+
+       /* Best antennas to use for MIMO (unused for 4965, assumes both). */
+       u8 dual_stream_ant_msk;         /* LINK_QUAL_ANT_* */
+
+       /*
+        * If driver needs to use different initial rates for different
+        * EDCA QOS access categories (as implemented by tx fifos 0-3),
+        * this table will set that up, by indicating the indexes in the
+        * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
+        * Otherwise, driver should set all entries to 0.
+        *
+        * Entry usage:
+        * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
+        * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
+        */
+       u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __packed;
+
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (100)
+
+#define LINK_QUAL_AGG_DISABLE_START_DEF        (3)
+#define LINK_QUAL_AGG_DISABLE_START_MAX        (255)
+#define LINK_QUAL_AGG_DISABLE_START_MIN        (0)
+
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF  (63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX  (63)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MIN  (0)
+
+/**
+ * struct iwl_link_qual_agg_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_agg_params {
+
+       /*
+        *Maximum number of uSec in aggregation.
+        * default set to 4000 (4 milliseconds) if not configured in .cfg
+        */
+       __le16 agg_time_limit;
+
+       /*
+        * Number of Tx retries allowed for a frame, before that frame will
+        * no longer be considered for the start of an aggregation sequence
+        * (scheduler will then try to tx it as single frame).
+        * Driver should set this to 3.
+        */
+       u8 agg_dis_start_th;
+
+       /*
+        * Maximum number of frames in aggregation.
+        * 0 = no limit (default).  1 = no aggregation.
+        * Other values = max # frames in aggregation.
+        */
+       u8 agg_frame_cnt_limit;
+
+       __le32 reserved;
+} __packed;
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ *
+ * For agn devices
+ *
+ * Each station in the agn device's internal station table has its own table
+ * of 16
+ * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
+ * an ACK is not received.  This command replaces the entire table for
+ * one station.
+ *
+ * NOTE:  Station must already be in agn device's station table.
+ *       Use REPLY_ADD_STA.
+ *
+ * The rate scaling procedures described below work well.  Of course, other
+ * procedures are possible, and may work better for particular environments.
+ *
+ *
+ * FILLING THE RATE TABLE
+ *
+ * Given a particular initial rate and mode, as determined by the rate
+ * scaling algorithm described below, the Linux driver uses the following
+ * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
+ * Link Quality command:
+ *
+ *
+ * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
+ *     a) Use this same initial rate for first 3 entries.
+ *     b) Find next lower available rate using same mode (SISO or MIMO),
+ *        use for next 3 entries.  If no lower rate available, switch to
+ *        legacy mode (no HT40 channel, no MIMO, no short guard interval).
+ *     c) If using MIMO, set command's mimo_delimiter to number of entries
+ *        using MIMO (3 or 6).
+ *     d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
+ *        no MIMO, no short guard interval), at the next lower bit rate
+ *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
+ *        legacy procedure for remaining table entries.
+ *
+ * 2)  If using legacy initial rate:
+ *     a) Use the initial rate for only one entry.
+ *     b) For each following entry, reduce the rate to next lower available
+ *        rate, until reaching the lowest available rate.
+ *     c) When reducing rate, also switch antenna selection.
+ *     d) Once lowest available rate is reached, repeat this rate until
+ *        rate table is filled (16 entries), switching antenna each entry.
+ *
+ *
+ * ACCUMULATING HISTORY
+ *
+ * The rate scaling algorithm for agn devices, as implemented in Linux driver,
+ * uses two sets of frame Tx success history:  One for the current/active
+ * modulation mode, and one for a speculative/search mode that is being
+ * attempted. If the speculative mode turns out to be more effective (i.e.
+ * actual transfer rate is better), then the driver continues to use the
+ * speculative mode as the new current active mode.
+ *
+ * Each history set contains, separately for each possible rate, data for a
+ * sliding window of the 62 most recent tx attempts at that rate.  The data
+ * includes a shifting bitmap of success(1)/failure(0), and sums of successful
+ * and attempted frames, from which the driver can additionally calculate a
+ * success ratio (success / attempted) and number of failures
+ * (attempted - success), and control the size of the window (attempted).
+ * The driver uses the bit map to remove successes from the success sum, as
+ * the oldest tx attempts fall out of the window.
+ *
+ * When the agn device makes multiple tx attempts for a given frame, each
+ * attempt might be at a different rate, and have different modulation
+ * characteristics (e.g. antenna, fat channel, short guard interval), as set
+ * up in the rate scaling table in the Link Quality command.  The driver must
+ * determine which rate table entry was used for each tx attempt, to determine
+ * which rate-specific history to update, and record only those attempts that
+ * match the modulation characteristics of the history set.
+ *
+ * When using block-ack (aggregation), all frames are transmitted at the same
+ * rate, since there is no per-attempt acknowledgment from the destination
+ * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
+ * rate_n_flags field.  After receiving a block-ack, the driver can update
+ * history for the entire block all at once.
+ *
+ *
+ * FINDING BEST STARTING RATE:
+ *
+ * When working with a selected initial modulation mode (see below), the
+ * driver attempts to find a best initial rate.  The initial rate is the
+ * first entry in the Link Quality command's rate table.
+ *
+ * 1)  Calculate actual throughput (success ratio * expected throughput, see
+ *     table below) for current initial rate.  Do this only if enough frames
+ *     have been attempted to make the value meaningful:  at least 6 failed
+ *     tx attempts, or at least 8 successes.  If not enough, don't try rate
+ *     scaling yet.
+ *
+ * 2)  Find available rates adjacent to current initial rate.  Available means:
+ *     a)  supported by hardware &&
+ *     b)  supported by association &&
+ *     c)  within any constraints selected by user
+ *
+ * 3)  Gather measured throughputs for adjacent rates.  These might not have
+ *     enough history to calculate a throughput.  That's okay, we might try
+ *     using one of them anyway!
+ *
+ * 4)  Try decreasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  lower adjacent rate has better measured throughput ||
+ *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
+ *
+ *     As a sanity check, if decrease was determined above, leave rate
+ *     unchanged if:
+ *     a)  lower rate unavailable
+ *     b)  success ratio at current rate > 85% (very good)
+ *     c)  current measured throughput is better than expected throughput
+ *         of lower rate (under perfect 100% tx conditions, see table below)
+ *
+ * 5)  Try increasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
+ *     b)  higher adjacent rate has better measured throughput ||
+ *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
+ *
+ *     As a sanity check, if increase was determined above, leave rate
+ *     unchanged if:
+ *     a)  success ratio at current rate < 70%.  This is not particularly
+ *         good performance; higher rate is sure to have poorer success.
+ *
+ * 6)  Re-evaluate the rate after each tx frame.  If working with block-
+ *     acknowledge, history and statistics may be calculated for the entire
+ *     block (including prior history that fits within the history windows),
+ *     before re-evaluation.
+ *
+ * FINDING BEST STARTING MODULATION MODE:
+ *
+ * After working with a modulation mode for a "while" (and doing rate scaling),
+ * the driver searches for a new initial mode in an attempt to improve
+ * throughput.  The "while" is measured by numbers of attempted frames:
+ *
+ * For legacy mode, search for new mode after:
+ *   480 successful frames, or 160 failed frames
+ * For high-throughput modes (SISO or MIMO), search for new mode after:
+ *   4500 successful frames, or 400 failed frames
+ *
+ * Mode switch possibilities are (3 for each mode):
+ *
+ * For legacy:
+ *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
+ * For SISO:
+ *   Change antenna, try MIMO, try shortened guard interval (SGI)
+ * For MIMO:
+ *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
+ *
+ * When trying a new mode, use the same bit rate as the old/current mode when
+ * trying antenna switches and shortened guard interval.  When switching to
+ * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
+ * for which the expected throughput (under perfect conditions) is about the
+ * same or slightly better than the actual measured throughput delivered by
+ * the old/current mode.
+ *
+ * Actual throughput can be estimated by multiplying the expected throughput
+ * by the success ratio (successful / attempted tx frames).  Frame size is
+ * not considered in this calculation; it assumes that frame size will average
+ * out to be fairly consistent over several samples.  The following are
+ * metric values for expected throughput assuming 100% success ratio.
+ * Only G band has support for CCK rates:
+ *
+ *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
+ *
+ *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
+ *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
+ *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
+ * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
+ *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
+ * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
+ *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
+ * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
+ *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
+ * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
+ *
+ * After the new mode has been tried for a short while (minimum of 6 failed
+ * frames or 8 successful frames), compare success ratio and actual throughput
+ * estimate of the new mode with the old.  If either is better with the new
+ * mode, continue to use the new mode.
+ *
+ * Continue comparing modes until all 3 possibilities have been tried.
+ * If moving from legacy to HT, try all 3 possibilities from the new HT
+ * mode.  After trying all 3, a best mode is found.  Continue to use this mode
+ * for the longer "while" described above (e.g. 480 successful frames for
+ * legacy), and then repeat the search process.
+ *
+ */
+struct iwl_link_quality_cmd {
+
+       /* Index of destination/recipient station in uCode's station table */
+       u8 sta_id;
+       u8 reserved1;
+       __le16 control;         /* not used */
+       struct iwl_link_qual_general_params general_params;
+       struct iwl_link_qual_agg_params agg_params;
+
+       /*
+        * Rate info; when using rate-scaling, Tx command's initial_rate_index
+        * specifies 1st Tx rate attempted, via index into this table.
+        * agn devices works its way through table when retrying Tx.
+        */
+       struct {
+               __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
+       } rs_table[LINK_QUAL_MAX_RETRY_NUM];
+       __le32 reserved2;
+} __packed;
+
+/*
+ * BT configuration enable flags:
+ *   bit 0 - 1: BT channel announcement enabled
+ *           0: disable
+ *   bit 1 - 1: priority of BT device enabled
+ *           0: disable
+ *   bit 2 - 1: BT 2 wire support enabled
+ *           0: disable
+ */
+#define BT_COEX_DISABLE (0x0)
+#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
+#define BT_ENABLE_PRIORITY        BIT(1)
+#define BT_ENABLE_2_WIRE          BIT(2)
+
+#define BT_COEX_DISABLE (0x0)
+#define BT_COEX_ENABLE  (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
+
+#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)
+
+#define BT_DURATION_LIMIT_DEF  625
+#define BT_DURATION_LIMIT_MAX  1250
+#define BT_DURATION_LIMIT_MIN  625
+
+#define BT_ON_THRESHOLD_DEF    4
+#define BT_ON_THRESHOLD_MAX    1000
+#define BT_ON_THRESHOLD_MIN    1
+
+#define BT_FRAG_THRESHOLD_DEF  0
+#define BT_FRAG_THRESHOLD_MAX  0
+#define BT_FRAG_THRESHOLD_MIN  0
+
+#define BT_AGG_THRESHOLD_DEF   1200
+#define BT_AGG_THRESHOLD_MAX   8000
+#define BT_AGG_THRESHOLD_MIN   400
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ *
+ * agn devices support hardware handshake with Bluetooth device on
+ * same platform.  Bluetooth device alerts wireless device when it will Tx;
+ * wireless device can delay or kill its own Tx to accommodate.
+ */
+struct iwl_bt_cmd {
+       u8 flags;
+       u8 lead_time;
+       u8 max_kill;
+       u8 reserved;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+} __packed;
+
+#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION      BIT(0)
+
+#define IWLAGN_BT_FLAG_COEX_MODE_MASK          (BIT(3)|BIT(4)|BIT(5))
+#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT         3
+#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED      0
+#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W     1
+#define IWLAGN_BT_FLAG_COEX_MODE_3W            2
+#define IWLAGN_BT_FLAG_COEX_MODE_4W            3
+
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT           BIT(6)
+/* Disable Sync PSPoll on SCO/eSCO */
+#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE       BIT(7)
+
+#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD       -75 /* dBm */
+#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD       -65 /* dBm */
+
+#define IWLAGN_BT_PRIO_BOOST_MAX       0xFF
+#define IWLAGN_BT_PRIO_BOOST_MIN       0x00
+#define IWLAGN_BT_PRIO_BOOST_DEFAULT   0xF0
+
+#define IWLAGN_BT_MAX_KILL_DEFAULT     5
+
+#define IWLAGN_BT3_T7_DEFAULT          1
+
+enum iwl_bt_kill_idx {
+       IWL_BT_KILL_DEFAULT = 0,
+       IWL_BT_KILL_OVERRIDE = 1,
+       IWL_BT_KILL_REDUCE = 2,
+};
+
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT        cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT        cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO        cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE     cpu_to_le32(0)
+
+#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
+
+#define IWLAGN_BT3_T2_DEFAULT          0xc
+
+#define IWLAGN_BT_VALID_ENABLE_FLAGS   cpu_to_le16(BIT(0))
+#define IWLAGN_BT_VALID_BOOST          cpu_to_le16(BIT(1))
+#define IWLAGN_BT_VALID_MAX_KILL       cpu_to_le16(BIT(2))
+#define IWLAGN_BT_VALID_3W_TIMERS      cpu_to_le16(BIT(3))
+#define IWLAGN_BT_VALID_KILL_ACK_MASK  cpu_to_le16(BIT(4))
+#define IWLAGN_BT_VALID_KILL_CTS_MASK  cpu_to_le16(BIT(5))
+#define IWLAGN_BT_VALID_REDUCED_TX_PWR cpu_to_le16(BIT(6))
+#define IWLAGN_BT_VALID_3W_LUT         cpu_to_le16(BIT(7))
+
+#define IWLAGN_BT_ALL_VALID_MSK                (IWLAGN_BT_VALID_ENABLE_FLAGS | \
+                                       IWLAGN_BT_VALID_BOOST | \
+                                       IWLAGN_BT_VALID_MAX_KILL | \
+                                       IWLAGN_BT_VALID_3W_TIMERS | \
+                                       IWLAGN_BT_VALID_KILL_ACK_MASK | \
+                                       IWLAGN_BT_VALID_KILL_CTS_MASK | \
+                                       IWLAGN_BT_VALID_REDUCED_TX_PWR | \
+                                       IWLAGN_BT_VALID_3W_LUT)
+
+#define IWLAGN_BT_REDUCED_TX_PWR       BIT(0)
+
+#define IWLAGN_BT_DECISION_LUT_SIZE    12
+
+struct iwl_basic_bt_cmd {
+       u8 flags;
+       u8 ledtime; /* unused */
+       u8 max_kill;
+       u8 bt3_timer_t7_value;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       u8 bt3_prio_sample_time;
+       u8 bt3_timer_t2_value;
+       __le16 bt4_reaction_time; /* unused */
+       __le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
+       /*
+        * bit 0: use reduced tx power for control frame
+        * bit 1 - 7: reserved
+        */
+       u8 reduce_txpower;
+       u8 reserved;
+       __le16 valid;
+};
+
+struct iwl_bt_cmd_v1 {
+       struct iwl_basic_bt_cmd basic;
+       u8 prio_boost;
+       /*
+        * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
+        * if configure the following patterns
+        */
+       u8 tx_prio_boost;       /* SW boost of WiFi tx priority */
+       __le16 rx_prio_boost;   /* SW boost of WiFi rx priority */
+};
+
+struct iwl_bt_cmd_v2 {
+       struct iwl_basic_bt_cmd basic;
+       __le32 prio_boost;
+       /*
+        * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
+        * if configure the following patterns
+        */
+       u8 reserved;
+       u8 tx_prio_boost;       /* SW boost of WiFi tx priority */
+       __le16 rx_prio_boost;   /* SW boost of WiFi rx priority */
+};
+
+#define IWLAGN_BT_SCO_ACTIVE   cpu_to_le32(BIT(0))
+
+struct iwlagn_bt_sco_cmd {
+       __le32 flags;
+};
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+                                RXON_FILTER_CTL2HOST_MSK        | \
+                                RXON_FILTER_ACCEPT_GRP_MSK      | \
+                                RXON_FILTER_DIS_DECRYPT_MSK     | \
+                                RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+                                RXON_FILTER_ASSOC_MSK           | \
+                                RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+       __le32 duration;        /* measurement duration in extended beacon
+                                * format */
+       u8 channel;             /* channel to measure */
+       u8 type;                /* see enum iwl_measure_type */
+       __le16 reserved;
+} __packed;
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+       __le16 len;             /* number of bytes starting from token */
+       u8 token;               /* token id */
+       u8 id;                  /* measurement id -- 0 or 1 */
+       u8 origin;              /* 0 = TGh, 1 = other, 2 = TGk */
+       u8 periodic;            /* 1 = periodic */
+       __le16 path_loss_timeout;
+       __le32 start_time;      /* start time in extended beacon format */
+       __le32 reserved2;
+       __le32 flags;           /* rxon flags */
+       __le32 filter_flags;    /* rxon filter flags */
+       __le16 channel_count;   /* minimum 1, maximum 10 */
+       __le16 reserved3;
+       struct iwl_measure_channel channels[10];
+} __packed;
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+       u8 token;
+       u8 id;                  /* id of the prior command replaced, or 0xff */
+       __le16 status;          /* 0 - command will be handled
+                                * 1 - cannot handle (conflicts with another
+                                *     measurement) */
+} __packed;
+
+enum iwl_measurement_state {
+       IWL_MEASUREMENT_START = 0,
+       IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+       IWL_MEASUREMENT_OK = 0,
+       IWL_MEASUREMENT_CONCURRENT = 1,
+       IWL_MEASUREMENT_CSA_CONFLICT = 2,
+       IWL_MEASUREMENT_TGH_CONFLICT = 3,
+       /* 4-5 reserved */
+       IWL_MEASUREMENT_STOPPED = 6,
+       IWL_MEASUREMENT_TIMEOUT = 7,
+       IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+       __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
+       __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];  /* in 1usec counts */
+} __packed;
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+       __le32 ofdm;
+       __le32 cck;
+} __packed;
+
+enum iwl_measure_type {
+       IWL_MEASURE_BASIC = (1 << 0),
+       IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+       IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+       IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+       IWL_MEASURE_FRAME = (1 << 4),
+       /* bits 5:6 are reserved */
+       IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+       u8 id;                  /* measurement id -- 0 or 1 */
+       u8 token;
+       u8 channel_index;       /* index in measurement channel list */
+       u8 state;               /* 0 - start, 1 - stop */
+       __le32 start_time;      /* lower 32-bits of TSF */
+       u8 band;                /* 0 - 5.2GHz, 1 - 2.4GHz */
+       u8 channel;
+       u8 type;                /* see enum iwl_measurement_type */
+       u8 reserved1;
+       /* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+        * valid if applicable for measurement type requested. */
+       __le32 cca_ofdm;        /* cca fraction time in 40Mhz clock periods */
+       __le32 cca_cck;         /* cca fraction time in 44Mhz clock periods */
+       __le32 cca_time;        /* channel load time in usecs */
+       u8 basic_type;          /* 0 - bss, 1 - ofdm preamble, 2 -
+                                * unidentified */
+       u8 reserved2[3];
+       struct iwl_measurement_histogram histogram;
+       __le32 stop_time;       /* lower 32-bits of TSF */
+       __le32 status;          /* see iwl_measurement_status */
+} __packed;
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ *
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ *
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ *
+ * PCI power managed
+ *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
+ *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
+ *
+ * Fast PD
+ *   bit 4 - '1' Put radio to sleep when receiving frame for others
+ *
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wake up
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK       cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_SAVE_ENA_MSK           cpu_to_le16(BIT(0))
+#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK     cpu_to_le16(BIT(1))
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK          cpu_to_le16(BIT(2))
+#define IWL_POWER_PCI_PM_MSK                   cpu_to_le16(BIT(3))
+#define IWL_POWER_FAST_PD                      cpu_to_le16(BIT(4))
+#define IWL_POWER_BEACON_FILTERING             cpu_to_le16(BIT(5))
+#define IWL_POWER_SHADOW_REG_ENA               cpu_to_le16(BIT(6))
+#define IWL_POWER_CT_KILL_SET                  cpu_to_le16(BIT(7))
+#define IWL_POWER_BT_SCO_ENA                   cpu_to_le16(BIT(8))
+#define IWL_POWER_ADVANCE_PM_ENA_MSK           cpu_to_le16(BIT(9))
+
+struct iwl_powertable_cmd {
+       __le16 flags;
+       u8 keep_alive_seconds;
+       u8 debug_flags;
+       __le32 rx_data_timeout;
+       __le32 tx_data_timeout;
+       __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+       __le32 keep_alive_beacons;
+} __packed;
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * all devices identical.
+ */
+struct iwl_sleep_notification {
+       u8 pm_sleep_mode;
+       u8 pm_wakeup_src;
+       __le16 reserved;
+       __le32 sleep_time;
+       __le32 tsf_low;
+       __le32 bcon_timer;
+} __packed;
+
+/* Sleep states.  all devices identical. */
+enum {
+       IWL_PM_NO_SLEEP = 0,
+       IWL_PM_SLP_MAC = 1,
+       IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+       IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+       IWL_PM_SLP_PHY = 4,
+       IWL_PM_SLP_REPENT = 5,
+       IWL_PM_WAKEUP_BY_TIMER = 6,
+       IWL_PM_WAKEUP_BY_DRIVER = 7,
+       IWL_PM_WAKEUP_BY_RFKILL = 8,
+       /* 3 reserved */
+       IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00    /* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01    /* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02    /* Power down permanently */
+struct iwl_card_state_cmd {
+       __le32 status;          /* CARD_STATE_CMD_* request new power state */
+} __packed;
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+       __le32 flags;
+} __packed;
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define CT_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+       __le32   reserved;
+       __le32   critical_temperature_M;
+       __le32   critical_temperature_R;
+}  __packed;
+
+/* 1000, and 6x00 */
+struct iwl_ct_kill_throttling_config {
+       __le32   critical_temperature_exit;
+       __le32   reserved;
+       __le32   critical_temperature_enter;
+}  __packed;
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0)
+#define SCAN_CHANNEL_TYPE_ACTIVE  cpu_to_le32(1)
+
+/**
+ * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
+ *
+ * One for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+
+struct iwl_scan_channel {
+       /*
+        * type is defined as:
+        * 0:0 1 = active, 0 = passive
+        * 1:20 SSID direct bit map; if a bit is set, then corresponding
+        *     SSID IE is transmitted in probe request.
+        * 21:31 reserved
+        */
+       __le32 type;
+       __le16 channel; /* band is selected by iwl_scan_cmd "flags" field */
+       u8 tx_gain;             /* gain for analog radio */
+       u8 dsp_atten;           /* gain for DSP */
+       __le16 active_dwell;    /* in 1024-uSec TU (time units), typ 5-50 */
+       __le16 passive_dwell;   /* in 1024-uSec TU (time units), typ 20-500 */
+} __packed;
+
+/* set number of direct probes __le32 type */
+#define IWL_SCAN_PROBE_MASK(n)         cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+
+/**
+ * struct iwl_ssid_ie - directed scan network information element
+ *
+ * Up to 20 of these may appear in REPLY_SCAN_CMD,
+ * selected by "type" bit field in struct iwl_scan_channel;
+ * each channel may select different ssids from among the 20 entries.
+ * SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl_ssid_ie {
+       u8 id;
+       u8 len;
+       u8 ssid[32];
+} __packed;
+
+#define PROBE_OPTION_MAX               20
+#define TX_CMD_LIFE_TIME_INFINITE      cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH_DISABLED       0
+#define IWL_GOOD_CRC_TH_DEFAULT                cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_NEVER          cpu_to_le16(0xffff)
+#define IWL_MAX_CMD_SIZE 4096
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ *
+ * The hardware scan command is very powerful; the driver can set it up to
+ * maintain (relatively) normal network traffic while doing a scan in the
+ * background.  The max_out_time and suspend_time control the ratio of how
+ * long the device stays on an associated network channel ("service channel")
+ * vs. how long it's away from the service channel, i.e. tuned to other channels
+ * for scanning.
+ *
+ * max_out_time is the max time off-channel (in usec), and suspend_time
+ * is how long (in "extended beacon" format) that the scan is "suspended"
+ * after returning to the service channel.  That is, suspend_time is the
+ * time that we stay on the service channel, doing normal work, between
+ * scan segments.  The driver may set these parameters differently to support
+ * scanning when associated vs. not associated, and light vs. heavy traffic
+ * loads when associated.
+ *
+ * After receiving this command, the device's scan engine does the following;
+ *
+ * 1)  Sends SCAN_START notification to driver
+ * 2)  Checks to see if it has time to do scan for one channel
+ * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
+ *     to tell AP that we're going off-channel
+ * 4)  Tunes to first channel in scan list, does active or passive scan
+ * 5)  Sends SCAN_RESULT notification to driver
+ * 6)  Checks to see if it has time to do scan on *next* channel in list
+ * 7)  Repeats 4-6 until it no longer has time to scan the next channel
+ *     before max_out_time expires
+ * 8)  Returns to service channel
+ * 9)  Sends NULL packet with PS=0 to tell AP that we're back
+ * 10) Stays on service channel until suspend_time expires
+ * 11) Repeats entire process 2-10 until list is complete
+ * 12) Sends SCAN_COMPLETE notification
+ *
+ * For fast, efficient scans, the scan command also has support for staying on
+ * a channel for just a short time, if doing active scanning and getting no
+ * responses to the transmitted probe request.  This time is controlled by
+ * quiet_time, and the number of received packets below which a channel is
+ * considered "quiet" is controlled by quiet_plcp_threshold.
+ *
+ * For active scanning on channels that have regulatory restrictions against
+ * blindly transmitting, the scan can listen before transmitting, to make sure
+ * that there is already legitimate activity on the channel.  If enough
+ * packets are cleanly received on the channel (controlled by good_CRC_th,
+ * typical value 1), the scan engine starts transmitting probe requests.
+ *
+ * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
+ *
+ * To avoid uCode errors, see timing restrictions described under
+ * struct iwl_scan_channel.
+ */
+
+enum iwl_scan_flags {
+       /* BIT(0) currently unused */
+       IWL_SCAN_FLAGS_ACTION_FRAME_TX  = BIT(1),
+       /* bits 2-7 reserved */
+};
+
+struct iwl_scan_cmd {
+       __le16 len;
+       u8 scan_flags;          /* scan flags: see enum iwl_scan_flags */
+       u8 channel_count;       /* # channels in channel list */
+       __le16 quiet_time;      /* dwell only this # millisecs on quiet channel
+                                * (only for active scan) */
+       __le16 quiet_plcp_th;   /* quiet chnl is < this # pkts (typ. 1) */
+       __le16 good_CRC_th;     /* passive -> active promotion threshold */
+       __le16 rx_chain;        /* RXON_RX_CHAIN_* */
+       __le32 max_out_time;    /* max usec to be away from associated (service)
+                                * channel */
+       __le32 suspend_time;    /* pause scan this long (in "extended beacon
+                                * format") when returning to service chnl:
+                                */
+       __le32 flags;           /* RXON_FLG_* */
+       __le32 filter_flags;    /* RXON_FILTER_* */
+
+       /* For active scans (set to all-0s for passive scans).
+        * Does not include payload.  Must specify Tx rate; no rate scaling. */
+       struct iwl_tx_cmd tx_cmd;
+
+       /* For directed active scans (set to all-0s otherwise) */
+       struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+       /*
+        * Probe request frame, followed by channel list.
+        *
+        * Size of probe request frame is specified by byte count in tx_cmd.
+        * Channel list follows immediately after probe request frame.
+        * Number of channels in list is specified by channel_count.
+        * Each channel in list is of type:
+        *
+        * struct iwl_scan_channel channels[0];
+        *
+        * NOTE:  Only one band of channels can be scanned per pass.  You
+        * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+        * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+        * before requesting another scan.
+        */
+       u8 data[0];
+} __packed;
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS       cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl_scanreq_notification {
+       __le32 status;          /* 1: okay, 2: cannot fulfill request */
+} __packed;
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl_scanstart_notification {
+       __le32 tsf_low;
+       __le32 tsf_high;
+       __le32 beacon_timer;
+       u8 channel;
+       u8 band;
+       u8 reserved[2];
+       __le32 status;
+} __packed;
+
+#define  SCAN_OWNER_STATUS 0x1
+#define  MEASURE_OWNER_STATUS 0x2
+
+#define IWL_PROBE_STATUS_OK            0
+#define IWL_PROBE_STATUS_TX_FAILED     BIT(0)
+/* error statuses combined with TX_FAILED */
+#define IWL_PROBE_STATUS_FAIL_TTL      BIT(1)
+#define IWL_PROBE_STATUS_FAIL_BT       BIT(2)
+
+#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+       u8 channel;
+       u8 band;
+       u8 probe_status;
+       u8 num_probe_not_sent; /* not enough time to send */
+       __le32 tsf_low;
+       __le32 tsf_high;
+       __le32 statistics[NUMBER_OF_STATISTICS];
+} __packed;
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+       u8 scanned_channels;
+       u8 status;
+       u8 bt_status;   /* BT On/Off status */
+       u8 last_channel;
+       __le32 tsf_low;
+       __le32 tsf_high;
+} __packed;
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+enum iwl_ibss_manager {
+       IWL_NOT_IBSS_MANAGER = 0,
+       IWL_IBSS_MANAGER = 1,
+};
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+
+struct iwlagn_beacon_notif {
+       struct iwlagn_tx_resp beacon_notify_hdr;
+       __le32 low_tsf;
+       __le32 high_tsf;
+       __le32 ibss_mgr_status;
+} __packed;
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+
+struct iwl_tx_beacon_cmd {
+       struct iwl_tx_cmd tx;
+       __le16 tim_idx;
+       u8 tim_size;
+       u8 reserved1;
+       struct ieee80211_hdr frame[0];  /* beacon frame */
+} __packed;
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+       union {
+               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } success;
+       union {
+               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } failed;
+} __packed;
+
+/* statistics command response */
+
+struct statistics_dbg {
+       __le32 burst_check;
+       __le32 burst_count;
+       __le32 wait_for_silence_timeout_cnt;
+       __le32 reserved[3];
+} __packed;
+
+struct statistics_rx_phy {
+       __le32 ina_cnt;
+       __le32 fina_cnt;
+       __le32 plcp_err;
+       __le32 crc32_err;
+       __le32 overrun_err;
+       __le32 early_overrun_err;
+       __le32 crc32_good;
+       __le32 false_alarm_cnt;
+       __le32 fina_sync_err_cnt;
+       __le32 sfd_timeout;
+       __le32 fina_timeout;
+       __le32 unresponded_rts;
+       __le32 rxe_frame_limit_overrun;
+       __le32 sent_ack_cnt;
+       __le32 sent_cts_cnt;
+       __le32 sent_ba_rsp_cnt;
+       __le32 dsp_self_kill;
+       __le32 mh_format_err;
+       __le32 re_acq_main_rssi_sum;
+       __le32 reserved3;
+} __packed;
+
+struct statistics_rx_ht_phy {
+       __le32 plcp_err;
+       __le32 overrun_err;
+       __le32 early_overrun_err;
+       __le32 crc32_good;
+       __le32 crc32_err;
+       __le32 mh_format_err;
+       __le32 agg_crc32_good;
+       __le32 agg_mpdu_cnt;
+       __le32 agg_cnt;
+       __le32 unsupport_mcs;
+} __packed;
+
+#define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
+
+struct statistics_rx_non_phy {
+       __le32 bogus_cts;       /* CTS received when not expecting CTS */
+       __le32 bogus_ack;       /* ACK received when not expecting ACK */
+       __le32 non_bssid_frames;        /* number of frames with BSSID that
+                                        * doesn't belong to the STA BSSID */
+       __le32 filtered_frames; /* count frames that were dumped in the
+                                * filtering process */
+       __le32 non_channel_beacons;     /* beacons with our bss id but not on
+                                        * our serving channel */
+       __le32 channel_beacons; /* beacons with our bss id and in our
+                                * serving channel */
+       __le32 num_missed_bcon; /* number of missed beacons */
+       __le32 adc_rx_saturation_time;  /* count in 0.8us units the time the
+                                        * ADC was in saturation */
+       __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+                                         * for INA */
+       __le32 beacon_silence_rssi_a;   /* RSSI silence after beacon frame */
+       __le32 beacon_silence_rssi_b;   /* RSSI silence after beacon frame */
+       __le32 beacon_silence_rssi_c;   /* RSSI silence after beacon frame */
+       __le32 interference_data_flag;  /* flag for interference data
+                                        * availability. 1 when data is
+                                        * available. */
+       __le32 channel_load;            /* counts RX Enable time in uSec */
+       __le32 dsp_false_alarms;        /* DSP false alarm (both OFDM
+                                        * and CCK) counter */
+       __le32 beacon_rssi_a;
+       __le32 beacon_rssi_b;
+       __le32 beacon_rssi_c;
+       __le32 beacon_energy_a;
+       __le32 beacon_energy_b;
+       __le32 beacon_energy_c;
+} __packed;
+
+struct statistics_rx_non_phy_bt {
+       struct statistics_rx_non_phy common;
+       /* additional stats for bt */
+       __le32 num_bt_kills;
+       __le32 reserved[2];
+} __packed;
+
+struct statistics_rx {
+       struct statistics_rx_phy ofdm;
+       struct statistics_rx_phy cck;
+       struct statistics_rx_non_phy general;
+       struct statistics_rx_ht_phy ofdm_ht;
+} __packed;
+
+struct statistics_rx_bt {
+       struct statistics_rx_phy ofdm;
+       struct statistics_rx_phy cck;
+       struct statistics_rx_non_phy_bt general;
+       struct statistics_rx_ht_phy ofdm_ht;
+} __packed;
+
+/**
+ * struct statistics_tx_power - current tx power
+ *
+ * @ant_a: current tx power on chain a in 1/2 dB step
+ * @ant_b: current tx power on chain b in 1/2 dB step
+ * @ant_c: current tx power on chain c in 1/2 dB step
+ */
+struct statistics_tx_power {
+       u8 ant_a;
+       u8 ant_b;
+       u8 ant_c;
+       u8 reserved;
+} __packed;
+
+struct statistics_tx_non_phy_agg {
+       __le32 ba_timeout;
+       __le32 ba_reschedule_frames;
+       __le32 scd_query_agg_frame_cnt;
+       __le32 scd_query_no_agg;
+       __le32 scd_query_agg;
+       __le32 scd_query_mismatch;
+       __le32 frame_not_ready;
+       __le32 underrun;
+       __le32 bt_prio_kill;
+       __le32 rx_ba_rsp_cnt;
+} __packed;
+
+struct statistics_tx {
+       __le32 preamble_cnt;
+       __le32 rx_detected_cnt;
+       __le32 bt_prio_defer_cnt;
+       __le32 bt_prio_kill_cnt;
+       __le32 few_bytes_cnt;
+       __le32 cts_timeout;
+       __le32 ack_timeout;
+       __le32 expected_ack_cnt;
+       __le32 actual_ack_cnt;
+       __le32 dump_msdu_cnt;
+       __le32 burst_abort_next_frame_mismatch_cnt;
+       __le32 burst_abort_missing_next_frame_cnt;
+       __le32 cts_timeout_collision;
+       __le32 ack_or_ba_timeout_collision;
+       struct statistics_tx_non_phy_agg agg;
+       /*
+        * "tx_power" are optional parameters provided by uCode,
+        * 6000 series is the only device provide the information,
+        * Those are reserved fields for all the other devices
+        */
+       struct statistics_tx_power tx_power;
+       __le32 reserved1;
+} __packed;
+
+
+struct statistics_div {
+       __le32 tx_on_a;
+       __le32 tx_on_b;
+       __le32 exec_time;
+       __le32 probe_time;
+       __le32 reserved1;
+       __le32 reserved2;
+} __packed;
+
+struct statistics_general_common {
+       __le32 temperature;   /* radio temperature */
+       __le32 temperature_m; /* radio voltage */
+       struct statistics_dbg dbg;
+       __le32 sleep_time;
+       __le32 slots_out;
+       __le32 slots_idle;
+       __le32 ttl_timestamp;
+       struct statistics_div div;
+       __le32 rx_enable_counter;
+       /*
+        * num_of_sos_states:
+        *  count the number of times we have to re-tune
+        *  in order to get out of bad PHY status
+        */
+       __le32 num_of_sos_states;
+} __packed;
+
+struct statistics_bt_activity {
+       /* Tx statistics */
+       __le32 hi_priority_tx_req_cnt;
+       __le32 hi_priority_tx_denied_cnt;
+       __le32 lo_priority_tx_req_cnt;
+       __le32 lo_priority_tx_denied_cnt;
+       /* Rx statistics */
+       __le32 hi_priority_rx_req_cnt;
+       __le32 hi_priority_rx_denied_cnt;
+       __le32 lo_priority_rx_req_cnt;
+       __le32 lo_priority_rx_denied_cnt;
+} __packed;
+
+struct statistics_general {
+       struct statistics_general_common common;
+       __le32 reserved2;
+       __le32 reserved3;
+} __packed;
+
+struct statistics_general_bt {
+       struct statistics_general_common common;
+       struct statistics_bt_activity activity;
+       __le32 reserved2;
+       __le32 reserved3;
+} __packed;
+
+#define UCODE_STATISTICS_CLEAR_MSK             (0x1 << 0)
+#define UCODE_STATISTICS_FREQUENCY_MSK         (0x1 << 1)
+#define UCODE_STATISTICS_NARROW_BAND_MSK       (0x1 << 2)
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * all devices identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)    /* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+       __le32 configuration_flags;     /* IWL_STATS_CONF_* */
+} __packed;
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_HT40_MODE_MSK        cpu_to_le32(0x8)
+
+struct iwl_notif_statistics {
+       __le32 flag;
+       struct statistics_rx rx;
+       struct statistics_tx tx;
+       struct statistics_general general;
+} __packed;
+
+struct iwl_bt_notif_statistics {
+       __le32 flag;
+       struct statistics_rx_bt rx;
+       struct statistics_tx tx;
+       struct statistics_general_bt general;
+} __packed;
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ *
+ * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
+ * in regardless of how many missed beacons, which mean when driver receive the
+ * notification, inside the command, it can find all the beacons information
+ * which include number of total missed beacons, number of consecutive missed
+ * beacons, number of beacons received and number of beacons expected to
+ * receive.
+ *
+ * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
+ * in order to bring the radio/PHY back to working state; which has no relation
+ * to when driver will perform sensitivity calibration.
+ *
+ * Driver should set it own missed_beacon_threshold to decide when to perform
+ * sensitivity calibration based on number of consecutive missed beacons in
+ * order to improve overall performance, especially in noisy environment.
+ *
+ */
+
+#define IWL_MISSED_BEACON_THRESHOLD_MIN        (1)
+#define IWL_MISSED_BEACON_THRESHOLD_DEF        (5)
+#define IWL_MISSED_BEACON_THRESHOLD_MAX        IWL_MISSED_BEACON_THRESHOLD_DEF
+
+struct iwl_missed_beacon_notif {
+       __le32 consecutive_missed_beacons;
+       __le32 total_missed_becons;
+       __le32 num_expected_beacons;
+       __le32 num_recvd_beacons;
+} __packed;
+
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ * With the uCode used for open source drivers, most Tx calibration (except
+ * for Tx Power) and most Rx calibration is done by uCode during the
+ * "initialize" phase of uCode boot.  Driver must calibrate only:
+ *
+ * 1)  Tx power (depends on temperature), described elsewhere
+ * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
+ * 3)  Receiver sensitivity (to optimize signal detection)
+ *
+ *****************************************************************************/
+
+/**
+ * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
+ *
+ * This command sets up the Rx signal detector for a sensitivity level that
+ * is high enough to lock onto all signals within the associated network,
+ * but low enough to ignore signals that are below a certain threshold, so as
+ * not to have too many "false alarms".  False alarms are signals that the
+ * Rx DSP tries to lock onto, but then discards after determining that they
+ * are noise.
+ *
+ * The optimum number of false alarms is between 5 and 50 per 200 TUs
+ * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
+ * time listening, not transmitting).  Driver must adjust sensitivity so that
+ * the ratio of actual false alarms to actual Rx time falls within this range.
+ *
+ * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
+ * received beacon.  These provide information to the driver to analyze the
+ * sensitivity.  Don't analyze statistics that come in from scanning, or any
+ * other non-associated-network source.  Pertinent statistics include:
+ *
+ * From "general" statistics (struct statistics_rx_non_phy):
+ *
+ * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
+ *   Measure of energy of desired signal.  Used for establishing a level
+ *   below which the device does not detect signals.
+ *
+ * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
+ *   Measure of background noise in silent period after beacon.
+ *
+ * channel_load
+ *   uSecs of actual Rx time during beacon period (varies according to
+ *   how much time was spent transmitting).
+ *
+ * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
+ *
+ * false_alarm_cnt
+ *   Signal locks abandoned early (before phy-level header).
+ *
+ * plcp_err
+ *   Signal locks abandoned late (during phy-level header).
+ *
+ * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
+ *        beacon to beacon, i.e. each value is an accumulation of all errors
+ *        before and including the latest beacon.  Values will wrap around to 0
+ *        after counting up to 2^32 - 1.  Driver must differentiate vs.
+ *        previous beacon's values to determine # false alarms in the current
+ *        beacon period.
+ *
+ * Total number of false alarms = false_alarms + plcp_errs
+ *
+ * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for OFDM are at or close to settings for
+ * maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
+ *
+ *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
+ *   by *adding* 1 to all 4 of the table entries above, up to the max for
+ *   each entry.  Conversely, if false alarm rate is too low (less than 5
+ *   for each 204.8 msecs listening), *subtract* 1 from each entry to
+ *   increase sensitivity.
+ *
+ * For CCK sensitivity, keep track of the following:
+ *
+ *   1).  20-beacon history of maximum background noise, indicated by
+ *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
+ *        3 receivers.  For any given beacon, the "silence reference" is
+ *        the maximum of last 60 samples (20 beacons * 3 receivers).
+ *
+ *   2).  10-beacon history of strongest signal level, as indicated
+ *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
+ *        i.e. the strength of the signal through the best receiver at the
+ *        moment.  These measurements are "upside down", with lower values
+ *        for stronger signals, so max energy will be *minimum* value.
+ *
+ *        Then for any given beacon, the driver must determine the *weakest*
+ *        of the strongest signals; this is the minimum level that needs to be
+ *        successfully detected, when using the best receiver at the moment.
+ *        "Max cck energy" is the maximum (higher value means lower energy!)
+ *        of the last 10 minima.  Once this is determined, driver must add
+ *        a little margin by adding "6" to it.
+ *
+ *   3).  Number of consecutive beacon periods with too few false alarms.
+ *        Reset this to 0 at the first beacon period that falls within the
+ *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
+ *
+ * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for CCK are at maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
+ *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), method for reducing
+ *   sensitivity is:
+ *
+ *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       up to max 400.
+ *
+ *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
+ *       sensitivity has been reduced a significant amount; bring it up to
+ *       a moderate 161.  Otherwise, *add* 3, up to max 200.
+ *
+ *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
+ *       sensitivity has been reduced only a moderate or small amount;
+ *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
+ *       down to min 0.  Otherwise (if gain has been significantly reduced),
+ *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
+ *
+ *       b)  Save a snapshot of the "silence reference".
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too low
+ *   (less than 5 for each 204.8 msecs listening), method for increasing
+ *   sensitivity is used only if:
+ *
+ *   1a)  Previous beacon did not have too many false alarms
+ *   1b)  AND difference between previous "silence reference" and current
+ *        "silence reference" (prev - current) is 2 or more,
+ *   OR 2)  100 or more consecutive beacon periods have had rate of
+ *          less than 5 false alarms per 204.8 milliseconds rx time.
+ *
+ *   Method for increasing sensitivity:
+ *
+ *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
+ *       down to min 125.
+ *
+ *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       down to min 200.
+ *
+ *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
+ *   (between 5 and 50 for each 204.8 msecs listening):
+ *
+ *   1)  Save a snapshot of the silence reference.
+ *
+ *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
+ *       give some extra margin to energy threshold by *subtracting* 8
+ *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
+ *
+ *   For all cases (too few, too many, good range), make sure that the CCK
+ *   detection threshold (energy) is below the energy level for robust
+ *   detection over the past 10 beacon periods, the "Max cck energy".
+ *   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".
+ *
+ */
+
+/*
+ * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
+ */
+#define HD_TABLE_SIZE  (11)    /* number of entries */
+#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)        /* table indexes */
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
+
+/*
+ * Additional table entries in enhance SENSITIVITY_CMD
+ */
+#define HD_INA_NON_SQUARE_DET_OFDM_INDEX               (11)
+#define HD_INA_NON_SQUARE_DET_CCK_INDEX                        (12)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX          (13)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX         (14)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX     (15)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX             (16)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX         (17)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX          (18)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX      (19)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_INDEX              (20)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX          (21)
+#define HD_RESERVED                                    (22)
+
+/* number of entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_SIZE  (23)
+
+/* number of additional entries for enhanced tbl */
+#define ENHANCE_HD_TABLE_ENTRIES  (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1             cpu_to_le16(0)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1              cpu_to_le16(0)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1                cpu_to_le16(0)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1       cpu_to_le16(668)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1   cpu_to_le16(4)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1           cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1       cpu_to_le16(37)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1                cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1    cpu_to_le16(4)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1            cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1                cpu_to_le16(99)
+
+#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2             cpu_to_le16(1)
+#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2              cpu_to_le16(1)
+#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2                cpu_to_le16(1)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2       cpu_to_le16(600)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2   cpu_to_le16(40)
+#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2           cpu_to_le16(486)
+#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2       cpu_to_le16(45)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2                cpu_to_le16(853)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2    cpu_to_le16(60)
+#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2            cpu_to_le16(476)
+#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2                cpu_to_le16(99)
+
+
+/* Control field in struct iwl_sensitivity_cmd */
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE  cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE     cpu_to_le16(1)
+
+/**
+ * struct iwl_sensitivity_cmd
+ * @control:  (1) updates working table, (0) updates default table
+ * @table:  energy threshold values, use HD_* as index into table
+ *
+ * Always use "1" in "control" to update uCode's working table and DSP.
+ */
+struct iwl_sensitivity_cmd {
+       __le16 control;                 /* always use "1" */
+       __le16 table[HD_TABLE_SIZE];    /* use HD_* as index */
+} __packed;
+
+/*
+ *
+ */
+struct iwl_enhance_sensitivity_cmd {
+       __le16 control;                 /* always use "1" */
+       __le16 enhance_table[ENHANCE_HD_TABLE_SIZE];    /* use HD_* as index */
+} __packed;
+
+
+/**
+ * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
+ *
+ * This command sets the relative gains of agn device's 3 radio receiver chains.
+ *
+ * After the first association, driver should accumulate signal and noise
+ * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
+ * beacons from the associated network (don't collect statistics that come
+ * in from scanning, or any other non-network source).
+ *
+ * DISCONNECTED ANTENNA:
+ *
+ * Driver should determine which antennas are actually connected, by comparing
+ * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
+ * following values over 20 beacons, one accumulator for each of the chains
+ * a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the strongest signal from among a/b/c.  Compare the other two to the
+ * strongest.  If any signal is more than 15 dB (times 20, unless you
+ * divide the accumulated values by 20) below the strongest, the driver
+ * considers that antenna to be disconnected, and should not try to use that
+ * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
+ * driver should declare the stronger one as connected, and attempt to use it
+ * (A and B are the only 2 Tx chains!).
+ *
+ *
+ * RX BALANCE:
+ *
+ * Driver should balance the 3 receivers (but just the ones that are connected
+ * to antennas, see above) for gain, by comparing the average signal levels
+ * detected during the silence after each beacon (background noise).
+ * Accumulate (add) the following values over 20 beacons, one accumulator for
+ * each of the chains a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the weakest background noise level from among a/b/c.  This Rx chain
+ * will be the reference, with 0 gain adjustment.  Attenuate other channels by
+ * finding noise difference:
+ *
+ * (accum_noise[i] - accum_noise[reference]) / 30
+ *
+ * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
+ * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
+ * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
+ * and set bit 2 to indicate "reduce gain".  The value for the reference
+ * (weakest) chain should be "0".
+ *
+ * diff_gain_[abc] bit fields:
+ *   2: (1) reduce gain, (0) increase gain
+ * 1-0: amount of gain, units of 1.5 dB
+ */
+
+/* Phy calibration command for series */
+enum {
+       IWL_PHY_CALIBRATE_DC_CMD                = 8,
+       IWL_PHY_CALIBRATE_LO_CMD                = 9,
+       IWL_PHY_CALIBRATE_TX_IQ_CMD             = 11,
+       IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD       = 15,
+       IWL_PHY_CALIBRATE_BASE_BAND_CMD         = 16,
+       IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD        = 17,
+       IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD       = 18,
+};
+
+/* This enum defines the bitmap of various calibrations to enable in both
+ * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
+ */
+enum iwl_ucode_calib_cfg {
+       IWL_CALIB_CFG_RX_BB_IDX                 = BIT(0),
+       IWL_CALIB_CFG_DC_IDX                    = BIT(1),
+       IWL_CALIB_CFG_LO_IDX                    = BIT(2),
+       IWL_CALIB_CFG_TX_IQ_IDX                 = BIT(3),
+       IWL_CALIB_CFG_RX_IQ_IDX                 = BIT(4),
+       IWL_CALIB_CFG_NOISE_IDX                 = BIT(5),
+       IWL_CALIB_CFG_CRYSTAL_IDX               = BIT(6),
+       IWL_CALIB_CFG_TEMPERATURE_IDX           = BIT(7),
+       IWL_CALIB_CFG_PAPD_IDX                  = BIT(8),
+       IWL_CALIB_CFG_SENSITIVITY_IDX           = BIT(9),
+       IWL_CALIB_CFG_TX_PWR_IDX                = BIT(10),
+};
+
+#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |   \
+                                       IWL_CALIB_CFG_DC_IDX |          \
+                                       IWL_CALIB_CFG_LO_IDX |          \
+                                       IWL_CALIB_CFG_TX_IQ_IDX |       \
+                                       IWL_CALIB_CFG_RX_IQ_IDX |       \
+                                       IWL_CALIB_CFG_CRYSTAL_IDX)
+
+#define IWL_CALIB_RT_CFG_ALL   cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |   \
+                                       IWL_CALIB_CFG_DC_IDX |          \
+                                       IWL_CALIB_CFG_LO_IDX |          \
+                                       IWL_CALIB_CFG_TX_IQ_IDX |       \
+                                       IWL_CALIB_CFG_RX_IQ_IDX |       \
+                                       IWL_CALIB_CFG_TEMPERATURE_IDX | \
+                                       IWL_CALIB_CFG_PAPD_IDX |        \
+                                       IWL_CALIB_CFG_TX_PWR_IDX |      \
+                                       IWL_CALIB_CFG_CRYSTAL_IDX)
+
+#define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK      cpu_to_le32(BIT(0))
+
+struct iwl_calib_cfg_elmnt_s {
+       __le32 is_enable;
+       __le32 start;
+       __le32 send_res;
+       __le32 apply_res;
+       __le32 reserved;
+} __packed;
+
+struct iwl_calib_cfg_status_s {
+       struct iwl_calib_cfg_elmnt_s once;
+       struct iwl_calib_cfg_elmnt_s perd;
+       __le32 flags;
+} __packed;
+
+struct iwl_calib_cfg_cmd {
+       struct iwl_calib_cfg_status_s ucd_calib_cfg;
+       struct iwl_calib_cfg_status_s drv_calib_cfg;
+       __le32 reserved1;
+} __packed;
+
+struct iwl_calib_hdr {
+       u8 op_code;
+       u8 first_group;
+       u8 groups_num;
+       u8 data_valid;
+} __packed;
+
+struct iwl_calib_cmd {
+       struct iwl_calib_hdr hdr;
+       u8 data[0];
+} __packed;
+
+struct iwl_calib_xtal_freq_cmd {
+       struct iwl_calib_hdr hdr;
+       u8 cap_pin1;
+       u8 cap_pin2;
+       u8 pad[2];
+} __packed;
+
+#define DEFAULT_RADIO_SENSOR_OFFSET    cpu_to_le16(2700)
+struct iwl_calib_temperature_offset_cmd {
+       struct iwl_calib_hdr hdr;
+       __le16 radio_sensor_offset;
+       __le16 reserved;
+} __packed;
+
+struct iwl_calib_temperature_offset_v2_cmd {
+       struct iwl_calib_hdr hdr;
+       __le16 radio_sensor_offset_high;
+       __le16 radio_sensor_offset_low;
+       __le16 burntVoltageRef;
+       __le16 reserved;
+} __packed;
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
+struct iwl_calib_chain_noise_reset_cmd {
+       struct iwl_calib_hdr hdr;
+       u8 data[0];
+};
+
+/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
+struct iwl_calib_chain_noise_gain_cmd {
+       struct iwl_calib_hdr hdr;
+       u8 delta_gain_1;
+       u8 delta_gain_2;
+       u8 pad[2];
+} __packed;
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl_led_cmd {
+       __le32 interval;        /* "interval" in uSec */
+       u8 id;                  /* 1: Activity, 2: Link, 3: Tech */
+       u8 off;                 /* # intervals off while blinking;
+                                * "0", with >0 "on" value, turns LED on */
+       u8 on;                  /* # intervals on while blinking;
+                                * "0", regardless of "off", turns LED off */
+       u8 reserved;
+} __packed;
+
+/*
+ * station priority table entries
+ * also used as potential "events" value for both
+ * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD
+ */
+
+/*
+ * COEX events entry flag masks
+ * RP - Requested Priority
+ * WP - Win Medium Priority: priority assigned when the contention has been won
+ */
+#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG        (0x1)
+#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG        (0x2)
+#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG  (0x4)
+
+#define COEX_CU_UNASSOC_IDLE_RP               4
+#define COEX_CU_UNASSOC_MANUAL_SCAN_RP        4
+#define COEX_CU_UNASSOC_AUTO_SCAN_RP          4
+#define COEX_CU_CALIBRATION_RP                4
+#define COEX_CU_PERIODIC_CALIBRATION_RP       4
+#define COEX_CU_CONNECTION_ESTAB_RP           4
+#define COEX_CU_ASSOCIATED_IDLE_RP            4
+#define COEX_CU_ASSOC_MANUAL_SCAN_RP          4
+#define COEX_CU_ASSOC_AUTO_SCAN_RP            4
+#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP         4
+#define COEX_CU_RF_ON_RP                      6
+#define COEX_CU_RF_OFF_RP                     4
+#define COEX_CU_STAND_ALONE_DEBUG_RP          6
+#define COEX_CU_IPAN_ASSOC_LEVEL_RP           4
+#define COEX_CU_RSRVD1_RP                     4
+#define COEX_CU_RSRVD2_RP                     4
+
+#define COEX_CU_UNASSOC_IDLE_WP               3
+#define COEX_CU_UNASSOC_MANUAL_SCAN_WP        3
+#define COEX_CU_UNASSOC_AUTO_SCAN_WP          3
+#define COEX_CU_CALIBRATION_WP                3
+#define COEX_CU_PERIODIC_CALIBRATION_WP       3
+#define COEX_CU_CONNECTION_ESTAB_WP           3
+#define COEX_CU_ASSOCIATED_IDLE_WP            3
+#define COEX_CU_ASSOC_MANUAL_SCAN_WP          3
+#define COEX_CU_ASSOC_AUTO_SCAN_WP            3
+#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP         3
+#define COEX_CU_RF_ON_WP                      3
+#define COEX_CU_RF_OFF_WP                     3
+#define COEX_CU_STAND_ALONE_DEBUG_WP          6
+#define COEX_CU_IPAN_ASSOC_LEVEL_WP           3
+#define COEX_CU_RSRVD1_WP                     3
+#define COEX_CU_RSRVD2_WP                     3
+
+#define COEX_UNASSOC_IDLE_FLAGS                     0
+#define COEX_UNASSOC_MANUAL_SCAN_FLAGS         \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_UNASSOC_AUTO_SCAN_FLAGS           \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_CALIBRATION_FLAGS                 \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_PERIODIC_CALIBRATION_FLAGS             0
+/*
+ * COEX_CONNECTION_ESTAB:
+ * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
+ */
+#define COEX_CONNECTION_ESTAB_FLAGS            \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |    \
+       COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+#define COEX_ASSOCIATED_IDLE_FLAGS                  0
+#define COEX_ASSOC_MANUAL_SCAN_FLAGS           \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_ASSOC_AUTO_SCAN_FLAGS             \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS               0
+#define COEX_RF_ON_FLAGS                            0
+#define COEX_RF_OFF_FLAGS                           0
+#define COEX_STAND_ALONE_DEBUG_FLAGS           \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
+#define COEX_IPAN_ASSOC_LEVEL_FLAGS            \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |   \
+        COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+#define COEX_RSRVD1_FLAGS                           0
+#define COEX_RSRVD2_FLAGS                           0
+/*
+ * COEX_CU_RF_ON is the event wrapping all radio ownership.
+ * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
+ */
+#define COEX_CU_RF_ON_FLAGS                    \
+       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
+        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |   \
+        COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
+
+
+enum {
+       /* un-association part */
+       COEX_UNASSOC_IDLE               = 0,
+       COEX_UNASSOC_MANUAL_SCAN        = 1,
+       COEX_UNASSOC_AUTO_SCAN          = 2,
+       /* calibration */
+       COEX_CALIBRATION                = 3,
+       COEX_PERIODIC_CALIBRATION       = 4,
+       /* connection */
+       COEX_CONNECTION_ESTAB           = 5,
+       /* association part */
+       COEX_ASSOCIATED_IDLE            = 6,
+       COEX_ASSOC_MANUAL_SCAN          = 7,
+       COEX_ASSOC_AUTO_SCAN            = 8,
+       COEX_ASSOC_ACTIVE_LEVEL         = 9,
+       /* RF ON/OFF */
+       COEX_RF_ON                      = 10,
+       COEX_RF_OFF                     = 11,
+       COEX_STAND_ALONE_DEBUG          = 12,
+       /* IPAN */
+       COEX_IPAN_ASSOC_LEVEL           = 13,
+       /* reserved */
+       COEX_RSRVD1                     = 14,
+       COEX_RSRVD2                     = 15,
+       COEX_NUM_OF_EVENTS              = 16
+};
+
+/*
+ * Coexistence WIFI/WIMAX  Command
+ * COEX_PRIORITY_TABLE_CMD = 0x5a
+ *
+ */
+struct iwl_wimax_coex_event_entry {
+       u8 request_prio;
+       u8 win_medium_prio;
+       u8 reserved;
+       u8 flags;
+} __packed;
+
+/* COEX flag masks */
+
+/* Station table is valid */
+#define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
+/* UnMask wake up src at unassociated sleep */
+#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
+/* UnMask wake up src at associated sleep */
+#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
+/* Enable CoEx feature. */
+#define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
+
+struct iwl_wimax_coex_cmd {
+       u8 flags;
+       u8 reserved[3];
+       struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
+} __packed;
+
+/*
+ * Coexistence MEDIUM NOTIFICATION
+ * COEX_MEDIUM_NOTIFICATION = 0x5b
+ *
+ * notification from uCode to host to indicate medium changes
+ *
+ */
+/*
+ * status field
+ * bit 0 - 2: medium status
+ * bit 3: medium change indication
+ * bit 4 - 31: reserved
+ */
+/* status option values, (0 - 2 bits) */
+#define COEX_MEDIUM_BUSY       (0x0) /* radio belongs to WiMAX */
+#define COEX_MEDIUM_ACTIVE     (0x1) /* radio belongs to WiFi */
+#define COEX_MEDIUM_PRE_RELEASE        (0x2) /* received radio release */
+#define COEX_MEDIUM_MSK                (0x7)
+
+/* send notification status (1 bit) */
+#define COEX_MEDIUM_CHANGED    (0x8)
+#define COEX_MEDIUM_CHANGED_MSK        (0x8)
+#define COEX_MEDIUM_SHIFT      (3)
+
+struct iwl_coex_medium_notification {
+       __le32 status;
+       __le32 events;
+} __packed;
+
+/*
+ * Coexistence EVENT  Command
+ * COEX_EVENT_CMD = 0x5c
+ *
+ * send from host to uCode for coex event request.
+ */
+/* flags options */
+#define COEX_EVENT_REQUEST_MSK (0x1)
+
+struct iwl_coex_event_cmd {
+       u8 flags;
+       u8 event;
+       __le16 reserved;
+} __packed;
+
+struct iwl_coex_event_resp {
+       __le32 status;
+} __packed;
+
+
+/******************************************************************************
+ * Bluetooth Coexistence commands
+ *
+ *****************************************************************************/
+
+/*
+ * BT Status notification
+ * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
+ */
+enum iwl_bt_coex_profile_traffic_load {
+       IWL_BT_COEX_TRAFFIC_LOAD_NONE =         0,
+       IWL_BT_COEX_TRAFFIC_LOAD_LOW =          1,
+       IWL_BT_COEX_TRAFFIC_LOAD_HIGH =         2,
+       IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =   3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+#define BT_SESSION_ACTIVITY_1_UART_MSG         0x1
+#define BT_SESSION_ACTIVITY_2_UART_MSG         0x2
+
+/* BT UART message - Share Part (BT -> WiFi) */
+#define BT_UART_MSG_FRAME1MSGTYPE_POS          (0)
+#define BT_UART_MSG_FRAME1MSGTYPE_MSK          \
+               (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
+#define BT_UART_MSG_FRAME1SSN_POS              (3)
+#define BT_UART_MSG_FRAME1SSN_MSK              \
+               (0x3 << BT_UART_MSG_FRAME1SSN_POS)
+#define BT_UART_MSG_FRAME1UPDATEREQ_POS                (5)
+#define BT_UART_MSG_FRAME1UPDATEREQ_MSK                \
+               (0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
+#define BT_UART_MSG_FRAME1RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME1RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
+
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS  (0)
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK  \
+               (0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS      (2)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK      \
+               (0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
+#define BT_UART_MSG_FRAME2CHLSEQN_POS          (4)
+#define BT_UART_MSG_FRAME2CHLSEQN_MSK          \
+               (0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
+#define BT_UART_MSG_FRAME2INBAND_POS           (5)
+#define BT_UART_MSG_FRAME2INBAND_MSK           \
+               (0x1 << BT_UART_MSG_FRAME2INBAND_POS)
+#define BT_UART_MSG_FRAME2RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME2RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_FRAME3SCOESCO_POS          (0)
+#define BT_UART_MSG_FRAME3SCOESCO_MSK          \
+               (0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
+#define BT_UART_MSG_FRAME3SNIFF_POS            (1)
+#define BT_UART_MSG_FRAME3SNIFF_MSK            \
+               (0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
+#define BT_UART_MSG_FRAME3A2DP_POS             (2)
+#define BT_UART_MSG_FRAME3A2DP_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3A2DP_POS)
+#define BT_UART_MSG_FRAME3ACL_POS              (3)
+#define BT_UART_MSG_FRAME3ACL_MSK              \
+               (0x1 << BT_UART_MSG_FRAME3ACL_POS)
+#define BT_UART_MSG_FRAME3MASTER_POS           (4)
+#define BT_UART_MSG_FRAME3MASTER_MSK           \
+               (0x1 << BT_UART_MSG_FRAME3MASTER_POS)
+#define BT_UART_MSG_FRAME3OBEX_POS             (5)
+#define BT_UART_MSG_FRAME3OBEX_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3OBEX_POS)
+#define BT_UART_MSG_FRAME3RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME3RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_FRAME4IDLEDURATION_POS     (0)
+#define BT_UART_MSG_FRAME4IDLEDURATION_MSK     \
+               (0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
+#define BT_UART_MSG_FRAME4RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME4RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_FRAME5TXACTIVITY_POS       (0)
+#define BT_UART_MSG_FRAME5TXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5RXACTIVITY_POS       (2)
+#define BT_UART_MSG_FRAME5RXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS   (4)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK   \
+               (0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
+#define BT_UART_MSG_FRAME5RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME5RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS    (0)
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK    \
+               (0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_POS     (5)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK     \
+               (0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
+#define BT_UART_MSG_FRAME6RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME6RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS    (0)
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK    \
+               (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
+#define BT_UART_MSG_FRAME7PAGE_POS             (3)
+#define BT_UART_MSG_FRAME7PAGE_MSK             \
+               (0x1 << BT_UART_MSG_FRAME7PAGE_POS)
+#define BT_UART_MSG_FRAME7INQUIRY_POS          (4)
+#define BT_UART_MSG_FRAME7INQUIRY_MSK          \
+               (0x1 << BT_UART_MSG_FRAME7INQUIRY_POS)
+#define BT_UART_MSG_FRAME7CONNECTABLE_POS      (5)
+#define BT_UART_MSG_FRAME7CONNECTABLE_MSK      \
+               (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
+#define BT_UART_MSG_FRAME7RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME7RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
+
+/* BT Session Activity 2 UART message (BT -> WiFi) */
+#define BT_UART_MSG_2_FRAME1RESERVED1_POS      (5)
+#define BT_UART_MSG_2_FRAME1RESERVED1_MSK      \
+               (0x1<<BT_UART_MSG_2_FRAME1RESERVED1_POS)
+#define BT_UART_MSG_2_FRAME1RESERVED2_POS      (6)
+#define BT_UART_MSG_2_FRAME1RESERVED2_MSK      \
+               (0x3<<BT_UART_MSG_2_FRAME1RESERVED2_POS)
+
+#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS (0)
+#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_MSK \
+               (0x3F<<BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS)
+#define BT_UART_MSG_2_FRAME2RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME2RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS  (0)
+#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_MSK  \
+               (0xF<<BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS)
+#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS  (4)
+#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_MSK  \
+               (0x1<<BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS)
+#define BT_UART_MSG_2_FRAME3LEMASTER_POS       (5)
+#define BT_UART_MSG_2_FRAME3LEMASTER_MSK       \
+               (0x1<<BT_UART_MSG_2_FRAME3LEMASTER_POS)
+#define BT_UART_MSG_2_FRAME3RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME3RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS  (0)
+#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_MSK  \
+               (0xF<<BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS)
+#define BT_UART_MSG_2_FRAME4NUMLECONN_POS      (4)
+#define BT_UART_MSG_2_FRAME4NUMLECONN_MSK      \
+               (0x3<<BT_UART_MSG_2_FRAME4NUMLECONN_POS)
+#define BT_UART_MSG_2_FRAME4RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME4RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME5BTMINRSSI_POS      (0)
+#define BT_UART_MSG_2_FRAME5BTMINRSSI_MSK      \
+               (0xF<<BT_UART_MSG_2_FRAME5BTMINRSSI_POS)
+#define BT_UART_MSG_2_FRAME5LESCANINITMODE_POS (4)
+#define BT_UART_MSG_2_FRAME5LESCANINITMODE_MSK \
+               (0x1<<BT_UART_MSG_2_FRAME5LESCANINITMODE_POS)
+#define BT_UART_MSG_2_FRAME5LEADVERMODE_POS    (5)
+#define BT_UART_MSG_2_FRAME5LEADVERMODE_MSK    \
+               (0x1<<BT_UART_MSG_2_FRAME5LEADVERMODE_POS)
+#define BT_UART_MSG_2_FRAME5RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME5RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS (0)
+#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_MSK \
+               (0x1F<<BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS)
+#define BT_UART_MSG_2_FRAME6RFU_POS            (5)
+#define BT_UART_MSG_2_FRAME6RFU_MSK            \
+               (0x1<<BT_UART_MSG_2_FRAME6RFU_POS)
+#define BT_UART_MSG_2_FRAME6RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME6RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS (0)
+#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_MSK \
+               (0x7<<BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILE1_POS     (3)
+#define BT_UART_MSG_2_FRAME7LEPROFILE1_MSK     \
+               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE1_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILE2_POS     (4)
+#define BT_UART_MSG_2_FRAME7LEPROFILE2_MSK     \
+               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE2_POS)
+#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS (5)
+#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_MSK \
+               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS)
+#define BT_UART_MSG_2_FRAME7RESERVED_POS       (6)
+#define BT_UART_MSG_2_FRAME7RESERVED_MSK       \
+               (0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS)
+
+
+#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD    (-62)
+#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD   (-65)
+
+struct iwl_bt_uart_msg {
+       u8 header;
+       u8 frame1;
+       u8 frame2;
+       u8 frame3;
+       u8 frame4;
+       u8 frame5;
+       u8 frame6;
+       u8 frame7;
+} __attribute__((packed));
+
+struct iwl_bt_coex_profile_notif {
+       struct iwl_bt_uart_msg last_bt_uart_msg;
+       u8 bt_status; /* 0 - off, 1 - on */
+       u8 bt_traffic_load; /* 0 .. 3? */
+       u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
+       u8 reserved;
+} __attribute__((packed));
+
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS        0
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK        0x1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_POS          1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK         0x0e
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS      4
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK     0xf0
+#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT                1
+
+/*
+ * BT Coexistence Priority table
+ * REPLY_BT_COEX_PRIO_TABLE = 0xcc
+ */
+enum bt_coex_prio_table_events {
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+       BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+       BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+       BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+       BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
+       BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
+       BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
+       BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
+       BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
+       BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
+       BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
+       /* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
+       BT_COEX_PRIO_TBL_EVT_MAX,
+};
+
+enum bt_coex_prio_table_priorities {
+       BT_COEX_PRIO_TBL_DISABLED = 0,
+       BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+       BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+       BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+       BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+       BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
+       BT_COEX_PRIO_TBL_MAX,
+};
+
+struct iwl_bt_coex_prio_table_cmd {
+       u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __attribute__((packed));
+
+#define IWL_BT_COEX_ENV_CLOSE  0
+#define IWL_BT_COEX_ENV_OPEN   1
+/*
+ * BT Protection Envelope
+ * REPLY_BT_COEX_PROT_ENV = 0xcd
+ */
+struct iwl_bt_coex_prot_env_cmd {
+       u8 action; /* 0 = closed, 1 = open */
+       u8 type; /* 0 .. 15 */
+       u8 reserved[2];
+} __attribute__((packed));
+
+/*
+ * REPLY_D3_CONFIG
+ */
+enum iwlagn_d3_wakeup_filters {
+       IWLAGN_D3_WAKEUP_RFKILL         = BIT(0),
+       IWLAGN_D3_WAKEUP_SYSASSERT      = BIT(1),
+};
+
+struct iwlagn_d3_config_cmd {
+       __le32 min_sleep_time;
+       __le32 wakeup_flags;
+} __packed;
+
+/*
+ * REPLY_WOWLAN_PATTERNS
+ */
+#define IWLAGN_WOWLAN_MIN_PATTERN_LEN  16
+#define IWLAGN_WOWLAN_MAX_PATTERN_LEN  128
+
+struct iwlagn_wowlan_pattern {
+       u8 mask[IWLAGN_WOWLAN_MAX_PATTERN_LEN / 8];
+       u8 pattern[IWLAGN_WOWLAN_MAX_PATTERN_LEN];
+       u8 mask_size;
+       u8 pattern_size;
+       __le16 reserved;
+} __packed;
+
+#define IWLAGN_WOWLAN_MAX_PATTERNS     20
+
+struct iwlagn_wowlan_patterns_cmd {
+       __le32 n_patterns;
+       struct iwlagn_wowlan_pattern patterns[];
+} __packed;
+
+/*
+ * REPLY_WOWLAN_WAKEUP_FILTER
+ */
+enum iwlagn_wowlan_wakeup_filters {
+       IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET       = BIT(0),
+       IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH      = BIT(1),
+       IWLAGN_WOWLAN_WAKEUP_BEACON_MISS        = BIT(2),
+       IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE        = BIT(3),
+       IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL     = BIT(4),
+       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(5),
+       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(6),
+       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(7),
+       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(8),
+};
+
+struct iwlagn_wowlan_wakeup_filter_cmd {
+       __le32 enabled;
+       __le16 non_qos_seq;
+       __le16 reserved;
+       __le16 qos_seq[8];
+};
+
+/*
+ * REPLY_WOWLAN_TSC_RSC_PARAMS
+ */
+#define IWLAGN_NUM_RSC 16
+
+struct tkip_sc {
+       __le16 iv16;
+       __le16 pad;
+       __le32 iv32;
+} __packed;
+
+struct iwlagn_tkip_rsc_tsc {
+       struct tkip_sc unicast_rsc[IWLAGN_NUM_RSC];
+       struct tkip_sc multicast_rsc[IWLAGN_NUM_RSC];
+       struct tkip_sc tsc;
+} __packed;
+
+struct aes_sc {
+       __le64 pn;
+} __packed;
+
+struct iwlagn_aes_rsc_tsc {
+       struct aes_sc unicast_rsc[IWLAGN_NUM_RSC];
+       struct aes_sc multicast_rsc[IWLAGN_NUM_RSC];
+       struct aes_sc tsc;
+} __packed;
+
+union iwlagn_all_tsc_rsc {
+       struct iwlagn_tkip_rsc_tsc tkip;
+       struct iwlagn_aes_rsc_tsc aes;
+};
+
+struct iwlagn_wowlan_rsc_tsc_params_cmd {
+       union iwlagn_all_tsc_rsc all_tsc_rsc;
+} __packed;
+
+/*
+ * REPLY_WOWLAN_TKIP_PARAMS
+ */
+#define IWLAGN_MIC_KEY_SIZE    8
+#define IWLAGN_P1K_SIZE                5
+struct iwlagn_mic_keys {
+       u8 tx[IWLAGN_MIC_KEY_SIZE];
+       u8 rx_unicast[IWLAGN_MIC_KEY_SIZE];
+       u8 rx_mcast[IWLAGN_MIC_KEY_SIZE];
+} __packed;
+
+struct iwlagn_p1k_cache {
+       __le16 p1k[IWLAGN_P1K_SIZE];
+} __packed;
+
+#define IWLAGN_NUM_RX_P1K_CACHE        2
+
+struct iwlagn_wowlan_tkip_params_cmd {
+       struct iwlagn_mic_keys mic_keys;
+       struct iwlagn_p1k_cache tx;
+       struct iwlagn_p1k_cache rx_uni[IWLAGN_NUM_RX_P1K_CACHE];
+       struct iwlagn_p1k_cache rx_multi[IWLAGN_NUM_RX_P1K_CACHE];
+} __packed;
+
+/*
+ * REPLY_WOWLAN_KEK_KCK_MATERIAL
+ */
+
+#define IWLAGN_KCK_MAX_SIZE    32
+#define IWLAGN_KEK_MAX_SIZE    32
+
+struct iwlagn_wowlan_kek_kck_material_cmd {
+       u8      kck[IWLAGN_KCK_MAX_SIZE];
+       u8      kek[IWLAGN_KEK_MAX_SIZE];
+       __le16  kck_len;
+       __le16  kek_len;
+       __le64  replay_ctr;
+} __packed;
+
+/*
+ * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
+ */
+
+/*
+ * Minimum slot time in TU
+ */
+#define IWL_MIN_SLOT_TIME      20
+
+/**
+ * struct iwl_wipan_slot
+ * @width: Time in TU
+ * @type:
+ *   0 - BSS
+ *   1 - PAN
+ */
+struct iwl_wipan_slot {
+       __le16 width;
+       u8 type;
+       u8 reserved;
+} __packed;
+
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS         BIT(1)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET       BIT(2)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE              BIT(3)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF       BIT(4)
+#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE         BIT(5)
+
+/**
+ * struct iwl_wipan_params_cmd
+ * @flags:
+ *   bit0: reserved
+ *   bit1: CP leave channel with CTS
+ *   bit2: CP leave channel qith Quiet
+ *   bit3: slotted mode
+ *     1 - work in slotted mode
+ *     0 - work in non slotted mode
+ *   bit4: filter beacon notification
+ *   bit5: full tx slotted mode. if this flag is set,
+ *         uCode will perform leaving channel methods in context switch
+ *         also when working in same channel mode
+ * @num_slots: 1 - 10
+ */
+struct iwl_wipan_params_cmd {
+       __le16 flags;
+       u8 reserved;
+       u8 num_slots;
+       struct iwl_wipan_slot slots[10];
+} __packed;
+
+/*
+ * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
+ *
+ * TODO: Figure out what this is used for,
+ *      it can only switch between 2.4 GHz
+ *      channels!!
+ */
+
+struct iwl_wipan_p2p_channel_switch_cmd {
+       __le16 channel;
+       __le16 reserved;
+};
+
+/*
+ * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
+ *
+ * This is used by the device to notify us of the
+ * NoA schedule it determined so we can forward it
+ * to userspace for inclusion in probe responses.
+ *
+ * In beacons, the NoA schedule is simply appended
+ * to the frame we give the device.
+ */
+
+struct iwl_wipan_noa_descriptor {
+       u8 count;
+       __le32 duration;
+       __le32 interval;
+       __le32 starttime;
+} __packed;
+
+struct iwl_wipan_noa_attribute {
+       u8 id;
+       __le16 length;
+       u8 index;
+       u8 ct_window;
+       struct iwl_wipan_noa_descriptor descr0, descr1;
+       u8 reserved;
+} __packed;
+
+struct iwl_wipan_noa_notification {
+       u32 noa_active;
+       struct iwl_wipan_noa_attribute noa_attribute;
+} __packed;
+
+#endif                         /* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
new file mode 100644 (file)
index 0000000..b0eff1c
--- /dev/null
@@ -0,0 +1,2432 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "iwl-debug.h"
+#include "iwl-io.h"
+#include "dev.h"
+#include "agn.h"
+
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
+       if (!debugfs_create_file(#name, mode, parent, priv,             \
+                                &iwl_dbgfs_##name##_ops))              \
+               goto err;                                               \
+} while (0)
+
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                       \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,           \
+                                   parent, ptr);                       \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
+} while (0)
+
+#define DEBUGFS_ADD_X32(name, parent, ptr) do {                                \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,            \
+                                  parent, ptr);                        \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
+} while (0)
+
+#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {                  \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_u32(#name, mode,                         \
+                                  parent, ptr);                        \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name)                                         \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
+                                       char __user *user_buf,          \
+                                       size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                        \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
+                                       const char __user *user_buf,    \
+                                       size_t count, loff_t *ppos);
+
+
+#define DEBUGFS_READ_FILE_OPS(name)                                     \
+       DEBUGFS_READ_FUNC(name);                                        \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
+       DEBUGFS_READ_FUNC(name);                                        \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+static ssize_t iwl_dbgfs_sram_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       u32 val = 0;
+       char *buf;
+       ssize_t ret;
+       int i = 0;
+       bool device_format = false;
+       int offset = 0;
+       int len = 0;
+       int pos = 0;
+       int sram;
+       struct iwl_priv *priv = file->private_data;
+       const struct fw_img *img;
+       size_t bufsz;
+
+       /* default is to dump the entire data segment */
+       if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
+               priv->dbgfs_sram_offset = 0x800000;
+               if (!priv->ucode_loaded)
+                       return -EINVAL;
+               img = &priv->fw->img[priv->cur_ucode];
+               priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+       }
+       len = priv->dbgfs_sram_len;
+
+       if (len == -4) {
+               device_format = true;
+               len = 4;
+       }
+
+       bufsz =  50 + len * 4;
+       buf = kmalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
+                        len);
+       pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
+                       priv->dbgfs_sram_offset);
+
+       /* adjust sram address since reads are only on even u32 boundaries */
+       offset = priv->dbgfs_sram_offset & 0x3;
+       sram = priv->dbgfs_sram_offset & ~0x3;
+
+       /* read the first u32 from sram */
+       val = iwl_read_targ_mem(priv->trans, sram);
+
+       for (; len; len--) {
+               /* put the address at the start of every line */
+               if (i == 0)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "%08X: ", sram + offset);
+
+               if (device_format)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "%02x", (val >> (8 * (3 - offset))) & 0xff);
+               else
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "%02x ", (val >> (8 * offset)) & 0xff);
+
+               /* if all bytes processed, read the next u32 from sram */
+               if (++offset == 4) {
+                       sram += 4;
+                       offset = 0;
+                       val = iwl_read_targ_mem(priv->trans, sram);
+               }
+
+               /* put in extra spaces and split lines for human readability */
+               if (++i == 16) {
+                       i = 0;
+                       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+               } else if (!(i & 7)) {
+                       pos += scnprintf(buf + pos, bufsz - pos, "   ");
+               } else if (!(i & 3)) {
+                       pos += scnprintf(buf + pos, bufsz - pos, " ");
+               }
+       }
+       if (i)
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_sram_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[64];
+       int buf_size;
+       u32 offset, len;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
+               priv->dbgfs_sram_offset = offset;
+               priv->dbgfs_sram_len = len;
+       } else if (sscanf(buf, "%x", &offset) == 1) {
+               priv->dbgfs_sram_offset = offset;
+               priv->dbgfs_sram_len = -4;
+       } else {
+               priv->dbgfs_sram_offset = 0;
+               priv->dbgfs_sram_len = 0;
+       }
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];
+
+       if (!priv->wowlan_sram)
+               return -ENODATA;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      priv->wowlan_sram,
+                                      img->sec[IWL_UCODE_SECTION_DATA].len);
+}
+static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct iwl_station_entry *station;
+       struct iwl_tid_data *tid_data;
+       char *buf;
+       int i, j, pos = 0;
+       ssize_t ret;
+       /* Add 30 for initial string */
+       const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
+
+       buf = kmalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
+                       priv->num_stations);
+
+       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+               station = &priv->stations[i];
+               if (!station->used)
+                       continue;
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "station %d - addr: %pM, flags: %#x\n",
+                                i, station->sta.sta.addr,
+                                station->sta.station_flags_msk);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "TID seqno  next_rclmd "
+                               "rate_n_flags state txq\n");
+
+               for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
+                       tid_data = &priv->tid_data[i][j];
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "%d:  0x%.4x 0x%.4x     0x%.8x   "
+                               "%d     %.2d",
+                               j, tid_data->seq_number,
+                               tid_data->next_reclaimed,
+                               tid_data->agg.rate_n_flags,
+                               tid_data->agg.state,
+                               tid_data->agg.txq_id);
+
+                       if (tid_data->agg.wait_for_ba)
+                               pos += scnprintf(buf + pos, bufsz - pos,
+                                                " - waitforba");
+                       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+               }
+
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_nvm_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count,
+                                      loff_t *ppos)
+{
+       ssize_t ret;
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0, ofs = 0, buf_size = 0;
+       const u8 *ptr;
+       char *buf;
+       u16 eeprom_ver;
+       size_t eeprom_len = priv->eeprom_blob_size;
+       buf_size = 4 * eeprom_len + 256;
+
+       if (eeprom_len % 16)
+               return -ENODATA;
+
+       ptr = priv->eeprom_blob;
+       if (!ptr)
+               return -ENOMEM;
+
+       /* 4 characters for byte 0xYY */
+       buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       eeprom_ver = priv->eeprom_data->eeprom_version;
+       pos += scnprintf(buf + pos, buf_size - pos,
+                        "NVM version: 0x%x\n", 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,
+                                  buf_size - pos, 0);
+               pos += strlen(buf + pos);
+               if (buf_size - pos > 0)
+                       buf[pos++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct ieee80211_channel *channels = NULL;
+       const struct ieee80211_supported_band *supp_band = NULL;
+       int pos = 0, i, bufsz = PAGE_SIZE;
+       char *buf;
+       ssize_t ret;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
+       if (supp_band) {
+               channels = supp_band->channels;
+
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "Displaying %d channels in 2.4GHz band 802.11bg):\n",
+                               supp_band->n_channels);
+
+               for (i = 0; i < supp_band->n_channels; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "%d: %ddBm: BSS%s%s, %s.\n",
+                                       channels[i].hw_value,
+                                       channels[i].max_power,
+                                       channels[i].flags & IEEE80211_CHAN_RADAR ?
+                                       " (IEEE 802.11h required)" : "",
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       || (channels[i].flags &
+                                       IEEE80211_CHAN_RADAR)) ? "" :
+                                       ", IBSS",
+                                       channels[i].flags &
+                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       "passive only" : "active/passive");
+       }
+       supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
+       if (supp_band) {
+               channels = supp_band->channels;
+
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "Displaying %d channels in 5.2GHz band (802.11a)\n",
+                               supp_band->n_channels);
+
+               for (i = 0; i < supp_band->n_channels; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "%d: %ddBm: BSS%s%s, %s.\n",
+                                       channels[i].hw_value,
+                                       channels[i].max_power,
+                                       channels[i].flags & IEEE80211_CHAN_RADAR ?
+                                       " (IEEE 802.11h required)" : "",
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       || (channels[i].flags &
+                                       IEEE80211_CHAN_RADAR)) ? "" :
+                                       ", IBSS",
+                                       channels[i].flags &
+                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       "passive only" : "active/passive");
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_status_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[512];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       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_ALIVE:\t\t %d\n",
+               test_bit(STATUS_ALIVE, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
+               test_bit(STATUS_READY, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
+               test_bit(STATUS_EXIT_PENDING, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
+               test_bit(STATUS_STATISTICS, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
+               test_bit(STATUS_SCANNING, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
+               test_bit(STATUS_SCAN_ABORTING, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
+               test_bit(STATUS_SCAN_HW, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
+               test_bit(STATUS_POWER_PMI, &priv->status));
+       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
+               test_bit(STATUS_FW_ERROR, &priv->status));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+
+       int pos = 0;
+       int cnt = 0;
+       char *buf;
+       int bufsz = 24 * 64; /* 24 items * 64 char per item */
+       ssize_t ret;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (cnt = 0; cnt < REPLY_MAX; cnt++) {
+               if (priv->rx_handlers_stats[cnt] > 0)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "\tRx handler[%36s]:\t\t %u\n",
+                               iwl_dvm_get_cmd_string(cnt),
+                               priv->rx_handlers_stats[cnt]);
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_handlers_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+
+       char buf[8];
+       int buf_size;
+       u32 reset_flag;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%x", &reset_flag) != 1)
+               return -EFAULT;
+       if (reset_flag == 0)
+               memset(&priv->rx_handlers_stats[0], 0,
+                       sizeof(priv->rx_handlers_stats));
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct iwl_rxon_context *ctx;
+       int pos = 0, i;
+       char buf[256 * NUM_IWL_RXON_CTX];
+       const size_t bufsz = sizeof(buf);
+
+       for_each_context(priv, ctx) {
+               pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
+                                ctx->ctxid);
+               for (i = 0; i < AC_NUM; i++) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "\tcw_min\tcw_max\taifsn\ttxop\n");
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+                               ctx->qos_data.def_qos_parm.ac[i].cw_min,
+                               ctx->qos_data.def_qos_parm.ac[i].cw_max,
+                               ctx->qos_data.def_qos_parm.ac[i].aifsn,
+                               ctx->qos_data.def_qos_parm.ac[i].edca_txop);
+               }
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       }
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
+                               char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+       char buf[100];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "Thermal Throttling Mode: %s\n",
+                       tt->advanced_tt ? "Advance" : "Legacy");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "Thermal Throttling State: %d\n",
+                       tt->state);
+       if (tt->advanced_tt) {
+               restriction = tt->restriction + tt->state;
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "Tx mode: %d\n",
+                               restriction->tx_stream);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "Rx mode: %d\n",
+                               restriction->rx_stream);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "HT mode: %d\n",
+                               restriction->is_ht);
+       }
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int ht40;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &ht40) != 1)
+               return -EFAULT;
+       if (!iwl_is_any_associated(priv))
+               priv->disable_ht40 = ht40 ? true : false;
+       else
+               return -EINVAL;
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[100];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "11n 40MHz Mode: %s\n",
+                       priv->disable_ht40 ? "Disabled" : "Enabled");
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_temperature_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+
+static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
+                                                   const char __user *user_buf,
+                                                   size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int value;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       if (sscanf(buf, "%d", &value) != 1)
+               return -EINVAL;
+
+       /*
+        * Our users expect 0 to be "CAM", but 0 isn't actually
+        * valid here. However, let's not confuse them and present
+        * IWL_POWER_INDEX_1 as "1", not "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;
+
+       mutex_lock(&priv->mutex);
+       iwl_power_update_mode(priv, true);
+       mutex_unlock(&priv->mutex);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
+                                                  char __user *user_buf,
+                                                  size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[10];
+       int pos, value;
+       const size_t bufsz = sizeof(buf);
+
+       /* see the write function */
+       value = priv->power_data.debug_sleep_level_override;
+       if (value >= 0)
+               value += 1;
+
+       pos = scnprintf(buf, bufsz, "%d\n", value);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
+                                                   char __user *user_buf,
+                                                   size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[200];
+       int pos = 0, i;
+       const size_t bufsz = sizeof(buf);
+       struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "flags: %#.2x\n", le16_to_cpu(cmd->flags));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "RX/TX timeout: %d/%d usec\n",
+                        le32_to_cpu(cmd->rx_data_timeout),
+                        le32_to_cpu(cmd->tx_data_timeout));
+       for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "sleep_interval[%d]: %d\n", i,
+                                le32_to_cpu(cmd->sleep_interval[i]));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(sram);
+DEBUGFS_READ_FILE_OPS(wowlan_sram);
+DEBUGFS_READ_FILE_OPS(nvm);
+DEBUGFS_READ_FILE_OPS(stations);
+DEBUGFS_READ_FILE_OPS(channels);
+DEBUGFS_READ_FILE_OPS(status);
+DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
+DEBUGFS_READ_FILE_OPS(qos);
+DEBUGFS_READ_FILE_OPS(thermal_throttling);
+DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_FILE_OPS(temperature);
+DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
+DEBUGFS_READ_FILE_OPS(current_sleep_command);
+
+static const char *fmt_value = "  %-30s %10u\n";
+static const char *fmt_hex   = "  %-30s       0x%02X\n";
+static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
+static const char *fmt_header =
+       "%-32s    current  cumulative       delta         max\n";
+
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+       int p = 0;
+       u32 flag;
+
+       lockdep_assert_held(&priv->statistics.lock);
+
+       flag = le32_to_cpu(priv->statistics.flag);
+
+       p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
+       if (flag & UCODE_STATISTICS_CLEAR_MSK)
+               p += scnprintf(buf + p, bufsz - p,
+               "\tStatistics have been cleared\n");
+       p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+               (flag & UCODE_STATISTICS_FREQUENCY_MSK)
+               ? "2.4 GHz" : "5.2 GHz");
+       p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+               (flag & UCODE_STATISTICS_NARROW_BAND_MSK)
+                ? "enabled" : "disabled");
+
+       return p;
+}
+
+static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+                   sizeof(struct statistics_rx_non_phy) * 40 +
+                   sizeof(struct statistics_rx_ht_phy) * 40 + 400;
+       ssize_t ret;
+       struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+       struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+       struct statistics_rx_non_phy *general, *accum_general;
+       struct statistics_rx_non_phy *delta_general, *max_general;
+       struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /*
+        * the statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       spin_lock_bh(&priv->statistics.lock);
+       ofdm = &priv->statistics.rx_ofdm;
+       cck = &priv->statistics.rx_cck;
+       general = &priv->statistics.rx_non_phy;
+       ht = &priv->statistics.rx_ofdm_ht;
+       accum_ofdm = &priv->accum_stats.rx_ofdm;
+       accum_cck = &priv->accum_stats.rx_cck;
+       accum_general = &priv->accum_stats.rx_non_phy;
+       accum_ht = &priv->accum_stats.rx_ofdm_ht;
+       delta_ofdm = &priv->delta_stats.rx_ofdm;
+       delta_cck = &priv->delta_stats.rx_cck;
+       delta_general = &priv->delta_stats.rx_non_phy;
+       delta_ht = &priv->delta_stats.rx_ofdm_ht;
+       max_ofdm = &priv->max_delta_stats.rx_ofdm;
+       max_cck = &priv->max_delta_stats.rx_cck;
+       max_general = &priv->max_delta_stats.rx_non_phy;
+       max_ht = &priv->max_delta_stats.rx_ofdm_ht;
+
+       pos += iwl_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_Rx - OFDM:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "ina_cnt:",
+                        le32_to_cpu(ofdm->ina_cnt),
+                        accum_ofdm->ina_cnt,
+                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_cnt:",
+                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "plcp_err:",
+                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_err:",
+                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "overrun_err:",
+                        le32_to_cpu(ofdm->overrun_err),
+                        accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+                        max_ofdm->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "early_overrun_err:",
+                        le32_to_cpu(ofdm->early_overrun_err),
+                        accum_ofdm->early_overrun_err,
+                        delta_ofdm->early_overrun_err,
+                        max_ofdm->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_good:",
+                        le32_to_cpu(ofdm->crc32_good),
+                        accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+                        max_ofdm->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "false_alarm_cnt:",
+                        le32_to_cpu(ofdm->false_alarm_cnt),
+                        accum_ofdm->false_alarm_cnt,
+                        delta_ofdm->false_alarm_cnt,
+                        max_ofdm->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_sync_err_cnt:",
+                        le32_to_cpu(ofdm->fina_sync_err_cnt),
+                        accum_ofdm->fina_sync_err_cnt,
+                        delta_ofdm->fina_sync_err_cnt,
+                        max_ofdm->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sfd_timeout:",
+                        le32_to_cpu(ofdm->sfd_timeout),
+                        accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
+                        max_ofdm->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_timeout:",
+                        le32_to_cpu(ofdm->fina_timeout),
+                        accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
+                        max_ofdm->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "unresponded_rts:",
+                        le32_to_cpu(ofdm->unresponded_rts),
+                        accum_ofdm->unresponded_rts,
+                        delta_ofdm->unresponded_rts,
+                        max_ofdm->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+                        accum_ofdm->rxe_frame_limit_overrun,
+                        delta_ofdm->rxe_frame_limit_overrun,
+                        max_ofdm->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_ack_cnt:",
+                        le32_to_cpu(ofdm->sent_ack_cnt),
+                        accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
+                        max_ofdm->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_cts_cnt:",
+                        le32_to_cpu(ofdm->sent_cts_cnt),
+                        accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
+                        max_ofdm->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_ba_rsp_cnt:",
+                        le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+                        accum_ofdm->sent_ba_rsp_cnt,
+                        delta_ofdm->sent_ba_rsp_cnt,
+                        max_ofdm->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "dsp_self_kill:",
+                        le32_to_cpu(ofdm->dsp_self_kill),
+                        accum_ofdm->dsp_self_kill,
+                        delta_ofdm->dsp_self_kill,
+                        max_ofdm->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "mh_format_err:",
+                        le32_to_cpu(ofdm->mh_format_err),
+                        accum_ofdm->mh_format_err,
+                        delta_ofdm->mh_format_err,
+                        max_ofdm->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "re_acq_main_rssi_sum:",
+                        le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+                        accum_ofdm->re_acq_main_rssi_sum,
+                        delta_ofdm->re_acq_main_rssi_sum,
+                        max_ofdm->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_Rx - CCK:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "ina_cnt:",
+                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+                        delta_cck->ina_cnt, max_cck->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_cnt:",
+                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+                        delta_cck->fina_cnt, max_cck->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "plcp_err:",
+                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+                        delta_cck->plcp_err, max_cck->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_err:",
+                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+                        delta_cck->crc32_err, max_cck->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "overrun_err:",
+                        le32_to_cpu(cck->overrun_err),
+                        accum_cck->overrun_err, delta_cck->overrun_err,
+                        max_cck->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "early_overrun_err:",
+                        le32_to_cpu(cck->early_overrun_err),
+                        accum_cck->early_overrun_err,
+                        delta_cck->early_overrun_err,
+                        max_cck->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_good:",
+                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+                        delta_cck->crc32_good, max_cck->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "false_alarm_cnt:",
+                        le32_to_cpu(cck->false_alarm_cnt),
+                        accum_cck->false_alarm_cnt,
+                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_sync_err_cnt:",
+                        le32_to_cpu(cck->fina_sync_err_cnt),
+                        accum_cck->fina_sync_err_cnt,
+                        delta_cck->fina_sync_err_cnt,
+                        max_cck->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sfd_timeout:",
+                        le32_to_cpu(cck->sfd_timeout),
+                        accum_cck->sfd_timeout, delta_cck->sfd_timeout,
+                        max_cck->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "fina_timeout:",
+                        le32_to_cpu(cck->fina_timeout),
+                        accum_cck->fina_timeout, delta_cck->fina_timeout,
+                        max_cck->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "unresponded_rts:",
+                        le32_to_cpu(cck->unresponded_rts),
+                        accum_cck->unresponded_rts, delta_cck->unresponded_rts,
+                        max_cck->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(cck->rxe_frame_limit_overrun),
+                        accum_cck->rxe_frame_limit_overrun,
+                        delta_cck->rxe_frame_limit_overrun,
+                        max_cck->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_ack_cnt:",
+                        le32_to_cpu(cck->sent_ack_cnt),
+                        accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
+                        max_cck->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_cts_cnt:",
+                        le32_to_cpu(cck->sent_cts_cnt),
+                        accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
+                        max_cck->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sent_ba_rsp_cnt:",
+                        le32_to_cpu(cck->sent_ba_rsp_cnt),
+                        accum_cck->sent_ba_rsp_cnt,
+                        delta_cck->sent_ba_rsp_cnt,
+                        max_cck->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "dsp_self_kill:",
+                        le32_to_cpu(cck->dsp_self_kill),
+                        accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
+                        max_cck->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "mh_format_err:",
+                        le32_to_cpu(cck->mh_format_err),
+                        accum_cck->mh_format_err, delta_cck->mh_format_err,
+                        max_cck->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "re_acq_main_rssi_sum:",
+                        le32_to_cpu(cck->re_acq_main_rssi_sum),
+                        accum_cck->re_acq_main_rssi_sum,
+                        delta_cck->re_acq_main_rssi_sum,
+                        max_cck->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_Rx - GENERAL:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "bogus_cts:",
+                        le32_to_cpu(general->bogus_cts),
+                        accum_general->bogus_cts, delta_general->bogus_cts,
+                        max_general->bogus_cts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "bogus_ack:",
+                        le32_to_cpu(general->bogus_ack),
+                        accum_general->bogus_ack, delta_general->bogus_ack,
+                        max_general->bogus_ack);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "non_bssid_frames:",
+                        le32_to_cpu(general->non_bssid_frames),
+                        accum_general->non_bssid_frames,
+                        delta_general->non_bssid_frames,
+                        max_general->non_bssid_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "filtered_frames:",
+                        le32_to_cpu(general->filtered_frames),
+                        accum_general->filtered_frames,
+                        delta_general->filtered_frames,
+                        max_general->filtered_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "non_channel_beacons:",
+                        le32_to_cpu(general->non_channel_beacons),
+                        accum_general->non_channel_beacons,
+                        delta_general->non_channel_beacons,
+                        max_general->non_channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "channel_beacons:",
+                        le32_to_cpu(general->channel_beacons),
+                        accum_general->channel_beacons,
+                        delta_general->channel_beacons,
+                        max_general->channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "num_missed_bcon:",
+                        le32_to_cpu(general->num_missed_bcon),
+                        accum_general->num_missed_bcon,
+                        delta_general->num_missed_bcon,
+                        max_general->num_missed_bcon);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "adc_rx_saturation_time:",
+                        le32_to_cpu(general->adc_rx_saturation_time),
+                        accum_general->adc_rx_saturation_time,
+                        delta_general->adc_rx_saturation_time,
+                        max_general->adc_rx_saturation_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "ina_detect_search_tm:",
+                        le32_to_cpu(general->ina_detection_search_time),
+                        accum_general->ina_detection_search_time,
+                        delta_general->ina_detection_search_time,
+                        max_general->ina_detection_search_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_silence_rssi_a:",
+                        le32_to_cpu(general->beacon_silence_rssi_a),
+                        accum_general->beacon_silence_rssi_a,
+                        delta_general->beacon_silence_rssi_a,
+                        max_general->beacon_silence_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_silence_rssi_b:",
+                        le32_to_cpu(general->beacon_silence_rssi_b),
+                        accum_general->beacon_silence_rssi_b,
+                        delta_general->beacon_silence_rssi_b,
+                        max_general->beacon_silence_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_silence_rssi_c:",
+                        le32_to_cpu(general->beacon_silence_rssi_c),
+                        accum_general->beacon_silence_rssi_c,
+                        delta_general->beacon_silence_rssi_c,
+                        max_general->beacon_silence_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "interference_data_flag:",
+                        le32_to_cpu(general->interference_data_flag),
+                        accum_general->interference_data_flag,
+                        delta_general->interference_data_flag,
+                        max_general->interference_data_flag);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "channel_load:",
+                        le32_to_cpu(general->channel_load),
+                        accum_general->channel_load,
+                        delta_general->channel_load,
+                        max_general->channel_load);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "dsp_false_alarms:",
+                        le32_to_cpu(general->dsp_false_alarms),
+                        accum_general->dsp_false_alarms,
+                        delta_general->dsp_false_alarms,
+                        max_general->dsp_false_alarms);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_rssi_a:",
+                        le32_to_cpu(general->beacon_rssi_a),
+                        accum_general->beacon_rssi_a,
+                        delta_general->beacon_rssi_a,
+                        max_general->beacon_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_rssi_b:",
+                        le32_to_cpu(general->beacon_rssi_b),
+                        accum_general->beacon_rssi_b,
+                        delta_general->beacon_rssi_b,
+                        max_general->beacon_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_rssi_c:",
+                        le32_to_cpu(general->beacon_rssi_c),
+                        accum_general->beacon_rssi_c,
+                        delta_general->beacon_rssi_c,
+                        max_general->beacon_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_energy_a:",
+                        le32_to_cpu(general->beacon_energy_a),
+                        accum_general->beacon_energy_a,
+                        delta_general->beacon_energy_a,
+                        max_general->beacon_energy_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_energy_b:",
+                        le32_to_cpu(general->beacon_energy_b),
+                        accum_general->beacon_energy_b,
+                        delta_general->beacon_energy_b,
+                        max_general->beacon_energy_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "beacon_energy_c:",
+                        le32_to_cpu(general->beacon_energy_c),
+                        accum_general->beacon_energy_c,
+                        delta_general->beacon_energy_c,
+                        max_general->beacon_energy_c);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_Rx - OFDM_HT:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "plcp_err:",
+                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+                        delta_ht->plcp_err, max_ht->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "overrun_err:",
+                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+                        delta_ht->overrun_err, max_ht->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "early_overrun_err:",
+                        le32_to_cpu(ht->early_overrun_err),
+                        accum_ht->early_overrun_err,
+                        delta_ht->early_overrun_err,
+                        max_ht->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_good:",
+                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+                        delta_ht->crc32_good, max_ht->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "crc32_err:",
+                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+                        delta_ht->crc32_err, max_ht->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "mh_format_err:",
+                        le32_to_cpu(ht->mh_format_err),
+                        accum_ht->mh_format_err,
+                        delta_ht->mh_format_err, max_ht->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg_crc32_good:",
+                        le32_to_cpu(ht->agg_crc32_good),
+                        accum_ht->agg_crc32_good,
+                        delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg_mpdu_cnt:",
+                        le32_to_cpu(ht->agg_mpdu_cnt),
+                        accum_ht->agg_mpdu_cnt,
+                        delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg_cnt:",
+                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+                        delta_ht->agg_cnt, max_ht->agg_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "unsupport_mcs:",
+                        le32_to_cpu(ht->unsupport_mcs),
+                        accum_ht->unsupport_mcs,
+                        delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
+       ssize_t ret;
+       struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* the statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       spin_lock_bh(&priv->statistics.lock);
+
+       tx = &priv->statistics.tx;
+       accum_tx = &priv->accum_stats.tx;
+       delta_tx = &priv->delta_stats.tx;
+       max_tx = &priv->max_delta_stats.tx;
+
+       pos += iwl_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_Tx:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "preamble:",
+                        le32_to_cpu(tx->preamble_cnt),
+                        accum_tx->preamble_cnt,
+                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "rx_detected_cnt:",
+                        le32_to_cpu(tx->rx_detected_cnt),
+                        accum_tx->rx_detected_cnt,
+                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "bt_prio_defer_cnt:",
+                        le32_to_cpu(tx->bt_prio_defer_cnt),
+                        accum_tx->bt_prio_defer_cnt,
+                        delta_tx->bt_prio_defer_cnt,
+                        max_tx->bt_prio_defer_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "bt_prio_kill_cnt:",
+                        le32_to_cpu(tx->bt_prio_kill_cnt),
+                        accum_tx->bt_prio_kill_cnt,
+                        delta_tx->bt_prio_kill_cnt,
+                        max_tx->bt_prio_kill_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "few_bytes_cnt:",
+                        le32_to_cpu(tx->few_bytes_cnt),
+                        accum_tx->few_bytes_cnt,
+                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "cts_timeout:",
+                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+                        delta_tx->cts_timeout, max_tx->cts_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "ack_timeout:",
+                        le32_to_cpu(tx->ack_timeout),
+                        accum_tx->ack_timeout,
+                        delta_tx->ack_timeout, max_tx->ack_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "expected_ack_cnt:",
+                        le32_to_cpu(tx->expected_ack_cnt),
+                        accum_tx->expected_ack_cnt,
+                        delta_tx->expected_ack_cnt,
+                        max_tx->expected_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "actual_ack_cnt:",
+                        le32_to_cpu(tx->actual_ack_cnt),
+                        accum_tx->actual_ack_cnt,
+                        delta_tx->actual_ack_cnt,
+                        max_tx->actual_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "dump_msdu_cnt:",
+                        le32_to_cpu(tx->dump_msdu_cnt),
+                        accum_tx->dump_msdu_cnt,
+                        delta_tx->dump_msdu_cnt,
+                        max_tx->dump_msdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "abort_nxt_frame_mismatch:",
+                        le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+                        accum_tx->burst_abort_next_frame_mismatch_cnt,
+                        delta_tx->burst_abort_next_frame_mismatch_cnt,
+                        max_tx->burst_abort_next_frame_mismatch_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "abort_missing_nxt_frame:",
+                        le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+                        accum_tx->burst_abort_missing_next_frame_cnt,
+                        delta_tx->burst_abort_missing_next_frame_cnt,
+                        max_tx->burst_abort_missing_next_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "cts_timeout_collision:",
+                        le32_to_cpu(tx->cts_timeout_collision),
+                        accum_tx->cts_timeout_collision,
+                        delta_tx->cts_timeout_collision,
+                        max_tx->cts_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "ack_ba_timeout_collision:",
+                        le32_to_cpu(tx->ack_or_ba_timeout_collision),
+                        accum_tx->ack_or_ba_timeout_collision,
+                        delta_tx->ack_or_ba_timeout_collision,
+                        max_tx->ack_or_ba_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg ba_timeout:",
+                        le32_to_cpu(tx->agg.ba_timeout),
+                        accum_tx->agg.ba_timeout,
+                        delta_tx->agg.ba_timeout,
+                        max_tx->agg.ba_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg ba_resched_frames:",
+                        le32_to_cpu(tx->agg.ba_reschedule_frames),
+                        accum_tx->agg.ba_reschedule_frames,
+                        delta_tx->agg.ba_reschedule_frames,
+                        max_tx->agg.ba_reschedule_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg scd_query_agg_frame:",
+                        le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+                        accum_tx->agg.scd_query_agg_frame_cnt,
+                        delta_tx->agg.scd_query_agg_frame_cnt,
+                        max_tx->agg.scd_query_agg_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg scd_query_no_agg:",
+                        le32_to_cpu(tx->agg.scd_query_no_agg),
+                        accum_tx->agg.scd_query_no_agg,
+                        delta_tx->agg.scd_query_no_agg,
+                        max_tx->agg.scd_query_no_agg);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg scd_query_agg:",
+                        le32_to_cpu(tx->agg.scd_query_agg),
+                        accum_tx->agg.scd_query_agg,
+                        delta_tx->agg.scd_query_agg,
+                        max_tx->agg.scd_query_agg);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg scd_query_mismatch:",
+                        le32_to_cpu(tx->agg.scd_query_mismatch),
+                        accum_tx->agg.scd_query_mismatch,
+                        delta_tx->agg.scd_query_mismatch,
+                        max_tx->agg.scd_query_mismatch);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg frame_not_ready:",
+                        le32_to_cpu(tx->agg.frame_not_ready),
+                        accum_tx->agg.frame_not_ready,
+                        delta_tx->agg.frame_not_ready,
+                        max_tx->agg.frame_not_ready);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg underrun:",
+                        le32_to_cpu(tx->agg.underrun),
+                        accum_tx->agg.underrun,
+                        delta_tx->agg.underrun, max_tx->agg.underrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg bt_prio_kill:",
+                        le32_to_cpu(tx->agg.bt_prio_kill),
+                        accum_tx->agg.bt_prio_kill,
+                        delta_tx->agg.bt_prio_kill,
+                        max_tx->agg.bt_prio_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "agg rx_ba_rsp_cnt:",
+                        le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+                        accum_tx->agg.rx_ba_rsp_cnt,
+                        delta_tx->agg.rx_ba_rsp_cnt,
+                        max_tx->agg.rx_ba_rsp_cnt);
+
+       if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "tx power: (1/2 dB step)\n");
+               if ((priv->eeprom_data->valid_tx_ant & ANT_A) &&
+                   tx->tx_power.ant_a)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       fmt_hex, "antenna A:",
+                                       tx->tx_power.ant_a);
+               if ((priv->eeprom_data->valid_tx_ant & ANT_B) &&
+                   tx->tx_power.ant_b)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       fmt_hex, "antenna B:",
+                                       tx->tx_power.ant_b);
+               if ((priv->eeprom_data->valid_tx_ant & ANT_C) &&
+                   tx->tx_power.ant_c)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       fmt_hex, "antenna C:",
+                                       tx->tx_power.ant_c);
+       }
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct statistics_general) * 10 + 300;
+       ssize_t ret;
+       struct statistics_general_common *general, *accum_general;
+       struct statistics_general_common *delta_general, *max_general;
+       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+       struct statistics_div *div, *accum_div, *delta_div, *max_div;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* the statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+
+       spin_lock_bh(&priv->statistics.lock);
+
+       general = &priv->statistics.common;
+       dbg = &priv->statistics.common.dbg;
+       div = &priv->statistics.common.div;
+       accum_general = &priv->accum_stats.common;
+       accum_dbg = &priv->accum_stats.common.dbg;
+       accum_div = &priv->accum_stats.common.div;
+       delta_general = &priv->delta_stats.common;
+       max_general = &priv->max_delta_stats.common;
+       delta_dbg = &priv->delta_stats.common.dbg;
+       max_dbg = &priv->max_delta_stats.common.dbg;
+       delta_div = &priv->delta_stats.common.div;
+       max_div = &priv->max_delta_stats.common.div;
+
+       pos += iwl_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_header, "Statistics_General:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_value, "temperature:",
+                        le32_to_cpu(general->temperature));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_value, "temperature_m:",
+                        le32_to_cpu(general->temperature_m));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_value, "ttl_timestamp:",
+                        le32_to_cpu(general->ttl_timestamp));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "burst_check:",
+                        le32_to_cpu(dbg->burst_check),
+                        accum_dbg->burst_check,
+                        delta_dbg->burst_check, max_dbg->burst_check);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "burst_count:",
+                        le32_to_cpu(dbg->burst_count),
+                        accum_dbg->burst_count,
+                        delta_dbg->burst_count, max_dbg->burst_count);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "wait_for_silence_timeout_count:",
+                        le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
+                        accum_dbg->wait_for_silence_timeout_cnt,
+                        delta_dbg->wait_for_silence_timeout_cnt,
+                        max_dbg->wait_for_silence_timeout_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "sleep_time:",
+                        le32_to_cpu(general->sleep_time),
+                        accum_general->sleep_time,
+                        delta_general->sleep_time, max_general->sleep_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "slots_out:",
+                        le32_to_cpu(general->slots_out),
+                        accum_general->slots_out,
+                        delta_general->slots_out, max_general->slots_out);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "slots_idle:",
+                        le32_to_cpu(general->slots_idle),
+                        accum_general->slots_idle,
+                        delta_general->slots_idle, max_general->slots_idle);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "tx_on_a:",
+                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+                        delta_div->tx_on_a, max_div->tx_on_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "tx_on_b:",
+                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+                        delta_div->tx_on_b, max_div->tx_on_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "exec_time:",
+                        le32_to_cpu(div->exec_time), accum_div->exec_time,
+                        delta_div->exec_time, max_div->exec_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "probe_time:",
+                        le32_to_cpu(div->probe_time), accum_div->probe_time,
+                        delta_div->probe_time, max_div->probe_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "rx_enable_counter:",
+                        le32_to_cpu(general->rx_enable_counter),
+                        accum_general->rx_enable_counter,
+                        delta_general->rx_enable_counter,
+                        max_general->rx_enable_counter);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        fmt_table, "num_of_sos_states:",
+                        le32_to_cpu(general->num_of_sos_states),
+                        accum_general->num_of_sos_states,
+                        delta_general->num_of_sos_states,
+                        max_general->num_of_sos_states);
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
+       ssize_t ret;
+       struct statistics_bt_activity *bt, *accum_bt;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       if (!priv->bt_enable_flag)
+               return -EINVAL;
+
+       /* make request to uCode to retrieve statistics information */
+       mutex_lock(&priv->mutex);
+       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
+       mutex_unlock(&priv->mutex);
+
+       if (ret)
+               return -EAGAIN;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /*
+        * the statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+
+       spin_lock_bh(&priv->statistics.lock);
+
+       bt = &priv->statistics.bt_activity;
+       accum_bt = &priv->accum_stats.bt_activity;
+
+       pos += iwl_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "\t\t\tcurrent\t\t\taccumulative\n");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->hi_priority_tx_req_cnt),
+                        accum_bt->hi_priority_tx_req_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->hi_priority_tx_denied_cnt),
+                        accum_bt->hi_priority_tx_denied_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->lo_priority_tx_req_cnt),
+                        accum_bt->lo_priority_tx_req_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->lo_priority_tx_denied_cnt),
+                        accum_bt->lo_priority_tx_denied_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->hi_priority_rx_req_cnt),
+                        accum_bt->hi_priority_rx_req_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->hi_priority_rx_denied_cnt),
+                        accum_bt->hi_priority_rx_denied_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->lo_priority_rx_req_cnt),
+                        accum_bt->lo_priority_rx_req_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
+                        le32_to_cpu(bt->lo_priority_rx_denied_cnt),
+                        accum_bt->lo_priority_rx_denied_cnt);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(priv->statistics.num_bt_kills),
+                        priv->statistics.accum_num_bt_kills);
+
+       spin_unlock_bh(&priv->statistics.lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
+               (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
+       ssize_t ret;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
+                        priv->reply_tx_stats.pp_delay);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
+                        priv->reply_tx_stats.pp_few_bytes);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
+                        priv->reply_tx_stats.pp_bt_prio);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
+                        priv->reply_tx_stats.pp_quiet_period);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
+                        priv->reply_tx_stats.pp_calc_ttak);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_tx_fail_reason(
+                               TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
+                        priv->reply_tx_stats.int_crossed_retry);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
+                        priv->reply_tx_stats.short_limit);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
+                        priv->reply_tx_stats.long_limit);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
+                        priv->reply_tx_stats.fifo_underrun);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
+                        priv->reply_tx_stats.drain_flow);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
+                        priv->reply_tx_stats.rfkill_flush);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
+                        priv->reply_tx_stats.life_expire);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
+                        priv->reply_tx_stats.dest_ps);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
+                        priv->reply_tx_stats.host_abort);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
+                        priv->reply_tx_stats.pp_delay);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
+                        priv->reply_tx_stats.sta_invalid);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
+                        priv->reply_tx_stats.frag_drop);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
+                        priv->reply_tx_stats.tid_disable);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
+                        priv->reply_tx_stats.fifo_flush);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_tx_fail_reason(
+                               TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
+                        priv->reply_tx_stats.insuff_cf_poll);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
+                        priv->reply_tx_stats.fail_hw_drop);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_tx_fail_reason(
+                               TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
+                        priv->reply_tx_stats.sta_color_mismatch);
+       pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+                        priv->reply_tx_stats.unknown);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "\nStatistics_Agg_TX_Error:\n");
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
+                        priv->reply_agg_tx_stats.underrun);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
+                        priv->reply_agg_tx_stats.bt_prio);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
+                        priv->reply_agg_tx_stats.few_bytes);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
+                        priv->reply_agg_tx_stats.abort);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(
+                               AGG_TX_STATE_LAST_SENT_TTL_MSK),
+                        priv->reply_agg_tx_stats.last_sent_ttl);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(
+                               AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
+                        priv->reply_agg_tx_stats.last_sent_try);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(
+                               AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
+                        priv->reply_agg_tx_stats.last_sent_bt_kill);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
+                        priv->reply_agg_tx_stats.scd_query);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(
+                               AGG_TX_STATE_TEST_BAD_CRC32_MSK),
+                        priv->reply_agg_tx_stats.bad_crc32);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
+                        priv->reply_agg_tx_stats.response);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
+                        priv->reply_agg_tx_stats.dump_tx);
+       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
+                        priv->reply_agg_tx_stats.delay_tx);
+       pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+                        priv->reply_agg_tx_stats.unknown);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       int cnt = 0;
+       char *buf;
+       int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
+       ssize_t ret;
+       struct iwl_sensitivity_data *data;
+
+       data = &priv->sensitivity_data;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
+                       data->auto_corr_ofdm);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "auto_corr_ofdm_mrc:\t\t %u\n",
+                       data->auto_corr_ofdm_mrc);
+       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
+                       data->auto_corr_ofdm_x1);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "auto_corr_ofdm_mrc_x1:\t\t %u\n",
+                       data->auto_corr_ofdm_mrc_x1);
+       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
+                       data->auto_corr_cck);
+       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
+                       data->auto_corr_cck_mrc);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "last_bad_plcp_cnt_ofdm:\t\t %u\n",
+                       data->last_bad_plcp_cnt_ofdm);
+       pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
+                       data->last_fa_cnt_ofdm);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "last_bad_plcp_cnt_cck:\t\t %u\n",
+                       data->last_bad_plcp_cnt_cck);
+       pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
+                       data->last_fa_cnt_cck);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
+                       data->nrg_curr_state);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
+                       data->nrg_prev_state);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
+       for (cnt = 0; cnt < 10; cnt++) {
+               pos += scnprintf(buf + pos, bufsz - pos, " %u",
+                               data->nrg_value[cnt]);
+       }
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
+       for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
+               pos += scnprintf(buf + pos, bufsz - pos, " %u",
+                               data->nrg_silence_rssi[cnt]);
+       }
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
+                       data->nrg_silence_ref);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
+                       data->nrg_energy_idx);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
+                       data->nrg_silence_idx);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
+                       data->nrg_th_cck);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "nrg_auto_corr_silence_diff:\t %u\n",
+                       data->nrg_auto_corr_silence_diff);
+       pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
+                       data->num_in_cck_no_fa);
+       pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
+                       data->nrg_th_ofdm);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+
+static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       int cnt = 0;
+       char *buf;
+       int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
+       ssize_t ret;
+       struct iwl_chain_noise_data *data;
+
+       data = &priv->chain_noise_data;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
+                       data->active_chains);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
+                       data->chain_noise_a);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
+                       data->chain_noise_b);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
+                       data->chain_noise_c);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
+                       data->chain_signal_a);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
+                       data->chain_signal_b);
+       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
+                       data->chain_signal_c);
+       pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
+                       data->beacon_count);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
+       for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+               pos += scnprintf(buf + pos, bufsz - pos, " %u",
+                               data->disconn_array[cnt]);
+       }
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
+       for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
+               pos += scnprintf(buf + pos, bufsz - pos, " %u",
+                               data->delta_gain_code[cnt]);
+       }
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
+                       data->radio_write);
+       pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
+                       data->state);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+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 = file->private_data;
+       char buf[60];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+       u32 pwrsave_status;
+
+       pwrsave_status = iwl_read32(priv->trans, 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);
+}
+
+static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int clear;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &clear) != 1)
+               return -EFAULT;
+
+       /* make request to uCode to retrieve statistics information */
+       mutex_lock(&priv->mutex);
+       iwl_send_statistics_request(priv, CMD_SYNC, true);
+       mutex_unlock(&priv->mutex);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char buf[128];
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
+                       priv->event_log.ucode_trace ? "On" : "Off");
+       pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
+                       priv->event_log.non_wraps_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
+                       priv->event_log.wraps_once_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
+                       priv->event_log.wraps_more_count);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int trace;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &trace) != 1)
+               return -EFAULT;
+
+       if (trace) {
+               priv->event_log.ucode_trace = true;
+               if (iwl_is_alive(priv)) {
+                       /* start collecting data now */
+                       mod_timer(&priv->ucode_trace, jiffies);
+               }
+       } else {
+               priv->event_log.ucode_trace = false;
+               del_timer_sync(&priv->ucode_trace);
+       }
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int len = 0;
+       char buf[20];
+
+       len = sprintf(buf, "0x%04X\n",
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int len = 0;
+       char buf[20];
+
+       len = sprintf(buf, "0x%04X\n",
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char buf[12];
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
+                       priv->missed_beacon_threshold);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int missed;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &missed) != 1)
+               return -EINVAL;
+
+       if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
+           missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
+               priv->missed_beacon_threshold =
+                       IWL_MISSED_BEACON_THRESHOLD_DEF;
+       else
+               priv->missed_beacon_threshold = missed;
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char buf[12];
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
+                       priv->plcp_delta_threshold);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int plcp;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &plcp) != 1)
+               return -EINVAL;
+       if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+               (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
+               priv->plcp_delta_threshold =
+                       IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
+       else
+               priv->plcp_delta_threshold = plcp;
+       return count;
+}
+
+static ssize_t iwl_dbgfs_rf_reset_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char buf[300];
+       const size_t bufsz = sizeof(buf);
+       struct iwl_rf_reset *rf_reset = &priv->rf_reset;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "RF reset statistics\n");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tnumber of reset request: %d\n",
+                       rf_reset->reset_request_count);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tnumber of reset request success: %d\n",
+                       rf_reset->reset_success_count);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tnumber of reset request reject: %d\n",
+                       rf_reset->reset_reject_count);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_rf_reset_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int ret;
+
+       ret = iwl_force_rf_reset(priv, true);
+       return ret ? ret : count;
+}
+
+static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int flush;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &flush) != 1)
+               return -EINVAL;
+
+       if (iwl_is_rfkill(priv))
+               return -EFAULT;
+
+       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[200];
+       const size_t bufsz = sizeof(buf);
+
+       if (!priv->bt_enable_flag) {
+               pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
+               return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       }
+       pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
+               priv->bt_enable_flag);
+       pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
+               priv->bt_full_concurrent ? "full concurrency" : "3-wire");
+       pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
+                        "last traffic notif: %d\n",
+               priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load);
+       pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
+                        "kill_ack_mask: %x, kill_cts_mask: %x\n",
+               priv->bt_ch_announce, priv->kill_ack_mask,
+               priv->kill_cts_mask);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+               pos += scnprintf(buf + pos, bufsz - pos, "High\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+       default:
+               pos += scnprintf(buf + pos, bufsz - pos, "None\n");
+               break;
+       }
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+
+       int pos = 0;
+       char buf[40];
+       const size_t bufsz = sizeof(buf);
+
+       if (priv->cfg->ht_params)
+               pos += scnprintf(buf + pos, bufsz - pos,
+                        "use %s for aggregation\n",
+                        (priv->hw_params.use_rts_for_aggregation) ?
+                               "rts/cts" : "cts-to-self");
+       else
+               pos += scnprintf(buf + pos, bufsz - pos, "N/A");
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int rts;
+
+       if (!priv->cfg->ht_params)
+               return -EINVAL;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &rts) != 1)
+               return -EINVAL;
+       if (rts)
+               priv->hw_params.use_rts_for_aggregation = true;
+       else
+               priv->hw_params.use_rts_for_aggregation = false;
+       return count;
+}
+
+static int iwl_cmd_echo_test(struct iwl_priv *priv)
+{
+       int ret;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_ECHO,
+               .len = { 0 },
+               .flags = CMD_SYNC,
+       };
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+       if (ret)
+               IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
+       else
+               IWL_DEBUG_INFO(priv, "echo testing pass\n");
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_echo_test_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       iwl_cmd_echo_test(priv);
+       return count;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -ENOMEM;
+
+       ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
+       if (buf) {
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+               kfree(buf);
+       }
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       u32 event_log_flag;
+       char buf[8];
+       int buf_size;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &event_log_flag) != 1)
+               return -EFAULT;
+       if (event_log_flag == 1)
+               iwl_dump_nic_event_log(priv, true, NULL, false);
+
+       return count;
+}
+#endif
+
+static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[120];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "Sensitivity calibrations %s\n",
+                        (priv->calib_disabled &
+                                       IWL_SENSITIVITY_CALIB_DISABLED) ?
+                        "DISABLED" : "ENABLED");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "Chain noise calibrations %s\n",
+                        (priv->calib_disabled &
+                                       IWL_CHAIN_NOISE_CALIB_DISABLED) ?
+                        "DISABLED" : "ENABLED");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "Tx power calibrations %s\n",
+                        (priv->calib_disabled &
+                                       IWL_TX_POWER_CALIB_DISABLED) ?
+                        "DISABLED" : "ENABLED");
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       u32 calib_disabled;
+       int buf_size;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%x", &calib_disabled) != 1)
+               return -EFAULT;
+
+       priv->calib_disabled = calib_disabled;
+
+       return count;
+}
+
+DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
+DEBUGFS_READ_FILE_OPS(ucode_general_stats);
+DEBUGFS_READ_FILE_OPS(sensitivity);
+DEBUGFS_READ_FILE_OPS(chain_noise);
+DEBUGFS_READ_FILE_OPS(power_save_status);
+DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
+DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
+DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
+DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
+DEBUGFS_READ_WRITE_FILE_OPS(rf_reset);
+DEBUGFS_READ_FILE_OPS(rxon_flags);
+DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
+DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
+DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
+DEBUGFS_READ_FILE_OPS(bt_traffic);
+DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
+DEBUGFS_READ_FILE_OPS(reply_tx_error);
+DEBUGFS_WRITE_FILE_OPS(echo_test);
+#ifdef CONFIG_IWLWIFI_DEBUG
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
+#endif
+DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
+{
+       struct dentry *phyd = priv->hw->wiphy->debugfsdir;
+       struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
+
+       dir_drv = debugfs_create_dir(name, phyd);
+       if (!dir_drv)
+               return -ENOMEM;
+
+       priv->debugfs_dir = dir_drv;
+
+       dir_data = debugfs_create_dir("data", dir_drv);
+       if (!dir_data)
+               goto err;
+       dir_rf = debugfs_create_dir("rf", dir_drv);
+       if (!dir_rf)
+               goto err;
+       dir_debug = debugfs_create_dir("debug", dir_drv);
+       if (!dir_debug)
+               goto err;
+
+       DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
+
+       DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
+#endif
+
+       if (iwl_advanced_bt_coexist(priv))
+               DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
+
+       /* Calibrations disabled/enabled status*/
+       DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
+
+       if (iwl_trans_dbgfs_register(priv->trans, dir_debug))
+               goto err;
+       return 0;
+
+err:
+       IWL_ERR(priv, "Can't create the debugfs directory\n");
+       iwl_dbgfs_unregister(priv);
+       return -ENOMEM;
+}
+
+/**
+ * Remove the debugfs files and directories
+ *
+ */
+void iwl_dbgfs_unregister(struct iwl_priv *priv)
+{
+       if (!priv->debugfs_dir)
+               return;
+
+       debugfs_remove_recursive(priv->debugfs_dir);
+       priv->debugfs_dir = NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h
new file mode 100644 (file)
index 0000000..54cf085
--- /dev/null
@@ -0,0 +1,933 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (dev.h) for driver implementation definitions.
+ * Please use commands.h for uCode API definitions.
+ */
+
+#ifndef __iwl_dev_h__
+#define __iwl_dev_h__
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include "iwl-fw.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-csr.h"
+#include "iwl-debug.h"
+#include "iwl-agn-hw.h"
+#include "iwl-op-mode.h"
+#include "iwl-notif-wait.h"
+#include "iwl-trans.h"
+
+#include "led.h"
+#include "power.h"
+#include "rs.h"
+#include "tt.h"
+
+#include "iwl-test.h"
+
+/* CT-KILL constants */
+#define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
+#define CT_KILL_THRESHOLD         114 /* in Celsius */
+#define CT_KILL_EXIT_THRESHOLD     95  /* in Celsius */
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated  no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for all agn devices, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE            2304U
+#define MAX_MPDU_SIZE            2346U
+#define DEFAULT_BEACON_INTERVAL   200U
+#define        DEFAULT_SHORT_RETRY_LIMIT 7U
+#define        DEFAULT_LONG_RETRY_LIMIT  4U
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+/*
+ * Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate
+ *  - 4 standard TX queues
+ *  - the command queue
+ *  - 4 PAN TX queues
+ *  - the PAN multicast queue, and
+ *  - the AUX (TX during scan dwell) queue.
+ */
+#define IWL_MIN_NUM_QUEUES     11
+
+/*
+ * Command queue depends on iPAN support.
+ */
+#define IWL_DEFAULT_CMD_QUEUE_NUM      4
+#define IWL_IPAN_CMD_QUEUE_NUM         9
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+union iwl_ht_rate_supp {
+       u16 rates;
+       struct {
+               u8 siso_rate;
+               u8 mimo_rate;
+       };
+};
+
+struct iwl_ht_config {
+       bool single_chain_sufficient;
+       enum ieee80211_smps_mode smps; /* current smps mode */
+};
+
+/* QoS structures */
+struct iwl_qos_info {
+       int qos_active;
+       struct iwl_qosparam_cmd def_qos_parm;
+};
+
+/**
+ * enum iwl_agg_state
+ *
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ *     HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ *     HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_agg_state {
+       IWL_AGG_OFF = 0,
+       IWL_AGG_STARTING,
+       IWL_AGG_ON,
+       IWL_EMPTYING_HW_QUEUE_ADDBA,
+       IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_ht_agg - aggregation state machine
+
+ * This structs holds the states for the BA agreement establishment and tear
+ * down. It also holds the state during the BA session itself. This struct is
+ * duplicated for each RA / TID.
+
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ *     Tx response (REPLY_TX), and the block ack notification
+ *     (REPLY_COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session
+ * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
+ *     the first packet to be sent in legacy HW queue in Tx AGG stop flow.
+ *     Basically when next_reclaimed reaches ssn, we can tell mac80211 that
+ *     we are ready to finish the Tx AGG stop / start flow.
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ */
+struct iwl_ht_agg {
+       u32 rate_n_flags;
+       enum iwl_agg_state state;
+       u16 txq_id;
+       u16 ssn;
+       bool wait_for_ba;
+};
+
+/**
+ * struct iwl_tid_data - one for each RA / TID
+
+ * This structs holds the states for each RA / TID.
+
+ * @seq_number: the next WiFi sequence number to use
+ * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
+ *     This is basically (last acked packet++).
+ * @agg: aggregation state machine
+ */
+struct iwl_tid_data {
+       u16 seq_number;
+       u16 next_reclaimed;
+       struct iwl_ht_agg agg;
+};
+
+/*
+ * Structure should be accessed with sta_lock held. When station addition
+ * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only
+ * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock
+ * held.
+ */
+struct iwl_station_entry {
+       struct iwl_addsta_cmd sta;
+       u8 used, ctxid;
+       struct iwl_link_quality_cmd *lq;
+};
+
+/*
+ * 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.
+ */
+struct iwl_station_priv {
+       struct iwl_rxon_context *ctx;
+       struct iwl_lq_sta lq_sta;
+       atomic_t pending_frames;
+       bool client;
+       bool asleep;
+       u8 max_agg_bufsize;
+       u8 sta_id;
+};
+
+/**
+ * struct iwl_vif_priv - driver's private per-interface information
+ *
+ * When mac80211 allocates a virtual interface, it can allocate
+ * space for us to put data into.
+ */
+struct iwl_vif_priv {
+       struct iwl_rxon_context *ctx;
+       u8 ibss_bssid_sta_id;
+};
+
+struct iwl_sensitivity_ranges {
+       u16 min_nrg_cck;
+
+       u16 nrg_th_cck;
+       u16 nrg_th_ofdm;
+
+       u16 auto_corr_min_ofdm;
+       u16 auto_corr_min_ofdm_mrc;
+       u16 auto_corr_min_ofdm_x1;
+       u16 auto_corr_min_ofdm_mrc_x1;
+
+       u16 auto_corr_max_ofdm;
+       u16 auto_corr_max_ofdm_mrc;
+       u16 auto_corr_max_ofdm_x1;
+       u16 auto_corr_max_ofdm_mrc_x1;
+
+       u16 auto_corr_max_cck;
+       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;
+};
+
+
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in core module which are forward declared here
+ * for use by iwl-[4-5].c
+ *
+ * NOTE:  The implementation of these functions are not hardware specific
+ * which is why they are in the core module files.
+ *
+ * Naming convention --
+ * iwl_         <-- Is part of iwlwifi
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ *
+ ****************************************************************************/
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern const u8 iwl_bcast_addr[ETH_ALEN];
+
+#define IWL_OPERATION_MODE_AUTO     0
+#define IWL_OPERATION_MODE_HT_ONLY  1
+#define IWL_OPERATION_MODE_MIXED    2
+#define IWL_OPERATION_MODE_20MHZ    3
+
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+
+/* Sensitivity and chain noise calibration */
+#define INITIALIZATION_VALUE           0xFFFF
+#define IWL_CAL_NUM_BEACONS            16
+#define MAXIMUM_ALLOWED_PATHLOSS       15
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM  50
+#define MIN_FA_OFDM  5
+#define MAX_FA_CCK   50
+#define MIN_FA_CCK   5
+
+#define AUTO_CORR_STEP_OFDM       1
+
+#define AUTO_CORR_STEP_CCK     3
+#define AUTO_CORR_MAX_TH_CCK   160
+
+#define NRG_DIFF               2
+#define NRG_STEP_CCK           2
+#define NRG_MARGIN             8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
+
+#define CHAIN_A             0
+#define CHAIN_B             1
+#define CHAIN_C             2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER                        0xFF00
+#define IN_BAND_FILTER                 0xFF
+#define MIN_AVERAGE_NOISE_MAX_VALUE    0xFFFFFFFF
+
+#define NRG_NUM_PREV_STAT_L     20
+#define NUM_RX_CHAINS           3
+
+enum iwlagn_false_alarm_state {
+       IWL_FA_TOO_MANY = 0,
+       IWL_FA_TOO_FEW = 1,
+       IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwlagn_chain_noise_state {
+       IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
+       IWL_CHAIN_NOISE_ACCUMULATE,
+       IWL_CHAIN_NOISE_CALIBRATED,
+       IWL_CHAIN_NOISE_DONE,
+};
+
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+       u32 auto_corr_ofdm;
+       u32 auto_corr_ofdm_mrc;
+       u32 auto_corr_ofdm_x1;
+       u32 auto_corr_ofdm_mrc_x1;
+       u32 auto_corr_cck;
+       u32 auto_corr_cck_mrc;
+
+       u32 last_bad_plcp_cnt_ofdm;
+       u32 last_fa_cnt_ofdm;
+       u32 last_bad_plcp_cnt_cck;
+       u32 last_fa_cnt_cck;
+
+       u32 nrg_curr_state;
+       u32 nrg_prev_state;
+       u32 nrg_value[10];
+       u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+       u32 nrg_silence_ref;
+       u32 nrg_energy_idx;
+       u32 nrg_silence_idx;
+       u32 nrg_th_cck;
+       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 */
+struct iwl_chain_noise_data {
+       u32 active_chains;
+       u32 chain_noise_a;
+       u32 chain_noise_b;
+       u32 chain_noise_c;
+       u32 chain_signal_a;
+       u32 chain_signal_b;
+       u32 chain_signal_c;
+       u16 beacon_count;
+       u8 disconn_array[NUM_RX_CHAINS];
+       u8 delta_gain_code[NUM_RX_CHAINS];
+       u8 radio_write;
+       u8 state;
+};
+
+enum {
+       MEASUREMENT_READY = (1 << 0),
+       MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+/* reply_tx_statistics (for _agn devices) */
+struct reply_tx_error_statistics {
+       u32 pp_delay;
+       u32 pp_few_bytes;
+       u32 pp_bt_prio;
+       u32 pp_quiet_period;
+       u32 pp_calc_ttak;
+       u32 int_crossed_retry;
+       u32 short_limit;
+       u32 long_limit;
+       u32 fifo_underrun;
+       u32 drain_flow;
+       u32 rfkill_flush;
+       u32 life_expire;
+       u32 dest_ps;
+       u32 host_abort;
+       u32 bt_retry;
+       u32 sta_invalid;
+       u32 frag_drop;
+       u32 tid_disable;
+       u32 fifo_flush;
+       u32 insuff_cf_poll;
+       u32 fail_hw_drop;
+       u32 sta_color_mismatch;
+       u32 unknown;
+};
+
+/* reply_agg_tx_statistics (for _agn devices) */
+struct reply_agg_tx_error_statistics {
+       u32 underrun;
+       u32 bt_prio;
+       u32 few_bytes;
+       u32 abort;
+       u32 last_sent_ttl;
+       u32 last_sent_try;
+       u32 last_sent_bt_kill;
+       u32 scd_query;
+       u32 bad_crc32;
+       u32 response;
+       u32 dump_tx;
+       u32 delay_tx;
+       u32 unknown;
+};
+
+/*
+ * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
+ * to perform continuous uCode event logging operation if enabled
+ */
+#define UCODE_TRACE_PERIOD (10)
+
+/*
+ * iwl_event_log: current uCode event log position
+ *
+ * @ucode_trace: enable/disable ucode continuous trace timer
+ * @num_wraps: how many times the event buffer wraps
+ * @next_entry:  the entry just before the next one that uCode would fill
+ * @non_wraps_count: counter for no wrap detected when dump ucode events
+ * @wraps_once_count: counter for wrap once detected when dump ucode events
+ * @wraps_more_count: counter for wrap more than once detected
+ *                   when dump ucode events
+ */
+struct iwl_event_log {
+       bool ucode_trace;
+       u32 num_wraps;
+       u32 next_entry;
+       int non_wraps_count;
+       int wraps_once_count;
+       int wraps_more_count;
+};
+
+#define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD      (35)
+
+/* Firmware reload counter and Timestamp */
+#define IWL_MIN_RELOAD_DURATION                1000 /* 1000 ms */
+#define IWL_MAX_CONTINUE_RELOAD_CNT    4
+
+
+struct iwl_rf_reset {
+       int reset_request_count;
+       int reset_success_count;
+       int reset_reject_count;
+       unsigned long last_reset_jiffies;
+};
+
+enum iwl_rxon_context_id {
+       IWL_RXON_CTX_BSS,
+       IWL_RXON_CTX_PAN,
+
+       NUM_IWL_RXON_CTX
+};
+
+/* extend beacon time format bit shifting  */
+/*
+ * for _agn devices
+ * bits 31:22 - extended
+ * bits 21:0  - interval
+ */
+#define IWLAGN_EXT_BEACON_TIME_POS     22
+
+struct iwl_rxon_context {
+       struct ieee80211_vif *vif;
+
+       u8 mcast_queue;
+       u8 ac_to_queue[IEEE80211_NUM_ACS];
+       u8 ac_to_fifo[IEEE80211_NUM_ACS];
+
+       /*
+        * We could use the vif to indicate active, but we
+        * also need it to be active during disabling when
+        * we already removed the vif for type setting.
+        */
+       bool always_active, is_active;
+
+       bool ht_need_multiple_chains;
+
+       enum iwl_rxon_context_id ctxid;
+
+       u32 interface_modes, exclusive_interface_modes;
+       u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
+
+       /*
+        * We declare this const so it can only be
+        * changed via explicit cast within the
+        * routines that actually update the physical
+        * hardware.
+        */
+       const struct iwl_rxon_cmd active;
+       struct iwl_rxon_cmd staging;
+
+       struct iwl_rxon_time_cmd timing;
+
+       struct iwl_qos_info qos_data;
+
+       u8 bcast_sta_id, ap_sta_id;
+
+       u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
+       u8 qos_cmd;
+       u8 wep_key_cmd;
+
+       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+       u8 key_mapping_keys;
+
+       __le32 station_flags;
+
+       int beacon_int;
+
+       struct {
+               bool non_gf_sta_present;
+               u8 protection;
+               bool enabled, is_40mhz;
+               u8 extension_chan_offset;
+       } ht;
+};
+
+enum iwl_scan_type {
+       IWL_SCAN_NORMAL,
+       IWL_SCAN_RADIO_RESET,
+       IWL_SCAN_ROC,
+};
+
+/**
+ * struct iwl_hw_params
+ *
+ * Holds the module parameters
+ *
+ * @tx_chains_num: Number of TX chains
+ * @rx_chains_num: Number of RX chains
+ * @ct_kill_threshold: temperature threshold - in hw dependent unit
+ * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
+ *     relevant for 1000, 6000 and up
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
+ * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+ */
+struct iwl_hw_params {
+       u8  tx_chains_num;
+       u8  rx_chains_num;
+       bool use_rts_for_aggregation;
+       u32 ct_kill_threshold;
+       u32 ct_kill_exit_threshold;
+
+       const struct iwl_sensitivity_ranges *sens;
+};
+
+struct iwl_lib_ops {
+       /* set hw dependent parameters */
+       void (*set_hw_params)(struct iwl_priv *priv);
+       int (*set_channel_switch)(struct iwl_priv *priv,
+                                 struct ieee80211_channel_switch *ch_switch);
+       /* device specific configuration */
+       void (*nic_config)(struct iwl_priv *priv);
+
+       /* temperature */
+       void (*temperature)(struct iwl_priv *priv);
+};
+
+struct iwl_wipan_noa_data {
+       struct rcu_head rcu_head;
+       u32 length;
+       u8 data[];
+};
+
+/* Calibration disabling bit mask */
+enum {
+       IWL_CALIB_ENABLE_ALL                    = 0,
+
+       IWL_SENSITIVITY_CALIB_DISABLED          = BIT(0),
+       IWL_CHAIN_NOISE_CALIB_DISABLED          = BIT(1),
+       IWL_TX_POWER_CALIB_DISABLED             = BIT(2),
+
+       IWL_CALIB_DISABLE_ALL                   = 0xFFFFFFFF,
+};
+
+#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
+       ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
+
+#define IWL_MAC80211_GET_DVM(_hw) \
+       ((struct iwl_priv *) ((struct iwl_op_mode *) \
+       (_hw)->priv)->op_mode_specific)
+
+struct iwl_priv {
+
+       struct iwl_trans *trans;
+       struct device *dev;             /* for debug prints only */
+       const struct iwl_cfg *cfg;
+       const struct iwl_fw *fw;
+       const struct iwl_lib_ops *lib;
+       unsigned long status;
+
+       spinlock_t sta_lock;
+       struct mutex mutex;
+
+       unsigned long transport_queue_stop;
+       bool passive_no_rx;
+#define IWL_INVALID_MAC80211_QUEUE     0xff
+       u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
+       atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+
+       unsigned long agg_q_alloc[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+
+       /* ieee device used by generic ieee processing code */
+       struct ieee80211_hw *hw;
+
+       struct list_head calib_results;
+
+       struct workqueue_struct *workqueue;
+
+       struct iwl_hw_params hw_params;
+
+       enum ieee80211_band band;
+       u8 valid_contexts;
+
+       int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+                                      struct iwl_rx_cmd_buffer *rxb,
+                                      struct iwl_device_cmd *cmd);
+
+       struct iwl_notif_wait_data notif_wait;
+
+       /* spectrum measurement report caching */
+       struct iwl_spectrum_notification measure_report;
+       u8 measurement_status;
+
+#define IWL_OWNERSHIP_DRIVER   0
+#define IWL_OWNERSHIP_TM       1
+       u8 ucode_owner;
+
+       /* ucode beacon time */
+       u32 ucode_beacon_time;
+       int missed_beacon_threshold;
+
+       /* track IBSS manager (last beacon) status */
+       u32 ibss_manager;
+
+       /* jiffies when last recovery from statistics was performed */
+       unsigned long rx_statistics_jiffies;
+
+       /*counters */
+       u32 rx_handlers_stats[REPLY_MAX];
+
+       /* rf reset */
+       struct iwl_rf_reset rf_reset;
+
+       /* firmware reload counter and timestamp */
+       unsigned long reload_jiffies;
+       int reload_count;
+       bool ucode_loaded;
+       bool init_ucode_run;            /* Don't run init uCode again */
+
+       u8 plcp_delta_threshold;
+
+       /* thermal calibration */
+       s32 temperature;        /* Celsius */
+       s32 last_temperature;
+
+       struct iwl_wipan_noa_data __rcu *noa_data;
+
+       /* Scan related variables */
+       unsigned long scan_start;
+       unsigned long scan_start_tsf;
+       void *scan_cmd;
+       enum ieee80211_band scan_band;
+       struct cfg80211_scan_request *scan_request;
+       struct ieee80211_vif *scan_vif;
+       enum iwl_scan_type scan_type;
+       u8 scan_tx_ant[IEEE80211_NUM_BANDS];
+       u8 mgmt_tx_ant;
+
+       /* max number of station keys */
+       u8 sta_key_max_num;
+
+       bool new_scan_threshold_behaviour;
+
+       bool wowlan;
+
+       /* EEPROM MAC addresses */
+       struct mac_address addresses[2];
+
+       struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
+
+       __le16 switch_channel;
+
+       u8 start_calib;
+       struct iwl_sensitivity_data sensitivity_data;
+       struct iwl_chain_noise_data chain_noise_data;
+       __le16 sensitivity_tbl[HD_TABLE_SIZE];
+       __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
+
+       struct iwl_ht_config current_ht_config;
+
+       /* Rate scaling data */
+       u8 retry_rate;
+
+       int activity_timer_active;
+
+       struct iwl_power_mgr power_data;
+       struct iwl_tt_mgmt thermal_throttle;
+
+       /* station table variables */
+       int num_stations;
+       struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
+       unsigned long ucode_key_table;
+       struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
+       atomic_t num_aux_in_flight;
+
+       u8 mac80211_registered;
+
+       /* Indication if ieee80211_ops->open has been called */
+       u8 is_open;
+
+       enum nl80211_iftype iw_mode;
+
+       /* Last Rx'd beacon timestamp */
+       u64 timestamp;
+
+       struct {
+               __le32 flag;
+               struct statistics_general_common common;
+               struct statistics_rx_non_phy rx_non_phy;
+               struct statistics_rx_phy rx_ofdm;
+               struct statistics_rx_ht_phy rx_ofdm_ht;
+               struct statistics_rx_phy rx_cck;
+               struct statistics_tx tx;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               struct statistics_bt_activity bt_activity;
+               __le32 num_bt_kills, accum_num_bt_kills;
+#endif
+               spinlock_t lock;
+       } statistics;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       struct {
+               struct statistics_general_common common;
+               struct statistics_rx_non_phy rx_non_phy;
+               struct statistics_rx_phy rx_ofdm;
+               struct statistics_rx_ht_phy rx_ofdm_ht;
+               struct statistics_rx_phy rx_cck;
+               struct statistics_tx tx;
+               struct statistics_bt_activity bt_activity;
+       } accum_stats, delta_stats, max_delta_stats;
+#endif
+
+       /*
+        * reporting the number of tids has AGG on. 0 means
+        * no AGGREGATION
+        */
+       u8 agg_tids_count;
+
+       struct iwl_rx_phy_res last_phy_res;
+       bool last_phy_res_valid;
+
+       /*
+        * chain noise reset and gain commands are the
+        * two extra calibration commands follows the standard
+        * phy calibration commands
+        */
+       u8 phy_calib_chain_noise_reset_cmd;
+       u8 phy_calib_chain_noise_gain_cmd;
+
+       /* counts reply_tx error */
+       struct reply_tx_error_statistics reply_tx_stats;
+       struct reply_agg_tx_error_statistics reply_agg_tx_stats;
+
+       /* remain-on-channel offload support */
+       struct ieee80211_channel *hw_roc_channel;
+       struct delayed_work hw_roc_disable_work;
+       enum nl80211_channel_type hw_roc_chantype;
+       int hw_roc_duration;
+       bool hw_roc_setup, hw_roc_start_notified;
+
+       /* bt coex */
+       u8 bt_enable_flag;
+       u8 bt_status;
+       u8 bt_traffic_load, last_bt_traffic_load;
+       bool bt_ch_announce;
+       bool bt_full_concurrent;
+       bool bt_ant_couple_ok;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       __le16 bt_valid;
+       bool reduced_txpower;
+       u16 bt_on_thresh;
+       u16 bt_duration;
+       u16 dynamic_frag_thresh;
+       u8 bt_ci_compliance;
+       struct work_struct bt_traffic_change_work;
+       bool bt_enable_pspoll;
+       struct iwl_rxon_context *cur_rssi_ctx;
+       bool bt_is_sco;
+
+       struct work_struct restart;
+       struct work_struct scan_completed;
+       struct work_struct abort_scan;
+
+       struct work_struct beacon_update;
+       struct iwl_rxon_context *beacon_ctx;
+       struct sk_buff *beacon_skb;
+       void *beacon_cmd;
+
+       struct work_struct tt_work;
+       struct work_struct ct_enter;
+       struct work_struct ct_exit;
+       struct work_struct start_internal_scan;
+       struct work_struct tx_flush;
+       struct work_struct bt_full_concurrency;
+       struct work_struct bt_runtime_config;
+
+       struct delayed_work scan_check;
+
+       /* TX Power settings */
+       s8 tx_power_user_lmt;
+       s8 tx_power_next;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       /* debugfs */
+       struct dentry *debugfs_dir;
+       u32 dbgfs_sram_offset, dbgfs_sram_len;
+       bool disable_ht40;
+       void *wowlan_sram;
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+
+       struct iwl_eeprom_data *eeprom_data;
+       /* eeprom blob for debugfs/testmode */
+       u8 *eeprom_blob;
+       size_t eeprom_blob_size;
+
+       struct work_struct txpower_work;
+       u32 calib_disabled;
+       struct work_struct run_time_calib_work;
+       struct timer_list statistics_periodic;
+       struct timer_list ucode_trace;
+
+       struct iwl_event_log event_log;
+
+       struct led_classdev led;
+       unsigned long blink_on, blink_off;
+       bool led_registered;
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+       struct iwl_test tst;
+       u32 tm_fixed_rate;
+#endif
+
+       /* WoWLAN GTK rekey data */
+       u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
+       __le64 replay_ctr;
+       __le16 last_seq_ctl;
+       bool have_rekey_data;
+
+       /* device_pointers: pointers to ucode event tables */
+       struct {
+               u32 error_event_table;
+               u32 log_event_table;
+       } device_pointers;
+
+       /* indicator of loaded ucode image */
+       enum iwl_ucode_type cur_ucode;
+}; /*iwl_priv */
+
+static inline struct iwl_rxon_context *
+iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       return vif_priv->ctx;
+}
+
+#define for_each_context(priv, ctx)                            \
+       for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];           \
+            ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)    \
+               if (priv->valid_contexts & BIT(ctx->ctxid))
+
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
+{
+       return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int iwl_is_associated(struct iwl_priv *priv,
+                                   enum iwl_rxon_context_id ctxid)
+{
+       return iwl_is_associated_ctx(&priv->contexts[ctxid]);
+}
+
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       for_each_context(priv, ctx)
+               if (iwl_is_associated_ctx(ctx))
+                       return true;
+       return false;
+}
+
+#endif                         /* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
new file mode 100644 (file)
index 0000000..349c205
--- /dev/null
@@ -0,0 +1,588 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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
+ *
+ *****************************************************************************/
+
+/*
+ * DVM device-specific data & functions
+ */
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-eeprom-parse.h"
+
+#include "agn.h"
+#include "dev.h"
+#include "commands.h"
+
+
+/*
+ * 1000 series
+ * ===========
+ */
+
+/*
+ * For 1000, use advance thermal throttling critical temperature threshold,
+ * but legacy thermal management implementation for now.
+ * This is for the reason of 1000 uCode using advance thermal throttling API
+ * but not implement ct_kill_exit based on ct_kill exit temperature
+ * so the thermal throttling will still based on legacy thermal throttling
+ * management.
+ * The code here need to be modified once 1000 uCode has the advanced thermal
+ * throttling algorithm in place
+ */
+static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
+{
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 1000 series */
+static void iwl1000_nic_config(struct iwl_priv *priv)
+{
+       /* Setting digital SVR for 1000 card to 1.32V */
+       /* locking is acquired in iwl_set_bits_mask_prph() function */
+       iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
+                               APMG_SVR_DIGITAL_VOLTAGE_1_32,
+                               ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+}
+
+/**
+ * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
+                                          u16 tsf_bits)
+{
+       return (1 << tsf_bits) - 1;
+}
+
+/**
+ * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
+                                           u16 tsf_bits)
+{
+       return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
+}
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in extended:internal format
+ * the extended part is the beacon counts
+ * the internal part is the time in usec within one beacon interval
+ */
+static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec,
+                               u32 beacon_interval)
+{
+       u32 quot;
+       u32 rem;
+       u32 interval = beacon_interval * TIME_UNIT;
+
+       if (!interval || !usec)
+               return 0;
+
+       quot = (usec / interval) &
+               (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
+               IWLAGN_EXT_BEACON_TIME_POS);
+       rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
+                                  IWLAGN_EXT_BEACON_TIME_POS);
+
+       return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+                          u32 addon, u32 beacon_interval)
+{
+       u32 base_low = base & iwl_beacon_time_mask_low(priv,
+                               IWLAGN_EXT_BEACON_TIME_POS);
+       u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
+                               IWLAGN_EXT_BEACON_TIME_POS);
+       u32 interval = beacon_interval * TIME_UNIT;
+       u32 res = (base & iwl_beacon_time_mask_high(priv,
+                               IWLAGN_EXT_BEACON_TIME_POS)) +
+                               (addon & iwl_beacon_time_mask_high(priv,
+                               IWLAGN_EXT_BEACON_TIME_POS));
+
+       if (base_low > addon_low)
+               res += base_low - addon_low;
+       else if (base_low < addon_low) {
+               res += interval + base_low - addon_low;
+               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
+       } else
+               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
+
+       return cpu_to_le32(res);
+}
+
+static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
+       .min_nrg_cck = 95,
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 120,
+       .auto_corr_min_ofdm_mrc_x1 = 240,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       .auto_corr_max_ofdm_x1 = 155,
+       .auto_corr_max_ofdm_mrc_x1 = 290,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .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 void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
+{
+       iwl1000_set_ct_threshold(priv);
+
+       /* Set initial sensitivity parameters */
+       priv->hw_params.sens = &iwl1000_sensitivity;
+}
+
+struct iwl_lib_ops iwl1000_lib = {
+       .set_hw_params = iwl1000_hw_set_hw_params,
+       .nic_config = iwl1000_nic_config,
+       .temperature = iwlagn_temperature,
+};
+
+
+/*
+ * 2000 series
+ * ===========
+ */
+
+static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
+{
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 2000 series */
+static void iwl2000_nic_config(struct iwl_priv *priv)
+{
+       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+                   CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
+}
+
+static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
+       .min_nrg_cck = 97,
+       .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 = 110,
+       .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 void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
+{
+       iwl2000_set_ct_threshold(priv);
+
+       /* Set initial sensitivity parameters */
+       priv->hw_params.sens = &iwl2000_sensitivity;
+}
+
+struct iwl_lib_ops iwl2000_lib = {
+       .set_hw_params = iwl2000_hw_set_hw_params,
+       .nic_config = iwl2000_nic_config,
+       .temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl2030_lib = {
+       .set_hw_params = iwl2000_hw_set_hw_params,
+       .nic_config = iwl2000_nic_config,
+       .temperature = iwlagn_temperature,
+};
+
+/*
+ * 5000 series
+ * ===========
+ */
+
+/* NIC configuration for 5000 series */
+static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
+       .min_nrg_cck = 100,
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 105,
+       .auto_corr_min_ofdm_mrc_x1 = 220,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       .auto_corr_max_ofdm_x1 = 120,
+       .auto_corr_max_ofdm_mrc_x1 = 240,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 200,
+       .auto_corr_max_cck_mrc = 400,
+       .nrg_th_cck = 100,
+       .nrg_th_ofdm = 100,
+
+       .barker_corr_th_min = 190,
+       .barker_corr_th_min_mrc = 390,
+       .nrg_th_cca = 62,
+};
+
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+       .min_nrg_cck = 95,
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 105,
+       .auto_corr_min_ofdm_mrc_x1 = 220,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       /* max = min for performance bug in 5150 DSP */
+       .auto_corr_max_ofdm_x1 = 105,
+       .auto_corr_max_ofdm_mrc_x1 = 220,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .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,
+};
+
+#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF  (-5)
+
+static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
+{
+       u16 temperature, voltage;
+
+       temperature = le16_to_cpu(priv->eeprom_data->kelvin_temperature);
+       voltage = le16_to_cpu(priv->eeprom_data->kelvin_voltage);
+
+       /* offset = temp - volt / coeff */
+       return (s32)(temperature -
+                       voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
+}
+
+static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
+{
+       const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
+       s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
+                       iwl_temp_calib_to_offset(priv);
+
+       priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
+}
+
+static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
+{
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
+}
+
+static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+{
+       iwl5000_set_ct_threshold(priv);
+
+       /* Set initial sensitivity parameters */
+       priv->hw_params.sens = &iwl5000_sensitivity;
+}
+
+static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
+{
+       iwl5150_set_ct_threshold(priv);
+
+       /* Set initial sensitivity parameters */
+       priv->hw_params.sens = &iwl5150_sensitivity;
+}
+
+static void iwl5150_temperature(struct iwl_priv *priv)
+{
+       u32 vt = 0;
+       s32 offset =  iwl_temp_calib_to_offset(priv);
+
+       vt = le32_to_cpu(priv->statistics.common.temperature);
+       vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
+       /* now vt hold the temperature in Kelvin */
+       priv->temperature = KELVIN_TO_CELSIUS(vt);
+       iwl_tt_handler(priv);
+}
+
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
+                                    struct ieee80211_channel_switch *ch_switch)
+{
+       /*
+        * MULTI-FIXME
+        * See iwlagn_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl5000_channel_switch_cmd cmd;
+       u32 switch_time_in_usec, ucode_switch_time;
+       u16 ch;
+       u32 tsf_low;
+       u8 switch_count;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_CHANNEL_SWITCH,
+               .len = { sizeof(cmd), },
+               .flags = CMD_SYNC,
+               .data = { &cmd, },
+       };
+
+       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+       ch = ch_switch->channel->hw_value;
+       IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+                     ctx->active.channel, ch);
+       cmd.channel = cpu_to_le16(ch);
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
+       switch_count = ch_switch->count;
+       tsf_low = ch_switch->timestamp & 0x0ffffffff;
+       /*
+        * calculate the ucode channel switch time
+        * adding TSF as one of the factor for when to switch
+        */
+       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+                   beacon_interval)) {
+                       switch_count -= (priv->ucode_beacon_time -
+                               tsf_low) / beacon_interval;
+               } else
+                       switch_count = 0;
+       }
+       if (switch_count <= 1)
+               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+       else {
+               switch_time_in_usec =
+                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+               ucode_switch_time = iwl_usecs_to_beacons(priv,
+                                                        switch_time_in_usec,
+                                                        beacon_interval);
+               cmd.switch_time = iwl_add_beacon_time(priv,
+                                                     priv->ucode_beacon_time,
+                                                     ucode_switch_time,
+                                                     beacon_interval);
+       }
+       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+                     cmd.switch_time);
+       cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+
+       return iwl_dvm_send_cmd(priv, &hcmd);
+}
+
+struct iwl_lib_ops iwl5000_lib = {
+       .set_hw_params = iwl5000_hw_set_hw_params,
+       .set_channel_switch = iwl5000_hw_channel_switch,
+       .temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl5150_lib = {
+       .set_hw_params = iwl5150_hw_set_hw_params,
+       .set_channel_switch = iwl5000_hw_channel_switch,
+       .temperature = iwl5150_temperature,
+};
+
+
+
+/*
+ * 6000 series
+ * ===========
+ */
+
+static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
+{
+       /* want Celsius */
+       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
+}
+
+/* NIC configuration for 6000 series */
+static void iwl6000_nic_config(struct iwl_priv *priv)
+{
+       switch (priv->cfg->device_family) {
+       case IWL_DEVICE_FAMILY_6005:
+       case IWL_DEVICE_FAMILY_6030:
+       case IWL_DEVICE_FAMILY_6000:
+               break;
+       case IWL_DEVICE_FAMILY_6000i:
+               /* 2x2 IPA phy type */
+               iwl_write32(priv->trans, CSR_GP_DRIVER_REG,
+                            CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
+               break;
+       case IWL_DEVICE_FAMILY_6050:
+               /* Indicate calibration version to uCode. */
+               if (priv->eeprom_data->calib_version >= 6)
+                       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+                                       CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+               break;
+       case IWL_DEVICE_FAMILY_6150:
+               /* Indicate calibration version to uCode. */
+               if (priv->eeprom_data->calib_version >= 6)
+                       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+                                       CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
+               iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
+                           CSR_GP_DRIVER_REG_BIT_6050_1x2);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
+       .min_nrg_cck = 110,
+       .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 = 110,
+       .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 = 110,
+       .nrg_th_ofdm = 110,
+
+       .barker_corr_th_min = 190,
+       .barker_corr_th_min_mrc = 336,
+       .nrg_th_cca = 62,
+};
+
+static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
+{
+       iwl6000_set_ct_threshold(priv);
+
+       /* Set initial sensitivity parameters */
+       priv->hw_params.sens = &iwl6000_sensitivity;
+
+}
+
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
+                                    struct ieee80211_channel_switch *ch_switch)
+{
+       /*
+        * MULTI-FIXME
+        * See iwlagn_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl6000_channel_switch_cmd cmd;
+       u32 switch_time_in_usec, ucode_switch_time;
+       u16 ch;
+       u32 tsf_low;
+       u8 switch_count;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_CHANNEL_SWITCH,
+               .len = { sizeof(cmd), },
+               .flags = CMD_SYNC,
+               .data = { &cmd, },
+       };
+
+       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+       ch = ch_switch->channel->hw_value;
+       IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
+                     ctx->active.channel, ch);
+       cmd.channel = cpu_to_le16(ch);
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
+       switch_count = ch_switch->count;
+       tsf_low = ch_switch->timestamp & 0x0ffffffff;
+       /*
+        * calculate the ucode channel switch time
+        * adding TSF as one of the factor for when to switch
+        */
+       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+                   beacon_interval)) {
+                       switch_count -= (priv->ucode_beacon_time -
+                               tsf_low) / beacon_interval;
+               } else
+                       switch_count = 0;
+       }
+       if (switch_count <= 1)
+               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+       else {
+               switch_time_in_usec =
+                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+               ucode_switch_time = iwl_usecs_to_beacons(priv,
+                                                        switch_time_in_usec,
+                                                        beacon_interval);
+               cmd.switch_time = iwl_add_beacon_time(priv,
+                                                     priv->ucode_beacon_time,
+                                                     ucode_switch_time,
+                                                     beacon_interval);
+       }
+       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+                     cmd.switch_time);
+       cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+
+       return iwl_dvm_send_cmd(priv, &hcmd);
+}
+
+struct iwl_lib_ops iwl6000_lib = {
+       .set_hw_params = iwl6000_hw_set_hw_params,
+       .set_channel_switch = iwl6000_hw_channel_switch,
+       .nic_config = iwl6000_nic_config,
+       .temperature = iwlagn_temperature,
+};
+
+struct iwl_lib_ops iwl6030_lib = {
+       .set_hw_params = iwl6000_hw_set_hw_params,
+       .set_channel_switch = iwl6000_hw_channel_switch,
+       .nic_config = iwl6000_nic_config,
+       .temperature = iwlagn_temperature,
+};
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c
new file mode 100644 (file)
index 0000000..bf479f7
--- /dev/null
@@ -0,0 +1,224 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+
+/* Throughput          OFF time(ms)    ON time (ms)
+ *     >300                    25              25
+ *     >200 to 300             40              40
+ *     >100 to 200             55              55
+ *     >70 to 100              65              65
+ *     >50 to 70               75              75
+ *     >20 to 50               85              85
+ *     >10 to 20               95              95
+ *     >5 to 10                110             110
+ *     >1 to 5                 130             130
+ *     >0 to 1                 167             167
+ *     <=0                                     SOLID ON
+ */
+static const struct ieee80211_tpt_blink iwl_blink[] = {
+       { .throughput = 0, .blink_time = 334 },
+       { .throughput = 1 * 1024 - 1, .blink_time = 260 },
+       { .throughput = 5 * 1024 - 1, .blink_time = 220 },
+       { .throughput = 10 * 1024 - 1, .blink_time = 190 },
+       { .throughput = 20 * 1024 - 1, .blink_time = 170 },
+       { .throughput = 50 * 1024 - 1, .blink_time = 150 },
+       { .throughput = 70 * 1024 - 1, .blink_time = 130 },
+       { .throughput = 100 * 1024 - 1, .blink_time = 110 },
+       { .throughput = 200 * 1024 - 1, .blink_time = 80 },
+       { .throughput = 300 * 1024 - 1, .blink_time = 50 },
+};
+
+/* Set led register off */
+void iwlagn_led_enable(struct iwl_priv *priv)
+{
+       iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+}
+
+/*
+ * Adjust led blink rate to compensate on a MAC Clock difference on every HW
+ * Led blink rate analysis showed an average deviation of 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)
+{
+       if (!compensation) {
+               IWL_ERR(priv, "undefined blink compensation: "
+                       "use pre-defined blinking time\n");
+               return time;
+       }
+
+       return (u8)((time * compensation) >> 6);
+}
+
+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,
+       };
+       u32 reg;
+
+       reg = iwl_read32(priv->trans, CSR_LED_REG);
+       if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+               iwl_write32(priv->trans, CSR_LED_REG,
+                           reg & CSR_LED_BSM_CTRL_MSK);
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+/* Set led pattern command */
+static int iwl_led_cmd(struct iwl_priv *priv,
+                      unsigned long on,
+                      unsigned long off)
+{
+       struct iwl_led_cmd led_cmd = {
+               .id = IWL_LED_LINK,
+               .interval = IWL_DEF_LED_INTRVL
+       };
+       int ret;
+
+       if (!test_bit(STATUS_READY, &priv->status))
+               return -EBUSY;
+
+       if (priv->blink_on == on && priv->blink_off == off)
+               return 0;
+
+       if (off == 0) {
+               /* led is SOLID_ON */
+               on = IWL_LED_SOLID;
+       }
+
+       IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
+                       priv->cfg->base_params->led_compensation);
+       led_cmd.on = iwl_blink_compensation(priv, on,
+                               priv->cfg->base_params->led_compensation);
+       led_cmd.off = iwl_blink_compensation(priv, off,
+                               priv->cfg->base_params->led_compensation);
+
+       ret = iwl_send_led_cmd(priv, &led_cmd);
+       if (!ret) {
+               priv->blink_on = on;
+               priv->blink_off = off;
+       }
+       return ret;
+}
+
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
+                                  enum led_brightness brightness)
+{
+       struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
+       unsigned long on = 0;
+
+       if (brightness > 0)
+               on = IWL_LED_SOLID;
+
+       iwl_led_cmd(priv, on, 0);
+}
+
+static int iwl_led_blink_set(struct led_classdev *led_cdev,
+                            unsigned long *delay_on,
+                            unsigned long *delay_off)
+{
+       struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
+
+       return iwl_led_cmd(priv, *delay_on, *delay_off);
+}
+
+void iwl_leds_init(struct iwl_priv *priv)
+{
+       int mode = iwlwifi_mod_params.led_mode;
+       int ret;
+
+       if (mode == IWL_LED_DISABLE) {
+               IWL_INFO(priv, "Led disabled\n");
+               return;
+       }
+       if (mode == IWL_LED_DEFAULT)
+               mode = priv->cfg->led_mode;
+
+       priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
+                                  wiphy_name(priv->hw->wiphy));
+       priv->led.brightness_set = iwl_led_brightness_set;
+       priv->led.blink_set = iwl_led_blink_set;
+       priv->led.max_brightness = 1;
+
+       switch (mode) {
+       case IWL_LED_DEFAULT:
+               WARN_ON(1);
+               break;
+       case IWL_LED_BLINK:
+               priv->led.default_trigger =
+                       ieee80211_create_tpt_led_trigger(priv->hw,
+                                       IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
+                                       iwl_blink, ARRAY_SIZE(iwl_blink));
+               break;
+       case IWL_LED_RF_STATE:
+               priv->led.default_trigger =
+                       ieee80211_get_radio_led_name(priv->hw);
+               break;
+       }
+
+       ret = led_classdev_register(priv->trans->dev, &priv->led);
+       if (ret) {
+               kfree(priv->led.name);
+               return;
+       }
+
+       priv->led_registered = true;
+}
+
+void iwl_leds_exit(struct iwl_priv *priv)
+{
+       if (!priv->led_registered)
+               return;
+
+       led_classdev_unregister(&priv->led);
+       kfree(priv->led.name);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h
new file mode 100644 (file)
index 0000000..b02a853
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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_leds_h__
+#define __iwl_leds_h__
+
+
+struct iwl_priv;
+
+#define IWL_LED_SOLID 11
+#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
+
+#define IWL_LED_ACTIVITY       (0<<1)
+#define IWL_LED_LINK           (1<<1)
+
+void iwlagn_led_enable(struct iwl_priv *priv);
+void iwl_leds_init(struct iwl_priv *priv);
+void iwl_leds_exit(struct iwl_priv *priv);
+
+#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
new file mode 100644 (file)
index 0000000..207ae91
--- /dev/null
@@ -0,0 +1,1291 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+
+#include "iwl-io.h"
+#include "iwl-agn-hw.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+
+#include "dev.h"
+#include "agn.h"
+
+int iwlagn_hw_valid_rtc_data_addr(u32 addr)
+{
+       return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
+               (addr < IWLAGN_RTC_DATA_UPPER_BOUND);
+}
+
+int iwlagn_send_tx_power(struct iwl_priv *priv)
+{
+       struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
+       u8 tx_ant_cfg_cmd;
+
+       if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
+                     "TX Power requested while scanning!\n"))
+               return -EAGAIN;
+
+       /* half dBm need to multiply */
+       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+       if (tx_power_cmd.global_lmt > priv->eeprom_data->max_tx_pwr_half_dbm) {
+               /*
+                * For the newer devices which using enhanced/extend tx power
+                * table in EEPROM, the format is in half dBm. driver need to
+                * convert to dBm format before report to mac80211.
+                * By doing so, there is a possibility of 1/2 dBm resolution
+                * lost. driver will perform "round-up" operation before
+                * reporting, but it will cause 1/2 dBm tx power over the
+                * regulatory limit. Perform the checking here, if the
+                * "tx_power_user_lmt" is higher than EEPROM value (in
+                * half-dBm format), lower the tx power based on EEPROM
+                */
+               tx_power_cmd.global_lmt =
+                       priv->eeprom_data->max_tx_pwr_half_dbm;
+       }
+       tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
+       tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
+
+       if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
+       else
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
+
+       return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
+                       sizeof(tx_power_cmd), &tx_power_cmd);
+}
+
+void iwlagn_temperature(struct iwl_priv *priv)
+{
+       lockdep_assert_held(&priv->statistics.lock);
+
+       /* store temperature from correct statistics (in Celsius) */
+       priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
+       iwl_tt_handler(priv);
+}
+
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+       int idx = 0;
+       int band_offset = 0;
+
+       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               idx = (rate_n_flags & 0xff);
+               return idx;
+       /* Legacy rate format, search for match in table */
+       } else {
+               if (band == IEEE80211_BAND_5GHZ)
+                       band_offset = IWL_FIRST_OFDM_RATE;
+               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+                               return idx - band_offset;
+       }
+
+       return -1;
+}
+
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       if (add)
+               return iwlagn_add_bssid_station(priv, vif_priv->ctx,
+                                               vif->bss_conf.bssid,
+                                               &vif_priv->ibss_bssid_sta_id);
+       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+                                 vif->bss_conf.bssid);
+}
+
+/**
+ * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
+ *
+ * pre-requirements:
+ *  1. acquire mutex before calling
+ *  2. make sure rf is on and not in exit state
+ */
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+       struct iwl_txfifo_flush_cmd flush_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_TXFIFO_FLUSH,
+               .len = { sizeof(struct iwl_txfifo_flush_cmd), },
+               .flags = CMD_SYNC,
+               .data = { &flush_cmd, },
+       };
+
+       might_sleep();
+
+       memset(&flush_cmd, 0, sizeof(flush_cmd));
+       if (flush_control & BIT(IWL_RXON_CTX_BSS))
+               flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
+                                IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
+                                IWL_SCD_MGMT_MSK;
+       if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
+           (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
+               flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
+                               IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
+                               IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
+                               IWL_PAN_SCD_MULTICAST_MSK;
+
+       if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE)
+               flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
+
+       IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
+                      flush_cmd.fifo_control);
+       flush_cmd.flush_control = cpu_to_le16(flush_control);
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+       mutex_lock(&priv->mutex);
+       ieee80211_stop_queues(priv->hw);
+       if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+               IWL_ERR(priv, "flush request fail\n");
+               goto done;
+       }
+       IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
+       iwl_trans_wait_tx_queue_empty(priv->trans);
+done:
+       ieee80211_wake_queues(priv->hw);
+       mutex_unlock(&priv->mutex);
+}
+
+/*
+ * BT coex
+ */
+/* Notmal TDM */
+static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xc0004000),
+       cpu_to_le32(0x00004000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0005000),
+};
+
+
+/* Loose Coex */
+static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0005000),
+};
+
+/* Full concurrency */
+static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+};
+
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
+{
+       struct iwl_basic_bt_cmd basic = {
+               .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
+               .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
+               .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
+               .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
+       };
+       struct iwl_bt_cmd_v1 bt_cmd_v1;
+       struct iwl_bt_cmd_v2 bt_cmd_v2;
+       int ret;
+
+       BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
+                       sizeof(basic.bt3_lookup_table));
+
+       if (priv->cfg->bt_params) {
+               /*
+                * newer generation of devices (2000 series and newer)
+                * use the version 2 of the bt command
+                * we need to make sure sending the host command
+                * with correct data structure to avoid uCode assert
+                */
+               if (priv->cfg->bt_params->bt_session_2) {
+                       bt_cmd_v2.prio_boost = cpu_to_le32(
+                               priv->cfg->bt_params->bt_prio_boost);
+                       bt_cmd_v2.tx_prio_boost = 0;
+                       bt_cmd_v2.rx_prio_boost = 0;
+               } else {
+                       bt_cmd_v1.prio_boost =
+                               priv->cfg->bt_params->bt_prio_boost;
+                       bt_cmd_v1.tx_prio_boost = 0;
+                       bt_cmd_v1.rx_prio_boost = 0;
+               }
+       } else {
+               IWL_ERR(priv, "failed to construct BT Coex Config\n");
+               return;
+       }
+
+       /*
+        * Possible situations when BT needs to take over for receive,
+        * at the same time where STA needs to response to AP's frame(s),
+        * reduce the tx power of the required response frames, by that,
+        * allow the concurrent BT receive & WiFi transmit
+        * (BT - ANT A, WiFi -ANT B), without interference to one another
+        *
+        * Reduced tx power apply to control frames only (ACK/Back/CTS)
+        * when indicated by the BT config command
+        */
+       basic.kill_ack_mask = priv->kill_ack_mask;
+       basic.kill_cts_mask = priv->kill_cts_mask;
+       if (priv->reduced_txpower)
+               basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
+       basic.valid = priv->bt_valid;
+
+       /*
+        * Configure BT coex mode to "no coexistence" when the
+        * user disabled BT coexistence, we have no interface
+        * (might be in monitor mode), or the interface is in
+        * IBSS mode (no proper uCode support for coex then).
+        */
+       if (!iwlwifi_mod_params.bt_coex_active ||
+           priv->iw_mode == NL80211_IFTYPE_ADHOC) {
+               basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
+       } else {
+               basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
+                                       IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+
+               if (!priv->bt_enable_pspoll)
+                       basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+               else
+                       basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+
+               if (priv->bt_ch_announce)
+                       basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
+               IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
+       }
+       priv->bt_enable_flag = basic.flags;
+       if (priv->bt_full_concurrent)
+               memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
+                       sizeof(iwlagn_concurrent_lookup));
+       else
+               memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
+                       sizeof(iwlagn_def_3w_lookup));
+
+       IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
+                      basic.flags ? "active" : "disabled",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       if (priv->cfg->bt_params->bt_session_2) {
+               memcpy(&bt_cmd_v2.basic, &basic,
+                       sizeof(basic));
+               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                       CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2);
+       } else {
+               memcpy(&bt_cmd_v1.basic, &basic,
+                       sizeof(basic));
+               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                       CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1);
+       }
+       if (ret)
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
+
+}
+
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
+{
+       struct iwl_rxon_context *ctx, *found_ctx = NULL;
+       bool found_ap = false;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /* Check whether AP or GO mode is active. */
+       if (rssi_ena) {
+               for_each_context(priv, ctx) {
+                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
+                           iwl_is_associated_ctx(ctx)) {
+                               found_ap = true;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If disable was received or If GO/AP mode, disable RSSI
+        * measurements.
+        */
+       if (!rssi_ena || found_ap) {
+               if (priv->cur_rssi_ctx) {
+                       ctx = priv->cur_rssi_ctx;
+                       ieee80211_disable_rssi_reports(ctx->vif);
+                       priv->cur_rssi_ctx = NULL;
+               }
+               return;
+       }
+
+       /*
+        * If rssi measurements need to be enabled, consider all cases now.
+        * Figure out how many contexts are active.
+        */
+       for_each_context(priv, ctx) {
+               if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+                   iwl_is_associated_ctx(ctx)) {
+                       found_ctx = ctx;
+                       break;
+               }
+       }
+
+       /*
+        * rssi monitor already enabled for the correct interface...nothing
+        * to do.
+        */
+       if (found_ctx == priv->cur_rssi_ctx)
+               return;
+
+       /*
+        * Figure out if rssi monitor is currently enabled, and needs
+        * to be changed. If rssi monitor is already enabled, disable
+        * it first else just enable rssi measurements on the
+        * interface found above.
+        */
+       if (priv->cur_rssi_ctx) {
+               ctx = priv->cur_rssi_ctx;
+               if (ctx->vif)
+                       ieee80211_disable_rssi_reports(ctx->vif);
+       }
+
+       priv->cur_rssi_ctx = found_ctx;
+
+       if (!found_ctx)
+               return;
+
+       ieee80211_enable_rssi_reports(found_ctx->vif,
+                       IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
+                       IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
+}
+
+static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
+{
+       return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
+                       BT_UART_MSG_FRAME3SCOESCO_POS;
+}
+
+static void iwlagn_bt_traffic_change_work(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_traffic_change_work);
+       struct iwl_rxon_context *ctx;
+       int smps_request = -1;
+
+       if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
+               /* bt coex disabled */
+               return;
+       }
+
+       /*
+        * Note: bt_traffic_load can be overridden by scan complete and
+        * coex profile notifications. Ignore that since only bad consequence
+        * can be not matching debug print with actual state.
+        */
+       IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
+                      priv->bt_traffic_load);
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               if (priv->bt_status)
+                       smps_request = IEEE80211_SMPS_DYNAMIC;
+               else
+                       smps_request = IEEE80211_SMPS_AUTOMATIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               smps_request = IEEE80211_SMPS_DYNAMIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               smps_request = IEEE80211_SMPS_STATIC;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT traffic load: %d\n",
+                       priv->bt_traffic_load);
+               break;
+       }
+
+       mutex_lock(&priv->mutex);
+
+       /*
+        * We can not send command to firmware while scanning. When the scan
+        * complete we will schedule this work again. We do check with mutex
+        * locked to prevent new scan request to arrive. We do not check
+        * STATUS_SCANNING to avoid race when queue_work two times from
+        * different notifications, but quit and not perform any work at all.
+        */
+       if (test_bit(STATUS_SCAN_HW, &priv->status))
+               goto out;
+
+       iwl_update_chain_flags(priv);
+
+       if (smps_request != -1) {
+               priv->current_ht_config.smps = smps_request;
+               for_each_context(priv, ctx) {
+                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
+                               ieee80211_request_smps(ctx->vif, smps_request);
+               }
+       }
+
+       /*
+        * Dynamic PS poll related functionality. Adjust RSSI measurements if
+        * necessary.
+        */
+       iwlagn_bt_coex_rssi_monitor(priv);
+out:
+       mutex_unlock(&priv->mutex);
+}
+
+/*
+ * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
+ * correct interface or disable it if this is the last interface to be
+ * removed.
+ */
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
+{
+       if (priv->bt_is_sco &&
+           priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
+               iwlagn_bt_adjust_rssi_monitor(priv, true);
+       else
+               iwlagn_bt_adjust_rssi_monitor(priv, false);
+}
+
+static void iwlagn_print_uartmsg(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
+{
+       IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, "
+                       "Update Req = 0x%X\n",
+               (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1MSGTYPE_POS,
+               (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1SSN_POS,
+               (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1UPDATEREQ_POS);
+
+       IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
+                       "Chl_SeqN = 0x%X, In band = 0x%X\n",
+               (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
+               (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
+               (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2CHLSEQN_POS,
+               (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2INBAND_POS);
+
+       IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
+                       "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n",
+               (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SCOESCO_POS,
+               (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SNIFF_POS,
+               (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3A2DP_POS,
+               (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3ACL_POS,
+               (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3MASTER_POS,
+               (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3OBEX_POS);
+
+       IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n",
+               (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
+                       BT_UART_MSG_FRAME4IDLEDURATION_POS);
+
+       IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
+                       "eSCO Retransmissions = 0x%X\n",
+               (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5TXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5RXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
+
+       IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n",
+               (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
+               (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6DISCOVERABLE_POS);
+
+       IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = "
+                       "0x%X, Inquiry = 0x%X, Connectable = 0x%X\n",
+               (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
+               (BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7PAGE_POS,
+               (BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7INQUIRY_POS,
+               (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7CONNECTABLE_POS);
+}
+
+static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
+{
+       bool need_update = false;
+       u8 kill_msk = IWL_BT_KILL_REDUCE;
+       static const __le32 bt_kill_ack_msg[3] = {
+               IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
+       static const __le32 bt_kill_cts_msg[3] = {
+               IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
+
+       if (!priv->reduced_txpower)
+               kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
+                       ? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
+       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
+           priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
+               priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
+               priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
+               priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
+               priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
+               need_update = true;
+       }
+       return need_update;
+}
+
+/*
+ * Upon RSSI changes, sends a bt config command with following changes
+ *  1. enable/disable "reduced control frames tx power
+ *  2. update the "kill)ack_mask" and "kill_cts_mask"
+ *
+ * If "reduced tx power" is enabled, uCode shall
+ *  1. ACK/Back/CTS rate shall reduced to 6Mbps
+ *  2. not use duplciate 20/40MHz mode
+ */
+static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
+{
+       bool need_update = false;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       int ave_rssi;
+
+       if (!ctx->vif || (ctx->vif->type != NL80211_IFTYPE_STATION)) {
+               IWL_DEBUG_INFO(priv, "BSS ctx not active or not in sta mode\n");
+               return false;
+       }
+
+       ave_rssi = ieee80211_ave_rssi(ctx->vif);
+       if (!ave_rssi) {
+               /* no rssi data, no changes to reduce tx power */
+               IWL_DEBUG_COEX(priv, "no rssi data available\n");
+               return need_update;
+       }
+       if (!priv->reduced_txpower &&
+           !iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+           (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
+           (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
+           BT_UART_MSG_FRAME3OBEX_MSK)) &&
+           !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
+           BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
+               /* enabling reduced tx power */
+               priv->reduced_txpower = true;
+               priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
+               need_update = true;
+       } else if (priv->reduced_txpower &&
+                  (iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
+                  (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
+                  (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
+                  BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
+                  !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
+                  BT_UART_MSG_FRAME3OBEX_MSK)))) {
+               /* disable reduced tx power */
+               priv->reduced_txpower = false;
+               priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
+               need_update = true;
+       }
+
+       return need_update;
+}
+
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_cmd_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
+       struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
+
+       if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
+               /* bt coex disabled */
+               return 0;
+       }
+
+       IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
+       IWL_DEBUG_COEX(priv, "    status: %d\n", coex->bt_status);
+       IWL_DEBUG_COEX(priv, "    traffic load: %d\n", coex->bt_traffic_load);
+       IWL_DEBUG_COEX(priv, "    CI compliance: %d\n",
+                       coex->bt_ci_compliance);
+       iwlagn_print_uartmsg(priv, uart_msg);
+
+       priv->last_bt_traffic_load = priv->bt_traffic_load;
+       priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
+
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+               if (priv->bt_status != coex->bt_status ||
+                   priv->last_bt_traffic_load != coex->bt_traffic_load) {
+                       if (coex->bt_status) {
+                               /* BT on */
+                               if (!priv->bt_ch_announce)
+                                       priv->bt_traffic_load =
+                                               IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                               else
+                                       priv->bt_traffic_load =
+                                               coex->bt_traffic_load;
+                       } else {
+                               /* BT off */
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+                       }
+                       priv->bt_status = coex->bt_status;
+                       queue_work(priv->workqueue,
+                                  &priv->bt_traffic_change_work);
+               }
+       }
+
+       /* schedule to send runtime bt_config */
+       /* check reduce power before change ack/cts kill mask */
+       if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
+           iwlagn_set_kill_msk(priv, uart_msg))
+               queue_work(priv->workqueue, &priv->bt_runtime_config);
+
+
+       /* FIXME: based on notification, adjust the prio_boost */
+
+       priv->bt_ci_compliance = coex->bt_ci_compliance;
+       return 0;
+}
+
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
+{
+       priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
+               iwlagn_bt_coex_profile_notif;
+}
+
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
+{
+       INIT_WORK(&priv->bt_traffic_change_work,
+                 iwlagn_bt_traffic_change_work);
+}
+
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
+{
+       cancel_work_sync(&priv->bt_traffic_change_work);
+}
+
+static bool is_single_rx_stream(struct iwl_priv *priv)
+{
+       return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
+              priv->current_ht_config.single_chain_sufficient;
+}
+
+#define IWL_NUM_RX_CHAINS_MULTIPLE     3
+#define IWL_NUM_RX_CHAINS_SINGLE       2
+#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
+ * 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)
+{
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           (priv->bt_full_concurrent ||
+            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               return IWL_NUM_RX_CHAINS_SINGLE;
+       }
+       /* # of Rx chains to use when expecting MIMO. */
+       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 mode, unless device support spatial
+ * multiplexing power save, use the active count for rx chain count.
+ */
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+       /* # Rx chains when idling, depending on SMPS mode */
+       switch (priv->current_ht_config.smps) {
+       case IEEE80211_SMPS_STATIC:
+       case IEEE80211_SMPS_DYNAMIC:
+               return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_AUTOMATIC:
+       case IEEE80211_SMPS_OFF:
+               return active_cnt;
+       default:
+               WARN(1, "invalid SMPS mode %d",
+                    priv->current_ht_config.smps);
+               return active_cnt;
+       }
+}
+
+/* up to 4 chains */
+static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
+{
+       u8 res;
+       res = (chain_bitmap & BIT(0)) >> 0;
+       res += (chain_bitmap & BIT(1)) >> 1;
+       res += (chain_bitmap & BIT(2)) >> 2;
+       res += (chain_bitmap & BIT(3)) >> 3;
+       return res;
+}
+
+/**
+ * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       bool is_single = is_single_rx_stream(priv);
+       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+       u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
+       u32 active_chains;
+       u16 rx_chain;
+
+       /* Tell uCode which antennas are actually connected.
+        * Before first association, we assume all antennas are connected.
+        * Just after first association, iwl_chain_noise_calibration()
+        *    checks which antennas actually *are* connected. */
+       if (priv->chain_noise_data.active_chains)
+               active_chains = priv->chain_noise_data.active_chains;
+       else
+               active_chains = priv->eeprom_data->valid_rx_ant;
+
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           (priv->bt_full_concurrent ||
+            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               active_chains = first_antenna(active_chains);
+       }
+
+       rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
+
+       /* How many receivers should we use? */
+       active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+       idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+
+       /* correct rx chain count according hw settings
+        * and chain noise calibration
+        */
+       valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
+       if (valid_rx_cnt < active_rx_cnt)
+               active_rx_cnt = valid_rx_cnt;
+
+       if (valid_rx_cnt < idle_rx_cnt)
+               idle_rx_cnt = valid_rx_cnt;
+
+       rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+       rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
+
+       ctx->staging.rx_chain = cpu_to_le16(rx_chain);
+
+       if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
+               ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+       else
+               ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+       IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
+                       ctx->staging.rx_chain,
+                       active_rx_cnt, idle_rx_cnt);
+
+       WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+               active_rx_cnt < idle_rx_cnt);
+}
+
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
+{
+       int i;
+       u8 ind = ant;
+
+       if (priv->band == IEEE80211_BAND_2GHZ &&
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+               return 0;
+
+       for (i = 0; i < RATE_ANT_NUM - 1; i++) {
+               ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
+               if (valid & BIT(ind))
+                       return ind;
+       }
+       return ant;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
+{
+       int i;
+
+       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
+               out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+       struct iwl_rxon_context *ctx;
+       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+       struct iwlagn_wowlan_tkip_params_cmd *tkip;
+       const u8 *bssid;
+       bool error, use_rsc_tsc, use_tkip;
+};
+
+
+static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_key_conf *key,
+                              void *_data)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct wowlan_key_data *data = _data;
+       struct iwl_rxon_context *ctx = data->ctx;
+       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+       struct iwlagn_p1k_cache *rx_p1ks;
+       u8 *rx_mic_key;
+       struct ieee80211_key_seq seq;
+       u32 cur_rx_iv32 = 0;
+       u16 p1k[IWLAGN_P1K_SIZE];
+       int ret, i;
+
+       mutex_lock(&priv->mutex);
+
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+            !sta && !ctx->key_mapping_keys)
+               ret = iwl_set_default_wep_key(priv, ctx, key);
+       else
+               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+
+       if (ret) {
+               IWL_ERR(priv, "Error setting key during suspend!\n");
+               data->error = true;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (sta) {
+                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+                       rx_p1ks = data->tkip->rx_uni;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
+
+                       memcpy(data->tkip->mic_keys.tx,
+                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              IWLAGN_MIC_KEY_SIZE);
+
+                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
+               } else {
+                       tkip_sc =
+                               data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+                       rx_p1ks = data->tkip->rx_multi;
+                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
+               }
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 (as they need to to avoid replay attacks)
+                * for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+                       /* wrapping isn't allowed, AP must rekey */
+                       if (seq.tkip.iv32 > cur_rx_iv32)
+                               cur_rx_iv32 = seq.tkip.iv32;
+               }
+
+               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
+               ieee80211_get_tkip_rx_p1k(key, data->bssid,
+                                         cur_rx_iv32 + 1, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+               memcpy(rx_mic_key,
+                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                      IWLAGN_MIC_KEY_SIZE);
+
+               data->use_tkip = true;
+               data->use_rsc_tsc = true;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (sta) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       aes_tx_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               } else
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       aes_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               }
+               data->use_rsc_tsc = true;
+               break;
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                       struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_WOWLAN_PATTERNS,
+               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+               .flags = CMD_SYNC,
+       };
+       int i, err;
+
+       if (!wowlan->n_patterns)
+               return 0;
+
+       cmd.len[0] = sizeof(*pattern_cmd) +
+               wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+
+       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+       if (!pattern_cmd)
+               return -ENOMEM;
+
+       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+       for (i = 0; i < wowlan->n_patterns; i++) {
+               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+               memcpy(&pattern_cmd->patterns[i].mask,
+                       wowlan->patterns[i].mask, mask_len);
+               memcpy(&pattern_cmd->patterns[i].pattern,
+                       wowlan->patterns[i].pattern,
+                       wowlan->patterns[i].pattern_len);
+               pattern_cmd->patterns[i].mask_size = mask_len;
+               pattern_cmd->patterns[i].pattern_size =
+                       wowlan->patterns[i].pattern_len;
+       }
+
+       cmd.data[0] = pattern_cmd;
+       err = iwl_dvm_send_cmd(priv, &cmd);
+       kfree(pattern_cmd);
+       return err;
+}
+
+int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
+       struct iwl_rxon_cmd rxon;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
+       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+       struct wowlan_key_data key_data = {
+               .ctx = ctx,
+               .bssid = ctx->active.bssid_addr,
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret, i;
+       u16 seq;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
+
+       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
+
+       /*
+        * We know the last used seqno, and the uCode expects to know that
+        * one, it will increment before TX.
+        */
+       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
+       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
+
+       /*
+        * For QoS counters, we store the one to use next, so subtract 0x10
+        * since the uCode will add 0x10 before using the value.
+        */
+       for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+               seq = priv->tid_data[IWL_AP_ID][i].seq_number;
+               seq -= 0x10;
+               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
+       }
+
+       if (wowlan->disconnect)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
+       if (wowlan->magic_pkt)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
+       if (wowlan->gtk_rekey_failure)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+       if (wowlan->eap_identity_req)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+       if (wowlan->four_way_handshake)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+       if (wowlan->n_patterns)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+       if (wowlan->rfkill_release)
+               d3_cfg_cmd.wakeup_flags |=
+                       cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
+
+       iwl_scan_cancel_timeout(priv, 200);
+
+       memcpy(&rxon, &ctx->active, sizeof(rxon));
+
+       priv->ucode_loaded = false;
+       iwl_trans_stop_device(priv->trans);
+
+       priv->wowlan = true;
+
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+       if (ret)
+               goto out;
+
+       /* now configure WoWLAN ucode */
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto out;
+
+       memcpy(&ctx->staging, &rxon, sizeof(rxon));
+       ret = iwlagn_commit_rxon(priv, ctx);
+       if (ret)
+               goto out;
+
+       ret = iwl_power_update_mode(priv, true);
+       if (ret)
+               goto out;
+
+       if (!iwlwifi_mod_params.sw_crypto) {
+               /* mark all keys clear */
+               priv->ucode_key_table = 0;
+               ctx->key_mapping_keys = 0;
+
+               /*
+                * This needs to be unlocked due to lock ordering
+                * constraints. Since we're in the suspend path
+                * that isn't really a problem though.
+                */
+               mutex_unlock(&priv->mutex);
+               ieee80211_iter_keys(priv->hw, ctx->vif,
+                                   iwlagn_wowlan_program_keys,
+                                   &key_data);
+               mutex_lock(&priv->mutex);
+               if (key_data.error) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               if (key_data.use_rsc_tsc) {
+                       struct iwl_host_cmd rsc_tsc_cmd = {
+                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
+                               .flags = CMD_SYNC,
+                               .data[0] = key_data.rsc_tsc,
+                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+                               .len[0] = sizeof(*key_data.rsc_tsc),
+                       };
+
+                       ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (key_data.use_tkip) {
+                       ret = iwl_dvm_send_cmd_pdu(priv,
+                                                REPLY_WOWLAN_TKIP_PARAMS,
+                                                CMD_SYNC, sizeof(tkip_cmd),
+                                                &tkip_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (priv->have_rekey_data) {
+                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
+                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
+                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
+
+                       ret = iwl_dvm_send_cmd_pdu(priv,
+                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
+                                                CMD_SYNC, sizeof(kek_kck_cmd),
+                                                &kek_kck_cmd);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, CMD_SYNC,
+                                    sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
+                                CMD_SYNC, sizeof(wakeup_filter_cmd),
+                                &wakeup_filter_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwlagn_send_patterns(priv, wowlan);
+ out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+#endif
+
+int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+       if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+               IWL_WARN(priv, "Not sending command - %s KILL\n",
+                        iwl_is_rfkill(priv) ? "RF" : "CT");
+               return -EIO;
+       }
+
+       if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+               IWL_ERR(priv, "Command %s failed: FW Error\n",
+                       iwl_dvm_get_cmd_string(cmd->id));
+               return -EIO;
+       }
+
+       /*
+        * Synchronous commands from this op-mode must hold
+        * the mutex, this ensures we don't try to send two
+        * (or more) synchronous commands at a time.
+        */
+       if (!(cmd->flags & CMD_ASYNC))
+               lockdep_assert_held(&priv->mutex);
+
+       if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
+           !(cmd->flags & CMD_ON_DEMAND)) {
+               IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
+               return -EIO;
+       }
+
+       return iwl_trans_send_cmd(priv->trans, cmd);
+}
+
+int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+                        u32 flags, u16 len, const void *data)
+{
+       struct iwl_host_cmd cmd = {
+               .id = id,
+               .len = { len, },
+               .data = { data, },
+               .flags = flags,
+       };
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
new file mode 100644 (file)
index 0000000..a5f7bce
--- /dev/null
@@ -0,0 +1,1652 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-modparams.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_sta_ap_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_p2p_sta_go_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_p2p_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+       },
+};
+
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                             const struct iwl_ucode_capabilities *capa)
+{
+       int ret;
+       struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
+       hw->rate_control_algorithm = "iwl-agn-rs";
+
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+                   IEEE80211_HW_QUEUE_CONTROL |
+                   IEEE80211_HW_SUPPORTS_PS |
+                   IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+                   IEEE80211_HW_WANT_MONITOR_VIF |
+                   IEEE80211_HW_SCAN_WHILE_IDLE;
+
+       hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
+       hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
+
+       /*
+        * Including the following line will crash some AP's.  This
+        * workaround removes the stimulus which causes the crash until
+        * the AP software can be fixed.
+       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+        */
+
+       if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
+#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
+       /* enable 11w if the uCode advertise */
+       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
+               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+       hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->iface_combinations =
+                       iwlagn_iface_combinations_dualmode;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+       }
+
+       hw->wiphy->max_remain_on_channel_duration = 1000;
+
+       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
+                           WIPHY_FLAG_IBSS_RSN;
+
+#ifdef CONFIG_PM_SLEEP
+       if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+           priv->trans->ops->wowlan_suspend &&
+           device_can_wakeup(priv->trans->dev)) {
+               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                         WIPHY_WOWLAN_DISCONNECT |
+                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               if (!iwlwifi_mod_params.sw_crypto)
+                       hw->wiphy->wowlan.flags |=
+                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+
+               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+               hw->wiphy->wowlan.pattern_min_len =
+                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
+               hw->wiphy->wowlan.pattern_max_len =
+                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+       }
+#endif
+
+       if (iwlwifi_mod_params.power_save)
+               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       else
+               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+       /* we create the 802.11 header and a max-length SSID element */
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
+
+       /*
+        * We don't use all queues: 4 and 9 are unused and any
+        * aggregation queue gets mapped down to the AC queue.
+        */
+       hw->queues = IWLAGN_FIRST_AMPDU_QUEUE;
+
+       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+       if (priv->eeprom_data->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->eeprom_data->bands[IEEE80211_BAND_2GHZ];
+       if (priv->eeprom_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->eeprom_data->bands[IEEE80211_BAND_5GHZ];
+
+       hw->wiphy->hw_version = priv->trans->hw_id;
+
+       iwl_leds_init(priv);
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+               iwl_leds_exit(priv);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
+
+       return 0;
+}
+
+void iwlagn_mac_unregister(struct iwl_priv *priv)
+{
+       if (!priv->mac80211_registered)
+               return;
+       iwl_leds_exit(priv);
+       ieee80211_unregister_hw(priv->hw);
+       priv->mac80211_registered = 0;
+}
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
+               return -EIO;
+       }
+
+       for_each_context(priv, ctx) {
+               ret = iwlagn_alloc_bcast_station(priv, ctx);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
+
+       ret = iwl_run_init_ucode(priv);
+       if (ret) {
+               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+       if (ret) {
+               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto error;
+       return 0;
+
+ error:
+       set_bit(STATUS_EXIT_PENDING, &priv->status);
+       iwl_down(priv);
+       clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+       IWL_ERR(priv, "Unable to initialize device.\n");
+       return ret;
+}
+
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       /* we should be verifying the device is ready to be opened */
+       mutex_lock(&priv->mutex);
+       ret = __iwl_up(priv);
+       mutex_unlock(&priv->mutex);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
+
+       /* Now we should be done, and the READY bit should be set. */
+       if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
+               ret = -EIO;
+
+       iwlagn_led_enable(priv);
+
+       priv->is_open = 1;
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!priv->is_open)
+               return;
+
+       priv->is_open = 0;
+
+       mutex_lock(&priv->mutex);
+       iwl_down(priv);
+       mutex_unlock(&priv->mutex);
+
+       iwl_cancel_deferred_work(priv);
+
+       flush_workqueue(priv->workqueue);
+
+       /* User space software may expect getting rfkill changes
+        * even if interface is down, trans->down will leave the RF
+        * kill interrupt enabled
+        */
+       iwl_trans_stop_hw(priv->trans, false);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct cfg80211_gtk_rekey_data *data)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       if (iwlwifi_mod_params.sw_crypto)
+               return;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
+               goto out;
+
+       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
+       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
+       priv->replay_ctr =
+               cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+       priv->have_rekey_data = true;
+
+ out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
+                             struct cfg80211_wowlan *wowlan)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       int ret;
+
+       if (WARN_ON(!wowlan))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       /* Don't attempt WoWLAN when not associated, tear down instead. */
+       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
+           !iwl_is_associated_ctx(ctx)) {
+               ret = 1;
+               goto out;
+       }
+
+       ret = iwlagn_suspend(priv, wowlan);
+       if (ret)
+               goto error;
+
+       iwl_trans_wowlan_suspend(priv->trans);
+
+       goto out;
+
+ error:
+       priv->wowlan = false;
+       iwlagn_prepare_restart(priv);
+       ieee80211_restart_hw(priv->hw);
+ out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_resume(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct ieee80211_vif *vif;
+       unsigned long flags;
+       u32 base, status = 0xffffffff;
+       int ret = -EIO;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       base = priv->device_pointers.error_event_table;
+       if (iwlagn_hw_valid_rtc_data_addr(base)) {
+               spin_lock_irqsave(&priv->trans->reg_lock, flags);
+               ret = iwl_grab_nic_access_silent(priv->trans);
+               if (likely(ret == 0)) {
+                       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
+                       status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+                       iwl_release_nic_access(priv->trans);
+               }
+               spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               if (ret == 0) {
+                       const struct fw_img *img;
+
+                       img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
+                       if (!priv->wowlan_sram) {
+                               priv->wowlan_sram =
+                                  kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
+                                               GFP_KERNEL);
+                       }
+
+                       if (priv->wowlan_sram)
+                               _iwl_read_targ_mem_dwords(
+                                     priv->trans, 0x800000,
+                                     priv->wowlan_sram,
+                                     img->sec[IWL_UCODE_SECTION_DATA].len / 4);
+               }
+#endif
+       }
+
+       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+       vif = ctx->vif;
+
+       priv->wowlan = false;
+
+       iwlagn_prepare_restart(priv);
+
+       memset((void *)&ctx->active, 0, sizeof(ctx->active));
+       iwl_connection_init_rx_config(priv, ctx);
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       ieee80211_resume_disconnect(vif);
+
+       return 1;
+}
+
+static void iwlagn_mac_set_wakeup(struct ieee80211_hw *hw, bool enabled)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       device_set_wakeup_enable(priv->trans->dev, enabled);
+}
+#endif
+
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
+
+       if (iwlagn_tx_skb(priv, skb))
+               dev_kfree_skb_any(skb);
+}
+
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_key_conf *keyconf,
+                                      struct ieee80211_sta *sta,
+                                      u32 iv32, u16 *phase1key)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
+}
+
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta,
+                             struct ieee80211_key_conf *key)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       bool is_default_wep_key = false;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (iwlwifi_mod_params.sw_crypto) {
+               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_CCMP:
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * We could program these keys into the hardware as well, but we
+        * don't expect much multicast traffic in IBSS and having keys
+        * for more stations is probably more useful.
+        *
+        * Mark key TX-only and return 0.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               key->hw_key_idx = WEP_INVALID_OFFSET;
+               return 0;
+       }
+
+       /* If they key was TX-only, accept deletion */
+       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
+               return 0;
+
+       mutex_lock(&priv->mutex);
+       iwl_scan_cancel_timeout(priv, 100);
+
+       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
+
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
+        * so far, we are in legacy wep mode (group key only), otherwise we are
+        * in 1X mode.
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
+               if (cmd == SET_KEY)
+                       is_default_wep_key = !ctx->key_mapping_keys;
+               else
+                       is_default_wep_key =
+                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
+       }
+
+
+       switch (cmd) {
+       case SET_KEY:
+               if (is_default_wep_key) {
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
+                       break;
+               }
+               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
+               if (ret) {
+                       /*
+                        * can't add key for RX, but we don't need it
+                        * in the device for TX so still return 0
+                        */
+                       ret = 0;
+                       key->hw_key_idx = WEP_INVALID_OFFSET;
+               }
+
+               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
+               break;
+       case DISABLE_KEY:
+               if (is_default_wep_key)
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
+               else
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
+
+               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  enum ieee80211_ampdu_mlme_action action,
+                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                                  u8 buf_size)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       int ret = -EINVAL;
+       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+
+       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
+                    sta->addr, tid);
+
+       if (!(priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE))
+               return -EACCES;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
+                       break;
+               IWL_DEBUG_HT(priv, "start Rx\n");
+               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               IWL_DEBUG_HT(priv, "stop Rx\n");
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               if (!priv->trans->ops->txq_enable)
+                       break;
+               if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
+                       break;
+               IWL_DEBUG_HT(priv, "start Tx\n");
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               IWL_DEBUG_HT(priv, "stop Tx\n");
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+               if ((ret == 0) && (priv->agg_tids_count > 0)) {
+                       priv->agg_tids_count--;
+                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                                    priv->agg_tids_count);
+               }
+               if (!priv->agg_tids_count &&
+                   priv->hw_params.use_rts_for_aggregation) {
+                       /*
+                        * switch off RTS/CTS if it was previously enabled
+                        */
+                       sta_priv->lq_sta.lq.general_params.flags &=
+                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+               }
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size);
+               break;
+       }
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return ret;
+}
+
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       int ret;
+       u8 sta_id;
+
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->sta_id = IWL_INVALID_STATION;
+
+       atomic_set(&sta_priv->pending_frames, 0);
+       if (vif->type == NL80211_IFTYPE_AP)
+               sta_priv->client = true;
+
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               return ret;
+       }
+
+       sta_priv->sta_id = sta_id;
+
+       return 0;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               /*
+                * Station will be removed from device when the RXON
+                * is set to unassociated -- just deactivate it here
+                * to avoid re-programming it.
+                */
+               ret = 0;
+               iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
+       } else {
+               ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+               if (ret)
+                       IWL_DEBUG_QUIET_RFKILL(priv,
+                               "Error removing station %pM\n", sta->addr);
+       }
+       return ret;
+}
+
+static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               enum ieee80211_sta_state old_state,
+                               enum ieee80211_sta_state new_state)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       enum {
+               NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
+       } op = NONE;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
+                          sta->addr, old_state, new_state);
+
+       mutex_lock(&priv->mutex);
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               if (old_state == IEEE80211_STA_NOTEXIST &&
+                   new_state == IEEE80211_STA_NONE)
+                       op = ADD;
+               else if (old_state == IEEE80211_STA_NONE &&
+                        new_state == IEEE80211_STA_NOTEXIST)
+                       op = REMOVE;
+               else if (old_state == IEEE80211_STA_AUTH &&
+                        new_state == IEEE80211_STA_ASSOC)
+                       op = HT_RATE_INIT;
+       } else {
+               if (old_state == IEEE80211_STA_AUTH &&
+                   new_state == IEEE80211_STA_ASSOC)
+                       op = ADD_RATE_INIT;
+               else if (old_state == IEEE80211_STA_ASSOC &&
+                        new_state == IEEE80211_STA_AUTH)
+                       op = REMOVE;
+       }
+
+       switch (op) {
+       case ADD:
+               ret = iwlagn_mac_sta_add(hw, vif, sta);
+               if (ret)
+                       break;
+               /*
+                * Clear the in-progress flag, the AP station entry was added
+                * but we'll initialize LQ only when we've associated (which
+                * would also clear the in-progress flag). This is necessary
+                * in case we never initialize LQ because association fails.
+                */
+               spin_lock_bh(&priv->sta_lock);
+               priv->stations[iwl_sta_id(sta)].used &=
+                       ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_bh(&priv->sta_lock);
+               break;
+       case REMOVE:
+               ret = iwlagn_mac_sta_remove(hw, vif, sta);
+               break;
+       case ADD_RATE_INIT:
+               ret = iwlagn_mac_sta_add(hw, vif, sta);
+               if (ret)
+                       break;
+               /* Initialize rate scaling */
+               IWL_DEBUG_INFO(priv,
+                              "Initializing rate scaling for station %pM\n",
+                              sta->addr);
+               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+               ret = 0;
+               break;
+       case HT_RATE_INIT:
+               /* Initialize rate scaling */
+               ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
+               if (ret)
+                       break;
+               IWL_DEBUG_INFO(priv,
+                              "Initializing rate scaling for station %pM\n",
+                              sta->addr);
+               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
+               ret = 0;
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       /*
+        * mac80211 might WARN if we fail, but due the way we
+        * (badly) handle hard rfkill, we might fail here
+        */
+       if (iwl_is_rfkill(priv))
+               ret = 0;
+
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                                     struct ieee80211_channel_switch *ch_switch)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = ch_switch->channel;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u16 ch;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (iwl_is_rfkill(priv))
+               goto out;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+           test_bit(STATUS_SCANNING, &priv->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               goto out;
+
+       if (!iwl_is_associated_ctx(ctx))
+               goto out;
+
+       if (!priv->lib->set_channel_switch)
+               goto out;
+
+       ch = channel->hw_value;
+       if (le16_to_cpu(ctx->active.channel) == ch)
+               goto out;
+
+       priv->current_ht_config.smps = conf->smps_mode;
+
+       /* Configure HT40 channels */
+       ctx->ht.enabled = conf_is_ht(conf);
+       if (ctx->ht.enabled)
+               iwlagn_config_ht40(conf, ctx);
+       else
+               ctx->ht.is_40mhz = false;
+
+       if ((le16_to_cpu(ctx->staging.channel) != ch))
+               ctx->staging.flags = 0;
+
+       iwl_set_rxon_channel(priv, channel, ctx);
+       iwl_set_rxon_ht(priv, ht_conf);
+       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+       /*
+        * at this point, staging_rxon has the
+        * configuration for channel switch
+        */
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+       priv->switch_channel = cpu_to_le16(ch);
+       if (priv->lib->set_channel_switch(priv, ch_switch)) {
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+               priv->switch_channel = 0;
+               ieee80211_chswitch_done(ctx->vif, false);
+       }
+
+out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
+{
+       /*
+        * MULTI-FIXME
+        * See iwlagn_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               ieee80211_chswitch_done(ctx->vif, is_success);
+}
+
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *total_flags,
+                                   u64 multicast)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
+
+       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+                       changed_flags, *total_flags);
+
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+       mutex_lock(&priv->mutex);
+
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+
+               /*
+                * Not committing directly because hardware can perform a scan,
+                * but we'll eventually commit the filter flags change anyway.
+                */
+       }
+
+       mutex_unlock(&priv->mutex);
+
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       mutex_lock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+               goto done;
+       }
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+               goto done;
+       }
+
+       /*
+        * mac80211 will not push any more frames for transmit
+        * until the flush is completed
+        */
+       if (drop) {
+               IWL_DEBUG_MAC80211(priv, "send flush command\n");
+               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
+       }
+       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+       iwl_trans_wait_tx_queue_empty(priv->trans);
+done:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+                                    struct ieee80211_channel *channel,
+                                    enum nl80211_channel_type channel_type,
+                                    int duration)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+       int err = 0;
+
+       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+               /* mac80211 should not scan while ROC or ROC while scanning */
+               if (WARN_ON_ONCE(priv->scan_type != IWL_SCAN_RADIO_RESET)) {
+                       err = -EBUSY;
+                       goto out;
+               }
+
+               iwl_scan_cancel_timeout(priv, 100);
+
+               if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+                       err = -EBUSY;
+                       goto out;
+               }
+       }
+
+       priv->hw_roc_channel = channel;
+       priv->hw_roc_chantype = channel_type;
+       /* convert from ms to TU */
+       priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
+       priv->hw_roc_start_notified = false;
+       cancel_delayed_work(&priv->hw_roc_disable_work);
+
+       if (!ctx->is_active) {
+               static const struct iwl_qos_info default_qos_data = {
+                       .def_qos_parm = {
+                               .ac[0] = {
+                                       .cw_min = cpu_to_le16(3),
+                                       .cw_max = cpu_to_le16(7),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(1504),
+                               },
+                               .ac[1] = {
+                                       .cw_min = cpu_to_le16(7),
+                                       .cw_max = cpu_to_le16(15),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(3008),
+                               },
+                               .ac[2] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 3,
+                               },
+                               .ac[3] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 7,
+                               },
+                       },
+               };
+
+               ctx->is_active = true;
+               ctx->qos_data = default_qos_data;
+               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+               memcpy(ctx->staging.node_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               memcpy(ctx->staging.bssid_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err)
+                       goto out;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+                                            RXON_FILTER_PROMISC_MSK |
+                                            RXON_FILTER_CTL2HOST_MSK;
+
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err) {
+                       iwlagn_disable_roc(priv);
+                       goto out;
+               }
+               priv->hw_roc_setup = true;
+       }
+
+       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+       if (err)
+               iwlagn_disable_roc(priv);
+
+ out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
+       iwlagn_disable_roc(priv);
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return 0;
+}
+
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+                                    enum ieee80211_rssi_event rssi_event)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->mutex);
+
+       if (priv->cfg->bt_params &&
+                       priv->cfg->bt_params->advanced_bt_coexist) {
+               if (rssi_event == RSSI_EVENT_LOW)
+                       priv->bt_enable_pspoll = true;
+               else if (rssi_event == RSSI_EVENT_HIGH)
+                       priv->bt_enable_pspoll = false;
+
+               iwlagn_send_advance_bt_config(priv);
+       } else {
+               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+                               "ignoring RSSI callback\n");
+       }
+
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+                             struct ieee80211_sta *sta, bool set)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       queue_work(priv->workqueue, &priv->beacon_update);
+
+       return 0;
+}
+
+static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u16 queue,
+                             const struct ieee80211_tx_queue_params *params)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int q;
+
+       if (WARN_ON(!ctx))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
+
+       if (queue >= AC_NUM) {
+               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+               return 0;
+       }
+
+       q = AC_NUM - 1 - queue;
+
+       mutex_lock(&priv->mutex);
+
+       ctx->qos_data.def_qos_parm.ac[q].cw_min =
+               cpu_to_le16(params->cw_min);
+       ctx->qos_data.def_qos_parm.ac[q].cw_max =
+               cpu_to_le16(params->cw_max);
+       ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+       ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                       cpu_to_le16((params->txop * 32));
+
+       ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+
+       return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       iwl_connection_init_rx_config(priv, ctx);
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       return iwlagn_commit_rxon(priv, ctx);
+}
+
+static int iwl_setup_interface(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       struct ieee80211_vif *vif = ctx->vif;
+       int err, ac;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
+       priv->iw_mode = vif->type;
+
+       ctx->is_active = true;
+
+       err = iwl_set_mode(priv, ctx);
+       if (err) {
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+               return err;
+       }
+
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
+       /* set up queue mappings */
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               vif->hw_queue[ac] = ctx->ac_to_queue[ac];
+
+       if (vif->type == NL80211_IFTYPE_AP)
+               vif->cab_queue = ctx->mcast_queue;
+       else
+               vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+       return 0;
+}
+
+static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
+       int err;
+       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
+       bool reset = false;
+
+       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+                          viftype, vif->addr);
+
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+       mutex_lock(&priv->mutex);
+
+       iwlagn_disable_roc(priv);
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_WARN(priv, "Try to add interface when device not ready\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* On reset we need to add the same interface again */
+                       if (tmp->vif == vif) {
+                               reset = true;
+                               ctx = tmp;
+                               break;
+                       }
+
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(viftype)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+
+       err = iwl_setup_interface(priv, ctx);
+       if (!err || reset)
+               goto out;
+
+       ctx->vif = NULL;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+ out:
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return err;
+}
+
+static void iwl_teardown_interface(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  bool mode_change)
+{
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (priv->scan_vif == vif) {
+               iwl_scan_cancel_timeout(priv, 200);
+               iwl_force_scan_end(priv);
+       }
+
+       if (!mode_change) {
+               iwl_set_mode(priv, ctx);
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+       }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->last_bt_traffic_load;
+}
+
+static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (WARN_ON(ctx->vif != vif)) {
+               struct iwl_rxon_context *tmp;
+               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+               for_each_context(priv, tmp)
+                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+                               tmp->ctxid, tmp, tmp->vif);
+       }
+       ctx->vif = NULL;
+
+       iwl_teardown_interface(priv, vif, false);
+
+       mutex_unlock(&priv->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+
+static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      enum nl80211_iftype newtype, bool newp2p)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx, *tmp;
+       enum nl80211_iftype newviftype = newtype;
+       u32 interface_modes;
+       int err;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+       mutex_lock(&priv->mutex);
+
+       ctx = iwl_rxon_ctx_from_vif(vif);
+
+       /*
+        * To simplify this code, only support changes on the
+        * BSS context. The PAN context is usually reassigned
+        * by creating/removing P2P interfaces anyway.
+        */
+       if (ctx->ctxid != IWL_RXON_CTX_BSS) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+               /*
+                * Huh? But wait ... this can maybe happen when
+                * we're in the middle of a firmware restart!
+                */
+               err = -EBUSY;
+               goto out;
+       }
+
+       /* Check if the switch is supported in the same context */
+       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+       if (!(interface_modes & BIT(newtype))) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       if (ctx->exclusive_interface_modes & BIT(newtype)) {
+               for_each_context(priv, tmp) {
+                       if (ctx == tmp)
+                               continue;
+
+                       if (!tmp->is_active)
+                               continue;
+
+                       /*
+                        * The current mode switch would be exclusive, but
+                        * another context is active ... refuse the switch.
+                        */
+                       err = -EBUSY;
+                       goto out;
+               }
+       }
+
+       /* success */
+       iwl_teardown_interface(priv, vif, true);
+       vif->type = newviftype;
+       vif->p2p = newp2p;
+       err = iwl_setup_interface(priv, ctx);
+       WARN_ON(err);
+       /*
+        * We've switched internally, but submitting to the
+        * device may have failed for some reason. Mask this
+        * error, because otherwise mac80211 will not switch
+        * (and set the interface type back) and we'll be
+        * out of sync with it.
+        */
+       err = 0;
+
+ out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct cfg80211_scan_request *req)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (req->n_channels == 0)
+               return -EINVAL;
+
+       mutex_lock(&priv->mutex);
+
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->scan_type != IWL_SCAN_NORMAL) {
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               ret = 0;
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
+               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
+                                       req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+       struct iwl_addsta_cmd cmd = {
+               .mode = STA_CONTROL_MODIFY_MSK,
+               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+               .sta.sta_id = sta_id,
+       };
+
+       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
+}
+
+static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 enum sta_notify_cmd cmd,
+                                 struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       switch (cmd) {
+       case STA_NOTIFY_SLEEP:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = true;
+               if (atomic_read(&sta_priv->pending_frames) > 0)
+                       ieee80211_sta_block_awake(hw, sta, true);
+               break;
+       case STA_NOTIFY_AWAKE:
+               WARN_ON(!sta_priv->client);
+               if (!sta_priv->asleep)
+                       break;
+               sta_priv->asleep = false;
+               sta_id = iwl_sta_id(sta);
+               if (sta_id != IWL_INVALID_STATION)
+                       iwl_sta_modify_ps_wake(priv, sta_id);
+               break;
+       default:
+               break;
+       }
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+struct ieee80211_ops iwlagn_hw_ops = {
+       .tx = iwlagn_mac_tx,
+       .start = iwlagn_mac_start,
+       .stop = iwlagn_mac_stop,
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwlagn_mac_suspend,
+       .resume = iwlagn_mac_resume,
+       .set_wakeup = iwlagn_mac_set_wakeup,
+#endif
+       .add_interface = iwlagn_mac_add_interface,
+       .remove_interface = iwlagn_mac_remove_interface,
+       .change_interface = iwlagn_mac_change_interface,
+       .config = iwlagn_mac_config,
+       .configure_filter = iwlagn_configure_filter,
+       .set_key = iwlagn_mac_set_key,
+       .update_tkip_key = iwlagn_mac_update_tkip_key,
+       .set_rekey_data = iwlagn_mac_set_rekey_data,
+       .conf_tx = iwlagn_mac_conf_tx,
+       .bss_info_changed = iwlagn_bss_info_changed,
+       .ampdu_action = iwlagn_mac_ampdu_action,
+       .hw_scan = iwlagn_mac_hw_scan,
+       .sta_notify = iwlagn_mac_sta_notify,
+       .sta_state = iwlagn_mac_sta_state,
+       .channel_switch = iwlagn_mac_channel_switch,
+       .flush = iwlagn_mac_flush,
+       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
+       .remain_on_channel = iwlagn_mac_remain_on_channel,
+       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+       .rssi_callback = iwlagn_mac_rssi_callback,
+       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+       .set_tim = iwlagn_mac_set_tim,
+};
+
+/* This function both allocates and initializes hw and priv. */
+struct ieee80211_hw *iwl_alloc_all(void)
+{
+       struct iwl_priv *priv;
+       struct iwl_op_mode *op_mode;
+       /* mac80211 allocates memory for this device instance, including
+        *   space for this driver's private structure */
+       struct ieee80211_hw *hw;
+
+       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
+                               sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
+       if (!hw)
+               goto out;
+
+       op_mode = hw->priv;
+       priv = IWL_OP_MODE_GET_DVM(op_mode);
+       priv->hw = hw;
+
+out:
+       return hw;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
new file mode 100644 (file)
index 0000000..abfd791
--- /dev/null
@@ -0,0 +1,2226 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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
+ *
+ *****************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-eeprom-read.h"
+#include "iwl-eeprom-parse.h"
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-op-mode.h"
+#include "iwl-drv.h"
+#include "iwl-modparams.h"
+#include "iwl-prph.h"
+
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION        "Intel(R) Wireless WiFi Link AGN driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#define DRV_VERSION     IWLWIFI_VERSION VD
+
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct iwl_op_mode_ops iwl_dvm_ops;
+
+void iwl_update_chain_flags(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+
+       for_each_context(priv, ctx) {
+               iwlagn_set_rxon_chain(priv, ctx);
+               if (ctx->active.rx_chain != ctx->staging.rx_chain)
+                       iwlagn_commit_rxon(priv, ctx);
+       }
+}
+
+/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
+static void iwl_set_beacon_tim(struct iwl_priv *priv,
+                              struct iwl_tx_beacon_cmd *tx_beacon_cmd,
+                              u8 *beacon, u32 frame_size)
+{
+       u16 tim_idx;
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
+
+       /*
+        * The index is relative to frame start but we start looking at the
+        * variable-length part of the beacon.
+        */
+       tim_idx = mgmt->u.beacon.variable - beacon;
+
+       /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
+       while ((tim_idx < (frame_size - 2)) &&
+                       (beacon[tim_idx] != WLAN_EID_TIM))
+               tim_idx += beacon[tim_idx+1] + 2;
+
+       /* If TIM field was found, set variables */
+       if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
+               tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
+               tx_beacon_cmd->tim_size = beacon[tim_idx+1];
+       } else
+               IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
+}
+
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
+{
+       struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_TX_BEACON,
+               .flags = CMD_SYNC,
+       };
+       struct ieee80211_tx_info *info;
+       u32 frame_size;
+       u32 rate_flags;
+       u32 rate;
+
+       /*
+        * We have to set up the TX command, the TX Beacon command, and the
+        * beacon contents.
+        */
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
+               return 0;
+       }
+
+       if (WARN_ON(!priv->beacon_skb))
+               return -EINVAL;
+
+       /* Allocate beacon command */
+       if (!priv->beacon_cmd)
+               priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
+       tx_beacon_cmd = priv->beacon_cmd;
+       if (!tx_beacon_cmd)
+               return -ENOMEM;
+
+       frame_size = priv->beacon_skb->len;
+
+       /* Set up TX command fields */
+       tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+       tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
+       tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
+               TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
+
+       /* Set up TX beacon command fields */
+       iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
+                          frame_size);
+
+       /* Set up packet rate and flags */
+       info = IEEE80211_SKB_CB(priv->beacon_skb);
+
+       /*
+        * Let's set up the rate at least somewhat correctly;
+        * it will currently not actually be used by the uCode,
+        * it uses the broadcast station's rate instead.
+        */
+       if (info->control.rates[0].idx < 0 ||
+           info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+               rate = 0;
+       else
+               rate = info->control.rates[0].idx;
+
+       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+                                             priv->eeprom_data->valid_tx_ant);
+       rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+       /* In mac80211, rates for 5 GHz start at 0 */
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate += IWL_FIRST_OFDM_RATE;
+       else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE)
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+       tx_beacon_cmd->tx.rate_n_flags =
+                       iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+       /* Submit command */
+       cmd.len[0] = sizeof(*tx_beacon_cmd);
+       cmd.data[0] = tx_beacon_cmd;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       cmd.len[1] = frame_size;
+       cmd.data[1] = priv->beacon_skb->data;
+       cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, beacon_update);
+       struct sk_buff *beacon;
+
+       mutex_lock(&priv->mutex);
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "updating beacon w/o beacon context!\n");
+               goto out;
+       }
+
+       if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
+               /*
+                * The ucode will send beacon notifications even in
+                * IBSS mode, but we don't want to process them. But
+                * we need to defer the type check to here due to
+                * requiring locking around the beacon_ctx access.
+                */
+               goto out;
+       }
+
+       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+       beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
+       if (!beacon) {
+               IWL_ERR(priv, "update beacon failed -- keeping old\n");
+               goto out;
+       }
+
+       /* new beacon skb is allocated every time; dispose previous.*/
+       dev_kfree_skb(priv->beacon_skb);
+
+       priv->beacon_skb = beacon;
+
+       iwlagn_send_beacon_cmd(priv);
+ out:
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_bt_runtime_config(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_runtime_config);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+       iwlagn_send_advance_bt_config(priv);
+}
+
+static void iwl_bg_bt_full_concurrency(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_full_concurrency);
+       struct iwl_rxon_context *ctx;
+
+       mutex_lock(&priv->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               goto out;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               goto out;
+
+       IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       /*
+        * LQ & RXON updated cmds must be sent before BT Config cmd
+        * to avoid 3-wire collisions
+        */
+       for_each_context(priv, ctx) {
+               iwlagn_set_rxon_chain(priv, ctx);
+               iwlagn_commit_rxon(priv, ctx);
+       }
+
+       iwlagn_send_advance_bt_config(priv);
+out:
+       mutex_unlock(&priv->mutex);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
+{
+       struct iwl_statistics_cmd statistics_cmd = {
+               .configuration_flags =
+                       clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
+       };
+
+       if (flags & CMD_ASYNC)
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       CMD_ASYNC,
+                                       sizeof(struct iwl_statistics_cmd),
+                                       &statistics_cmd);
+       else
+               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       CMD_SYNC,
+                                       sizeof(struct iwl_statistics_cmd),
+                                       &statistics_cmd);
+}
+
+/**
+ * iwl_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to send a statistics request.
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received.  We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER.
+ */
+static void iwl_bg_statistics_periodic(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       iwl_send_statistics_request(priv, CMD_ASYNC, false);
+}
+
+
+static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
+                                       u32 start_idx, u32 num_events,
+                                       u32 capacity, u32 mode)
+{
+       u32 i;
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+       unsigned long reg_flags;
+
+       if (mode == 0)
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
+       else
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
+
+       /* Make sure device is powered up for SRAM reads */
+       spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
+       if (unlikely(!iwl_grab_nic_access(priv->trans))) {
+               spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+               return;
+       }
+
+       /* Set starting address; reads will auto-increment */
+       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
+
+       /*
+        * Refuse to read more than would have fit into the log from
+        * the current start_idx. This used to happen due to the race
+        * described below, but now WARN because the code below should
+        * prevent it from happening here.
+        */
+       if (WARN_ON(num_events > capacity - start_idx))
+               num_events = capacity - start_idx;
+
+       /*
+        * "time" is actually "data" for mode 0 (no timestamp).
+        * place event id # at far right for easier visual parsing.
+        */
+       for (i = 0; i < num_events; i++) {
+               ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+               time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+               if (mode == 0) {
+                       trace_iwlwifi_dev_ucode_cont_event(
+                                       priv->trans->dev, 0, time, ev);
+               } else {
+                       data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+                       trace_iwlwifi_dev_ucode_cont_event(
+                                       priv->trans->dev, time, data, ev);
+               }
+       }
+       /* Allow device to power down */
+       iwl_release_nic_access(priv->trans);
+       spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
+}
+
+static void iwl_continuous_event_trace(struct iwl_priv *priv)
+{
+       u32 capacity;   /* event log capacity in # entries */
+       struct {
+               u32 capacity;
+               u32 mode;
+               u32 wrap_counter;
+               u32 write_counter;
+       } __packed read;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+
+       base = priv->device_pointers.log_event_table;
+       if (iwlagn_hw_valid_rtc_data_addr(base)) {
+               iwl_read_targ_mem_bytes(priv->trans, base, &read, sizeof(read));
+               capacity = read.capacity;
+               mode = read.mode;
+               num_wraps = read.wrap_counter;
+               next_entry = read.write_counter;
+       } else
+               return;
+
+       /*
+        * Unfortunately, the uCode doesn't use temporary variables.
+        * Therefore, it can happen that we read next_entry == capacity,
+        * which really means next_entry == 0.
+        */
+       if (unlikely(next_entry == capacity))
+               next_entry = 0;
+       /*
+        * Additionally, the uCode increases the write pointer before
+        * the wraps counter, so if the write pointer is smaller than
+        * the old write pointer (wrap occurred) but we read that no
+        * wrap occurred, we actually read between the next_entry and
+        * num_wraps update (this does happen in practice!!) -- take
+        * that into account by increasing num_wraps.
+        */
+       if (unlikely(next_entry < priv->event_log.next_entry &&
+                    num_wraps == priv->event_log.num_wraps))
+               num_wraps++;
+
+       if (num_wraps == priv->event_log.num_wraps) {
+               iwl_print_cont_event_trace(
+                       priv, base, priv->event_log.next_entry,
+                       next_entry - priv->event_log.next_entry,
+                       capacity, mode);
+
+               priv->event_log.non_wraps_count++;
+       } else {
+               if (num_wraps - priv->event_log.num_wraps > 1)
+                       priv->event_log.wraps_more_count++;
+               else
+                       priv->event_log.wraps_once_count++;
+
+               trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev,
+                               num_wraps - priv->event_log.num_wraps,
+                               next_entry, priv->event_log.next_entry);
+
+               if (next_entry < priv->event_log.next_entry) {
+                       iwl_print_cont_event_trace(
+                               priv, base, priv->event_log.next_entry,
+                               capacity - priv->event_log.next_entry,
+                               capacity, mode);
+
+                       iwl_print_cont_event_trace(
+                               priv, base, 0, next_entry, capacity, mode);
+               } else {
+                       iwl_print_cont_event_trace(
+                               priv, base, next_entry,
+                               capacity - next_entry,
+                               capacity, mode);
+
+                       iwl_print_cont_event_trace(
+                               priv, base, 0, next_entry, capacity, mode);
+               }
+       }
+
+       priv->event_log.num_wraps = num_wraps;
+       priv->event_log.next_entry = next_entry;
+}
+
+/**
+ * iwl_bg_ucode_trace - Timer callback to log ucode event
+ *
+ * The timer is continually set to execute every
+ * UCODE_TRACE_PERIOD milliseconds after the last timer expired
+ * this function is to perform continuous uCode event logging operation
+ * if enabled
+ */
+static void iwl_bg_ucode_trace(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (priv->event_log.ucode_trace) {
+               iwl_continuous_event_trace(priv);
+               /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
+               mod_timer(&priv->ucode_trace,
+                        jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+       }
+}
+
+static void iwl_bg_tx_flush(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, tx_flush);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* do nothing if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
+       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+}
+
+/*
+ * queue/FIFO/AC mapping definitions
+ */
+
+#define IWL_TX_FIFO_BK         0       /* shared */
+#define IWL_TX_FIFO_BE         1
+#define IWL_TX_FIFO_VI         2       /* shared */
+#define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN    4
+#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN    5
+/* re-uses the VO FIFO, uCode will properly flush/schedule */
+#define IWL_TX_FIFO_AUX                5
+#define IWL_TX_FIFO_UNUSED     -1
+
+#define IWLAGN_CMD_FIFO_NUM    7
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE   8
+
+static const u8 iwlagn_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWLAGN_CMD_FIFO_NUM,
+};
+
+static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWL_TX_FIFO_BK_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWLAGN_CMD_FIFO_NUM,
+       IWL_TX_FIFO_AUX,
+};
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static const u8 iwlagn_bss_ac_to_queue[] = {
+       0, 1, 2, 3,
+};
+
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_BK_IPAN,
+};
+
+static const u8 iwlagn_pan_ac_to_queue[] = {
+       7, 6, 5, 4,
+};
+
+static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
+{
+       int i;
+
+       /*
+        * The default context is always valid,
+        * the PAN context depends on uCode.
+        */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+       if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
+               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
+       priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+               BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION);
+       priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
+              iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
+              iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
+
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
+               REPLY_WIPAN_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
+               REPLY_WIPAN_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+       priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+       priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+       priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+
+       if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
+               priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
+                       BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                       BIT(NL80211_IFTYPE_P2P_GO);
+
+       priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+       priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+       priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
+              iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
+       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
+              iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
+       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+}
+
+static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+{
+       struct iwl_ct_kill_config cmd;
+       struct iwl_ct_kill_throttling_config adv_cmd;
+       int ret = 0;
+
+       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+
+       priv->thermal_throttle.ct_kill_toggle = false;
+
+       if (priv->cfg->base_params->support_ct_kill_exit) {
+               adv_cmd.critical_temperature_enter =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
+               adv_cmd.critical_temperature_exit =
+                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+               ret = iwl_dvm_send_cmd_pdu(priv,
+                                      REPLY_CT_KILL_CONFIG_CMD,
+                                      CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                               "succeeded, critical temperature enter is %d,"
+                               "exit is %d\n",
+                               priv->hw_params.ct_kill_threshold,
+                               priv->hw_params.ct_kill_exit_threshold);
+       } else {
+               cmd.critical_temperature_R =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
+
+               ret = iwl_dvm_send_cmd_pdu(priv,
+                                      REPLY_CT_KILL_CONFIG_CMD,
+                                      CMD_SYNC, sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                               "succeeded, "
+                               "critical temperature is %d\n",
+                               priv->hw_params.ct_kill_threshold);
+       }
+}
+
+static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
+{
+       struct iwl_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+
+static int iwlagn_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->fw->ucode_ver) > 1) {
+               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+               return iwl_dvm_send_cmd_pdu(priv,
+                                       TX_ANT_CONFIGURATION_CMD,
+                                       CMD_SYNC,
+                                       sizeof(struct iwl_tx_ant_config_cmd),
+                                       &tx_ant_cmd);
+       } else {
+               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+static void iwl_send_bt_config(struct iwl_priv *priv)
+{
+       struct iwl_bt_cmd bt_cmd = {
+               .lead_time = BT_LEAD_TIME_DEF,
+               .max_kill = BT_MAX_KILL_DEF,
+               .kill_ack_mask = 0,
+               .kill_cts_mask = 0,
+       };
+
+       if (!iwlwifi_mod_params.bt_coex_active)
+               bt_cmd.flags = BT_COEX_DISABLE;
+       else
+               bt_cmd.flags = BT_COEX_ENABLE;
+
+       priv->bt_enable_flag = bt_cmd.flags;
+       IWL_DEBUG_INFO(priv, "BT coex %s\n",
+               (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
+
+       if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                            CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
+}
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl_init_alive_start()).
+ */
+int iwl_alive_start(struct iwl_priv *priv)
+{
+       int ret = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+       IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+
+       /* After the ALIVE response, we can send host commands to the uCode */
+       set_bit(STATUS_ALIVE, &priv->status);
+
+       if (iwl_is_rfkill(priv))
+               return -ERFKILL;
+
+       if (priv->event_log.ucode_trace) {
+               /* start collecting data now */
+               mod_timer(&priv->ucode_trace, jiffies);
+       }
+
+       /* download priority table before any calibration request */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               /* Configure Bluetooth device coexistence support */
+               if (priv->cfg->bt_params->bt_sco_disable)
+                       priv->bt_enable_pspoll = false;
+               else
+                       priv->bt_enable_pspoll = true;
+
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               iwlagn_send_advance_bt_config(priv);
+               priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+               priv->cur_rssi_ctx = NULL;
+
+               iwl_send_prio_tbl(priv);
+
+               /* FIXME: w/a to force change uCode BT state machine */
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+                                        BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+               if (ret)
+                       return ret;
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+                                        BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+               if (ret)
+                       return ret;
+       } else {
+               /*
+                * default is 2-wire BT coexexistence support
+                */
+               iwl_send_bt_config(priv);
+       }
+
+       /*
+        * Perform runtime calibrations, including DC calibration.
+        */
+       iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX);
+
+       ieee80211_wake_queues(priv->hw);
+
+       /* Configure Tx antenna selection based on H/W config */
+       iwlagn_send_tx_ant_config(priv, priv->eeprom_data->valid_tx_ant);
+
+       if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
+               struct iwl_rxon_cmd *active_rxon =
+                               (struct iwl_rxon_cmd *)&ctx->active;
+               /* apply any changes in staging */
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       } else {
+               struct iwl_rxon_context *tmp;
+               /* Initialize our rx_config data */
+               for_each_context(priv, tmp)
+                       iwl_connection_init_rx_config(priv, tmp);
+
+               iwlagn_set_rxon_chain(priv, ctx);
+       }
+
+       if (!priv->wowlan) {
+               /* WoWLAN ucode will not reply in the same way, skip it */
+               iwl_reset_run_time_calib(priv);
+       }
+
+       set_bit(STATUS_READY, &priv->status);
+
+       /* Configure the adapter for unassociated operation */
+       ret = iwlagn_commit_rxon(priv, ctx);
+       if (ret)
+               return ret;
+
+       /* At this point, the NIC is initialized and operational */
+       iwl_rf_kill_ct_config(priv);
+
+       IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
+
+       return iwl_power_update_mode(priv, true);
+}
+
+/**
+ * iwl_clear_driver_stations - clear knowledge of all stations from driver
+ * @priv: iwl priv struct
+ *
+ * This is called during iwl_down() to make sure that in the case
+ * we're coming there from a hardware restart mac80211 will be
+ * able to reconfigure stations -- if we're getting there in the
+ * normal down flow then the stations will already be cleared.
+ */
+static void iwl_clear_driver_stations(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+
+       spin_lock_bh(&priv->sta_lock);
+       memset(priv->stations, 0, sizeof(priv->stations));
+       priv->num_stations = 0;
+
+       priv->ucode_key_table = 0;
+
+       for_each_context(priv, ctx) {
+               /*
+                * Remove all key information that is not stored as part
+                * of station information since mac80211 may not have had
+                * a chance to remove all the keys. When device is
+                * reconfigured by mac80211 after an error all keys will
+                * be reconfigured.
+                */
+               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
+               ctx->key_mapping_keys = 0;
+       }
+
+       spin_unlock_bh(&priv->sta_lock);
+}
+
+void iwl_down(struct iwl_priv *priv)
+{
+       int exit_pending;
+
+       IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
+
+       lockdep_assert_held(&priv->mutex);
+
+       iwl_scan_cancel_timeout(priv, 200);
+
+       /*
+        * If active, scanning won't cancel it, so say it expired.
+        * No race since we hold the mutex here and a new one
+        * can't come in at this time.
+        */
+       ieee80211_remain_on_channel_expired(priv->hw);
+
+       exit_pending =
+               test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
+       iwl_clear_driver_stations(priv);
+
+       /* reset BT coex data */
+       priv->bt_status = 0;
+       priv->cur_rssi_ctx = NULL;
+       priv->bt_is_sco = 0;
+       if (priv->cfg->bt_params)
+               priv->bt_traffic_load =
+                        priv->cfg->bt_params->bt_init_traffic_load;
+       else
+               priv->bt_traffic_load = 0;
+       priv->bt_full_concurrent = false;
+       priv->bt_ci_compliance = 0;
+
+       /* Wipe out the EXIT_PENDING status bit if we are not actually
+        * exiting the module */
+       if (!exit_pending)
+               clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+       if (priv->mac80211_registered)
+               ieee80211_stop_queues(priv->hw);
+
+       priv->ucode_loaded = false;
+       iwl_trans_stop_device(priv->trans);
+
+       /* Set num_aux_in_flight must be done after the transport is stopped */
+       atomic_set(&priv->num_aux_in_flight, 0);
+
+       /* Clear out all status bits but a few that are stable across reset */
+       priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+                               STATUS_RF_KILL_HW |
+                       test_bit(STATUS_FW_ERROR, &priv->status) <<
+                               STATUS_FW_ERROR |
+                       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
+                               STATUS_EXIT_PENDING;
+
+       dev_kfree_skb(priv->beacon_skb);
+       priv->beacon_skb = NULL;
+}
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_run_time_calib_work(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv,
+                       run_time_calib_work);
+
+       mutex_lock(&priv->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+           test_bit(STATUS_SCANNING, &priv->status)) {
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
+       if (priv->start_calib) {
+               iwl_chain_noise_calibration(priv);
+               iwl_sensitivity_calibration(priv);
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+void iwlagn_prepare_restart(struct iwl_priv *priv)
+{
+       bool bt_full_concurrent;
+       u8 bt_ci_compliance;
+       u8 bt_load;
+       u8 bt_status;
+       bool bt_is_sco;
+       int i;
+
+       lockdep_assert_held(&priv->mutex);
+
+       priv->is_open = 0;
+
+       /*
+        * __iwl_down() will clear the BT status variables,
+        * which is correct, but when we restart we really
+        * want to keep them so restore them afterwards.
+        *
+        * The restart process will later pick them up and
+        * re-configure the hw when we reconfigure the BT
+        * command.
+        */
+       bt_full_concurrent = priv->bt_full_concurrent;
+       bt_ci_compliance = priv->bt_ci_compliance;
+       bt_load = priv->bt_traffic_load;
+       bt_status = priv->bt_status;
+       bt_is_sco = priv->bt_is_sco;
+
+       iwl_down(priv);
+
+       priv->bt_full_concurrent = bt_full_concurrent;
+       priv->bt_ci_compliance = bt_ci_compliance;
+       priv->bt_traffic_load = bt_load;
+       priv->bt_status = bt_status;
+       priv->bt_is_sco = bt_is_sco;
+
+       /* reset aggregation queues */
+       for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
+               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+       /* and stop counts */
+       for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
+               atomic_set(&priv->queue_stop_count[i], 0);
+
+       memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+       struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               mutex_lock(&priv->mutex);
+               iwlagn_prepare_restart(priv);
+               mutex_unlock(&priv->mutex);
+               iwl_cancel_deferred_work(priv);
+               ieee80211_restart_hw(priv->hw);
+       } else {
+               WARN_ON(1);
+       }
+}
+
+
+
+
+void iwlagn_disable_roc(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->hw_roc_setup)
+               return;
+
+       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+       priv->hw_roc_channel = NULL;
+
+       memset(ctx->staging.node_addr, 0, ETH_ALEN);
+
+       iwlagn_commit_rxon(priv, ctx);
+
+       ctx->is_active = false;
+       priv->hw_roc_setup = false;
+}
+
+static void iwlagn_disable_roc_work(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv,
+                                            hw_roc_disable_work.work);
+
+       mutex_lock(&priv->mutex);
+       iwlagn_disable_roc(priv);
+       mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+       priv->workqueue = create_singlethread_workqueue(DRV_NAME);
+
+       INIT_WORK(&priv->restart, iwl_bg_restart);
+       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
+       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+                         iwlagn_disable_roc_work);
+
+       iwl_setup_scan_deferred_work(priv);
+
+       if (priv->cfg->bt_params)
+               iwlagn_bt_setup_deferred_work(priv);
+
+       init_timer(&priv->statistics_periodic);
+       priv->statistics_periodic.data = (unsigned long)priv;
+       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
+}
+
+void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+       if (priv->cfg->bt_params)
+               iwlagn_bt_cancel_deferred_work(priv);
+
+       cancel_work_sync(&priv->run_time_calib_work);
+       cancel_work_sync(&priv->beacon_update);
+
+       iwl_cancel_scan_deferred_work(priv);
+
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+       del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
+}
+
+static int iwl_init_drv(struct iwl_priv *priv)
+{
+       spin_lock_init(&priv->sta_lock);
+
+       mutex_init(&priv->mutex);
+
+       INIT_LIST_HEAD(&priv->calib_results);
+
+       priv->band = IEEE80211_BAND_2GHZ;
+
+       priv->plcp_delta_threshold =
+               priv->cfg->base_params->plcp_delta_threshold;
+
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+       priv->agg_tids_count = 0;
+
+       priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
+
+       priv->rx_statistics_jiffies = jiffies;
+
+       /* Choose which receivers/antennas to use */
+       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
+
+       iwl_init_scan_params(priv);
+
+       /* init bt coex */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+       }
+
+       return 0;
+}
+
+static void iwl_uninit_drv(struct iwl_priv *priv)
+{
+       kfree(priv->scan_cmd);
+       kfree(priv->beacon_cmd);
+       kfree(rcu_dereference_raw(priv->noa_data));
+       iwl_calib_free_results(priv);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       kfree(priv->wowlan_sram);
+#endif
+}
+
+static void iwl_set_hw_params(struct iwl_priv *priv)
+{
+       if (priv->cfg->ht_params)
+               priv->hw_params.use_rts_for_aggregation =
+                       priv->cfg->ht_params->use_rts_for_aggregation;
+
+       /* Device-specific setup */
+       priv->lib->set_hw_params(priv);
+}
+
+
+
+/* show what optional capabilities we have */
+static void iwl_option_config(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
+#else
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
+#else
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
+#else
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
+#else
+       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
+#endif
+
+#ifdef CONFIG_IWLWIFI_P2P
+       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
+#else
+       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
+#endif
+}
+
+static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
+{
+       u16 radio_cfg;
+
+       priv->eeprom_data->sku = priv->eeprom_data->sku;
+
+       if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE &&
+           !priv->cfg->ht_params) {
+               IWL_ERR(priv, "Invalid 11n configuration\n");
+               return -EINVAL;
+       }
+
+       if (!priv->eeprom_data->sku) {
+               IWL_ERR(priv, "Invalid device sku\n");
+               return -EINVAL;
+       }
+
+       IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
+
+       radio_cfg = priv->eeprom_data->radio_cfg;
+
+       priv->hw_params.tx_chains_num =
+               num_of_ant(priv->eeprom_data->valid_tx_ant);
+       if (priv->cfg->rx_with_siso_diversity)
+               priv->hw_params.rx_chains_num = 1;
+       else
+               priv->hw_params.rx_chains_num =
+                       num_of_ant(priv->eeprom_data->valid_rx_ant);
+
+       IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
+                priv->eeprom_data->valid_tx_ant,
+                priv->eeprom_data->valid_rx_ant);
+
+       return 0;
+}
+
+static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
+                                                const struct iwl_cfg *cfg,
+                                                const struct iwl_fw *fw)
+{
+       struct iwl_priv *priv;
+       struct ieee80211_hw *hw;
+       struct iwl_op_mode *op_mode;
+       u16 num_mac;
+       u32 ucode_flags;
+       struct iwl_trans_config trans_cfg;
+       static const u8 no_reclaim_cmds[] = {
+               REPLY_RX_PHY_CMD,
+               REPLY_RX,
+               REPLY_RX_MPDU_CMD,
+               REPLY_COMPRESSED_BA,
+               STATISTICS_NOTIFICATION,
+               REPLY_TX,
+       };
+       int i;
+
+       /************************
+        * 1. Allocating HW data
+        ************************/
+       hw = iwl_alloc_all();
+       if (!hw) {
+               pr_err("%s: Cannot allocate network device\n", cfg->name);
+               goto out;
+       }
+
+       op_mode = hw->priv;
+       op_mode->ops = &iwl_dvm_ops;
+       priv = IWL_OP_MODE_GET_DVM(op_mode);
+       priv->trans = trans;
+       priv->dev = trans->dev;
+       priv->cfg = cfg;
+       priv->fw = fw;
+
+       switch (priv->cfg->device_family) {
+       case IWL_DEVICE_FAMILY_1000:
+       case IWL_DEVICE_FAMILY_100:
+               priv->lib = &iwl1000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_2000:
+       case IWL_DEVICE_FAMILY_105:
+               priv->lib = &iwl2000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_2030:
+       case IWL_DEVICE_FAMILY_135:
+               priv->lib = &iwl2030_lib;
+               break;
+       case IWL_DEVICE_FAMILY_5000:
+               priv->lib = &iwl5000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_5150:
+               priv->lib = &iwl5150_lib;
+               break;
+       case IWL_DEVICE_FAMILY_6000:
+       case IWL_DEVICE_FAMILY_6005:
+       case IWL_DEVICE_FAMILY_6000i:
+       case IWL_DEVICE_FAMILY_6050:
+       case IWL_DEVICE_FAMILY_6150:
+               priv->lib = &iwl6000_lib;
+               break;
+       case IWL_DEVICE_FAMILY_6030:
+               priv->lib = &iwl6030_lib;
+               break;
+       default:
+               break;
+       }
+
+       if (WARN_ON(!priv->lib))
+               goto out_free_hw;
+
+       /*
+        * Populate the state variables that the transport layer needs
+        * to know about.
+        */
+       trans_cfg.op_mode = op_mode;
+       trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
+       trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
+       trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
+       if (!iwlwifi_mod_params.wd_disable)
+               trans_cfg.queue_watchdog_timeout =
+                       priv->cfg->base_params->wd_timeout;
+       else
+               trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+       trans_cfg.command_names = iwl_dvm_cmd_strings;
+
+       WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE <
+               priv->cfg->base_params->num_of_queues);
+
+       ucode_flags = fw->ucode_capa.flags;
+
+#ifndef CONFIG_IWLWIFI_P2P
+       ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+#endif
+
+       if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
+               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+               trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
+       } else {
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+       }
+
+       /* Configure transport layer */
+       iwl_trans_configure(priv->trans, &trans_cfg);
+
+       /* At this point both hw and priv are allocated. */
+
+       SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
+
+       iwl_option_config(priv);
+
+       IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
+
+       /* is antenna coupling more than 35dB ? */
+       priv->bt_ant_couple_ok =
+               (iwlwifi_mod_params.ant_coupling >
+                       IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
+                       true : false;
+
+       /* enable/disable bt channel inhibition */
+       priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce;
+       IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
+                      (priv->bt_ch_announce) ? "On" : "Off");
+
+       /* these spin locks will be used in apm_ops.init and EEPROM access
+        * we should init now
+        */
+       spin_lock_init(&priv->statistics.lock);
+
+       /***********************
+        * 2. Read REV register
+        ***********************/
+       IWL_INFO(priv, "Detected %s, REV=0x%X\n",
+               priv->cfg->name, priv->trans->hw_rev);
+
+       if (iwl_trans_start_hw(priv->trans))
+               goto out_free_hw;
+
+       /* Read the EEPROM */
+       if (iwl_read_eeprom(priv->trans, &priv->eeprom_blob,
+                           &priv->eeprom_blob_size)) {
+               IWL_ERR(priv, "Unable to init EEPROM\n");
+               goto out_free_hw;
+       }
+
+       /* Reset chip to save power until we load uCode during "up". */
+       iwl_trans_stop_hw(priv->trans, false);
+
+       priv->eeprom_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
+                                                 priv->eeprom_blob,
+                                                 priv->eeprom_blob_size);
+       if (!priv->eeprom_data)
+               goto out_free_eeprom_blob;
+
+       if (iwl_eeprom_check_version(priv->eeprom_data, priv->trans))
+               goto out_free_eeprom;
+
+       if (iwl_eeprom_init_hw_params(priv))
+               goto out_free_eeprom;
+
+       /* extract MAC Address */
+       memcpy(priv->addresses[0].addr, priv->eeprom_data->hw_addr, ETH_ALEN);
+       IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
+       priv->hw->wiphy->addresses = priv->addresses;
+       priv->hw->wiphy->n_addresses = 1;
+       num_mac = priv->eeprom_data->n_hw_addrs;
+       if (num_mac > 1) {
+               memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
+                      ETH_ALEN);
+               priv->addresses[1].addr[5]++;
+               priv->hw->wiphy->n_addresses++;
+       }
+
+       /************************
+        * 4. Setup HW constants
+        ************************/
+       iwl_set_hw_params(priv);
+
+       if (!(priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
+               IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
+               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
+               /*
+                * if not PAN, then don't support P2P -- might be a uCode
+                * packaging bug or due to the eeprom check above
+                */
+               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+               trans_cfg.n_queue_to_fifo =
+                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
+
+               /* Configure transport layer again*/
+               iwl_trans_configure(priv->trans, &trans_cfg);
+       }
+
+       /*******************
+        * 5. Setup priv
+        *******************/
+       for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
+               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
+               if (i < IWLAGN_FIRST_AMPDU_QUEUE &&
+                   i != IWL_DEFAULT_CMD_QUEUE_NUM &&
+                   i != IWL_IPAN_CMD_QUEUE_NUM)
+                       priv->queue_to_mac80211[i] = i;
+               atomic_set(&priv->queue_stop_count[i], 0);
+       }
+
+       WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
+                                               IWLAGN_CMD_FIFO_NUM);
+
+       if (iwl_init_drv(priv))
+               goto out_free_eeprom;
+
+       /* At this point both hw and priv are initialized. */
+
+       /********************
+        * 6. Setup services
+        ********************/
+       iwl_setup_deferred_work(priv);
+       iwl_setup_rx_handlers(priv);
+       iwl_testmode_init(priv);
+
+       iwl_power_initialize(priv);
+       iwl_tt_initialize(priv);
+
+       snprintf(priv->hw->wiphy->fw_version,
+                sizeof(priv->hw->wiphy->fw_version),
+                "%s", fw->fw_version);
+
+       priv->new_scan_threshold_behaviour =
+               !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
+       priv->phy_calib_chain_noise_reset_cmd =
+               fw->ucode_capa.standard_phy_calibration_size;
+       priv->phy_calib_chain_noise_gain_cmd =
+               fw->ucode_capa.standard_phy_calibration_size + 1;
+
+       /* initialize all valid contexts */
+       iwl_init_context(priv, ucode_flags);
+
+       /**************************************************
+        * This is still part of probe() in a sense...
+        *
+        * 7. Setup and register with mac80211 and debugfs
+        **************************************************/
+       if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
+               goto out_destroy_workqueue;
+
+       if (iwl_dbgfs_register(priv, DRV_NAME))
+               IWL_ERR(priv,
+                       "failed to create debugfs files. Ignoring error\n");
+
+       return op_mode;
+
+out_destroy_workqueue:
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
+       iwl_uninit_drv(priv);
+out_free_eeprom_blob:
+       kfree(priv->eeprom_blob);
+out_free_eeprom:
+       iwl_free_eeprom_data(priv->eeprom_data);
+out_free_hw:
+       ieee80211_free_hw(priv->hw);
+out:
+       op_mode = NULL;
+       return op_mode;
+}
+
+static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
+
+       iwl_dbgfs_unregister(priv);
+
+       iwl_testmode_free(priv);
+       iwlagn_mac_unregister(priv);
+
+       iwl_tt_exit(priv);
+
+       /*This will stop the queues, move the device to low power state */
+       priv->ucode_loaded = false;
+       iwl_trans_stop_device(priv->trans);
+
+       kfree(priv->eeprom_blob);
+       iwl_free_eeprom_data(priv->eeprom_data);
+
+       /*netif_stop_queue(dev); */
+       flush_workqueue(priv->workqueue);
+
+       /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
+        * priv->workqueue... so we can't take down the workqueue
+        * until now... */
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
+
+       iwl_uninit_drv(priv);
+
+       dev_kfree_skb(priv->beacon_skb);
+
+       iwl_trans_stop_hw(priv->trans, true);
+       ieee80211_free_hw(priv->hw);
+}
+
+static const char * const desc_lookup_text[] = {
+       "OK",
+       "FAIL",
+       "BAD_PARAM",
+       "BAD_CHECKSUM",
+       "NMI_INTERRUPT_WDG",
+       "SYSASSERT",
+       "FATAL_ERROR",
+       "BAD_COMMAND",
+       "HW_ERROR_TUNE_LOCK",
+       "HW_ERROR_TEMPERATURE",
+       "ILLEGAL_CHAN_FREQ",
+       "VCC_NOT_STABLE",
+       "FH_ERROR",
+       "NMI_INTERRUPT_HOST",
+       "NMI_INTERRUPT_ACTION_PT",
+       "NMI_INTERRUPT_UNKNOWN",
+       "UCODE_VERSION_MISMATCH",
+       "HW_ERROR_ABS_LOCK",
+       "HW_ERROR_CAL_LOCK_FAIL",
+       "NMI_INTERRUPT_INST_ACTION_PT",
+       "NMI_INTERRUPT_DATA_ACTION_PT",
+       "NMI_TRM_HW_ER",
+       "NMI_INTERRUPT_TRM",
+       "NMI_INTERRUPT_BREAK_POINT",
+       "DEBUG_0",
+       "DEBUG_1",
+       "DEBUG_2",
+       "DEBUG_3",
+};
+
+static struct { char *name; u8 num; } advanced_lookup[] = {
+       { "NMI_INTERRUPT_WDG", 0x34 },
+       { "SYSASSERT", 0x35 },
+       { "UCODE_VERSION_MISMATCH", 0x37 },
+       { "BAD_COMMAND", 0x38 },
+       { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
+       { "FATAL_ERROR", 0x3D },
+       { "NMI_TRM_HW_ERR", 0x46 },
+       { "NMI_INTERRUPT_TRM", 0x4C },
+       { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
+       { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
+       { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
+       { "NMI_INTERRUPT_HOST", 0x66 },
+       { "NMI_INTERRUPT_ACTION_PT", 0x7C },
+       { "NMI_INTERRUPT_UNKNOWN", 0x84 },
+       { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
+       { "ADVANCED_SYSASSERT", 0 },
+};
+
+static const char *desc_lookup(u32 num)
+{
+       int i;
+       int max = ARRAY_SIZE(desc_lookup_text);
+
+       if (num < max)
+               return desc_lookup_text[num];
+
+       max = ARRAY_SIZE(advanced_lookup) - 1;
+       for (i = 0; i < max; i++) {
+               if (advanced_lookup[i].num == num)
+                       break;
+       }
+       return advanced_lookup[i].name;
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+       struct iwl_trans *trans = priv->trans;
+       u32 base;
+       struct iwl_error_event_table table;
+
+       base = priv->device_pointers.error_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               if (!base)
+                       base = priv->fw->init_errlog_ptr;
+       } else {
+               if (!base)
+                       base = priv->fw->inst_errlog_ptr;
+       }
+
+       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv,
+                       "Not valid error log pointer 0x%08X for %s uCode\n",
+                       base,
+                       (priv->cur_ucode == IWL_UCODE_INIT)
+                                       ? "Init" : "RT");
+               return;
+       }
+
+       /*TODO: Update dbgfs with ISR error stats obtained below */
+       iwl_read_targ_mem_bytes(trans, base, &table, sizeof(table));
+
+       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+               IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+               IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+                       priv->status, table.valid);
+       }
+
+       trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
+                                     table.data1, table.data2, table.line,
+                                     table.blink1, table.blink2, table.ilink1,
+                                     table.ilink2, table.bcon_time, table.gp1,
+                                     table.gp2, table.gp3, table.ucode_ver,
+                                     table.hw_ver, table.brd_ver);
+       IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+               desc_lookup(table.error_id));
+       IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+       IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+       IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+       IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+       IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+       IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+       IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+       IWL_ERR(priv, "0x%08X | line\n", table.line);
+       IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+       IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+       IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+       IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+       IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+       IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+       IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+       IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+       IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+       IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
+       IWL_ERR(priv, "0x%08X | isr0\n", table.isr0);
+       IWL_ERR(priv, "0x%08X | isr1\n", table.isr1);
+       IWL_ERR(priv, "0x%08X | isr2\n", table.isr2);
+       IWL_ERR(priv, "0x%08X | isr3\n", table.isr3);
+       IWL_ERR(priv, "0x%08X | isr4\n", table.isr4);
+       IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref);
+       IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event);
+       IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control);
+       IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration);
+       IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+       IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+       IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+       IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp);
+       IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                              u32 num_events, u32 mode,
+                              int pos, char **buf, size_t bufsz)
+{
+       u32 i;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+       unsigned long reg_flags;
+
+       struct iwl_trans *trans = priv->trans;
+
+       if (num_events == 0)
+               return pos;
+
+       base = priv->device_pointers.log_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               if (!base)
+                       base = priv->fw->init_evtlog_ptr;
+       } else {
+               if (!base)
+                       base = priv->fw->inst_evtlog_ptr;
+       }
+
+       if (mode == 0)
+               event_size = 2 * sizeof(u32);
+       else
+               event_size = 3 * sizeof(u32);
+
+       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+       /* Make sure device is powered up for SRAM reads */
+       spin_lock_irqsave(&trans->reg_lock, reg_flags);
+       if (unlikely(!iwl_grab_nic_access(trans)))
+               goto out_unlock;
+
+       /* Set starting address; reads will auto-increment */
+       iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
+
+       /* "time" is actually "data" for mode 0 (no timestamp).
+       * place event id # at far right for easier visual parsing. */
+       for (i = 0; i < num_events; i++) {
+               ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               time = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+               if (mode == 0) {
+                       /* data, ev */
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOG:0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               trace_iwlwifi_dev_ucode_event(trans->dev, 0,
+                                       time, ev);
+                               IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+                                       time, ev);
+                       }
+               } else {
+                       data = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                       time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(trans->dev, time,
+                                       data, ev);
+                       }
+               }
+       }
+
+       /* Allow device to power down */
+       iwl_release_nic_access(trans);
+out_unlock:
+       spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
+       return pos;
+}
+
+/**
+ * iwl_print_last_event_logs - Dump the newest # of event log to syslog
+ */
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                   u32 num_wraps, u32 next_entry,
+                                   u32 size, u32 mode,
+                                   int pos, char **buf, size_t bufsz)
+{
+       /*
+        * display the newest DEFAULT_LOG_ENTRIES entries
+        * i.e the entries just before the next ont that uCode would fill.
+        */
+       if (num_wraps) {
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv,
+                                               capacity - (size - next_entry),
+                                               size - next_entry, mode,
+                                               pos, buf, bufsz);
+                       pos = iwl_print_event_log(priv, 0,
+                                                 next_entry, mode,
+                                                 pos, buf, bufsz);
+               } else
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+       } else {
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv, 0, next_entry,
+                                                 mode, pos, buf, bufsz);
+               } else {
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+               }
+       }
+       return pos;
+}
+
+#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
+
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
+{
+       u32 base;       /* SRAM byte address of event log header */
+       u32 capacity;   /* event log capacity in # entries */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+       u32 size;       /* # entries that we'll print */
+       u32 logsize;
+       int pos = 0;
+       size_t bufsz = 0;
+       struct iwl_trans *trans = priv->trans;
+
+       base = priv->device_pointers.log_event_table;
+       if (priv->cur_ucode == IWL_UCODE_INIT) {
+               logsize = priv->fw->init_evtlog_size;
+               if (!base)
+                       base = priv->fw->init_evtlog_ptr;
+       } else {
+               logsize = priv->fw->inst_evtlog_size;
+               if (!base)
+                       base = priv->fw->inst_evtlog_ptr;
+       }
+
+       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
+               IWL_ERR(priv,
+                       "Invalid event log pointer 0x%08X for %s uCode\n",
+                       base,
+                       (priv->cur_ucode == IWL_UCODE_INIT)
+                                       ? "Init" : "RT");
+               return -EINVAL;
+       }
+
+       /* event log header */
+       capacity = iwl_read_targ_mem(trans, base);
+       mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
+
+       if (capacity > logsize) {
+               IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
+                       "entries\n", capacity, logsize);
+               capacity = logsize;
+       }
+
+       if (next_entry > logsize) {
+               IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
+                       next_entry, logsize);
+               next_entry = logsize;
+       }
+
+       size = num_wraps ? capacity : next_entry;
+
+       /* bail out if nothing in log */
+       if (size == 0) {
+               IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
+               return pos;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
+               size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+                       ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#else
+       size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
+               ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
+#endif
+       IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
+               size);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+       }
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
+               /*
+                * if uCode has wrapped back to top of log,
+                * start at the oldest entry,
+                * i.e the next one that uCode would fill.
+                */
+               if (num_wraps)
+                       pos = iwl_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
+               /* (then/else) start at top of log */
+               pos = iwl_print_event_log(priv, 0,
+                                         next_entry, mode, pos, buf, bufsz);
+       } else
+               pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                               next_entry, size, mode,
+                                               pos, buf, bufsz);
+#else
+       pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode,
+                                       pos, buf, bufsz);
+#endif
+       return pos;
+}
+
+static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
+{
+       unsigned int reload_msec;
+       unsigned long reload_jiffies;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
+               iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
+#endif
+
+       /* uCode is no longer loaded. */
+       priv->ucode_loaded = false;
+
+       /* Set the FW error flag -- cleared on iwl_down */
+       set_bit(STATUS_FW_ERROR, &priv->status);
+
+       iwl_abort_notification_waits(&priv->notif_wait);
+
+       /* Keep the restart process from trying to send host
+        * commands by clearing the ready bit */
+       clear_bit(STATUS_READY, &priv->status);
+
+       wake_up(&priv->trans->wait_command_queue);
+
+       if (!ondemand) {
+               /*
+                * If firmware keep reloading, then it indicate something
+                * serious wrong and firmware having problem to recover
+                * from it. Instead of keep trying which will fill the syslog
+                * and hang the system, let's just stop it
+                */
+               reload_jiffies = jiffies;
+               reload_msec = jiffies_to_msecs((long) reload_jiffies -
+                                       (long) priv->reload_jiffies);
+               priv->reload_jiffies = reload_jiffies;
+               if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+                       priv->reload_count++;
+                       if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+                               IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+                               return;
+                       }
+               } else
+                       priv->reload_count = 0;
+       }
+
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               if (iwlwifi_mod_params.restart_fw) {
+                       IWL_DEBUG_FW_ERRORS(priv,
+                                 "Restarting adapter due to uCode error.\n");
+                       queue_work(priv->workqueue, &priv->restart);
+               } else
+                       IWL_DEBUG_FW_ERRORS(priv,
+                                 "Detected FW error, but not restarting\n");
+       }
+}
+
+static void iwl_nic_error(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       IWL_ERR(priv, "Loaded firmware version: %s\n",
+               priv->fw->fw_version);
+
+       iwl_dump_nic_error_log(priv);
+       iwl_dump_nic_event_log(priv, false, NULL, false);
+
+       iwlagn_fw_error(priv, false);
+}
+
+static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       if (!iwl_check_for_ct_kill(priv)) {
+               IWL_ERR(priv, "Restarting adapter queue is full\n");
+               iwlagn_fw_error(priv, false);
+       }
+}
+
+#define EEPROM_RF_CONFIG_TYPE_MAX      0x3
+
+static void iwl_nic_config(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       u16 radio_cfg = priv->eeprom_data->radio_cfg;
+
+       /* SKU Control */
+       iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+                         CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
+                         CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP,
+                         (CSR_HW_REV_STEP(priv->trans->hw_rev) <<
+                               CSR_HW_IF_CONFIG_REG_POS_MAC_STEP) |
+                         (CSR_HW_REV_DASH(priv->trans->hw_rev) <<
+                               CSR_HW_IF_CONFIG_REG_POS_MAC_DASH));
+
+       /* write radio config values to register */
+       if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) {
+               u32 reg_val =
+                       EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <<
+                               CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE |
+                       EEPROM_RF_CFG_STEP_MSK(radio_cfg) <<
+                               CSR_HW_IF_CONFIG_REG_POS_PHY_STEP |
+                       EEPROM_RF_CFG_DASH_MSK(radio_cfg) <<
+                               CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
+
+               iwl_set_bits_mask(priv->trans, CSR_HW_IF_CONFIG_REG,
+                                 CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE |
+                                 CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP |
+                                 CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH, reg_val);
+
+               IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
+                        EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
+                        EEPROM_RF_CFG_STEP_MSK(radio_cfg),
+                        EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+       } else {
+               WARN_ON(1);
+       }
+
+       /* set CSR_HW_CONFIG_REG for uCode use */
+       iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
+                   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+                   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+       /* W/A : NIC is stuck in a reset state after Early PCIe power off
+        * (PCIe power is lost before PERST# is asserted),
+        * causing ME FW to lose ownership and not being able to obtain it back.
+        */
+       iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG,
+                              APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+                              ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+
+       if (priv->lib->nic_config)
+               priv->lib->nic_config(priv);
+}
+
+static void iwl_wimax_active(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       clear_bit(STATUS_READY, &priv->status);
+       IWL_ERR(priv, "RF is used by WiMAX\n");
+}
+
+static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int mq = priv->queue_to_mac80211[queue];
+
+       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+               return;
+
+       if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (mac80211 %d) already stopped\n",
+                       queue, mq);
+               return;
+       }
+
+       set_bit(mq, &priv->transport_queue_stop);
+       ieee80211_stop_queue(priv->hw, mq);
+}
+
+static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int mq = priv->queue_to_mac80211[queue];
+
+       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
+               return;
+
+       if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "queue %d (mac80211 %d) already awake\n",
+                       queue, mq);
+               return;
+       }
+
+       clear_bit(mq, &priv->transport_queue_stop);
+
+       if (!priv->passive_no_rx)
+               ieee80211_wake_queue(priv->hw, mq);
+}
+
+void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
+{
+       int mq;
+
+       if (!priv->passive_no_rx)
+               return;
+
+       for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) {
+               if (!test_bit(mq, &priv->transport_queue_stop)) {
+                       IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq);
+                       ieee80211_wake_queue(priv->hw, mq);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq);
+               }
+       }
+
+       priv->passive_no_rx = false;
+}
+
+static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       struct ieee80211_tx_info *info;
+
+       info = IEEE80211_SKB_CB(skb);
+       iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+       dev_kfree_skb_any(skb);
+}
+
+static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+
+       if (state)
+               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, state);
+}
+
+static const struct iwl_op_mode_ops iwl_dvm_ops = {
+       .start = iwl_op_mode_dvm_start,
+       .stop = iwl_op_mode_dvm_stop,
+       .rx = iwl_rx_dispatch,
+       .queue_full = iwl_stop_sw_queue,
+       .queue_not_full = iwl_wake_sw_queue,
+       .hw_rf_kill = iwl_set_hw_rfkill_state,
+       .free_skb = iwl_free_skb,
+       .nic_error = iwl_nic_error,
+       .cmd_queue_full = iwl_cmd_queue_full,
+       .nic_config = iwl_nic_config,
+       .wimax_active = iwl_wimax_active,
+};
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+static int __init iwl_init(void)
+{
+
+       int ret;
+       pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+       pr_info(DRV_COPYRIGHT "\n");
+
+       ret = iwlagn_rate_control_register();
+       if (ret) {
+               pr_err("Unable to register rate control algorithm: %d\n", ret);
+               return ret;
+       }
+
+       ret = iwl_opmode_register("iwldvm", &iwl_dvm_ops);
+       if (ret) {
+               pr_err("Unable to register op_mode: %d\n", ret);
+               iwlagn_rate_control_unregister();
+       }
+
+       return ret;
+}
+module_init(iwl_init);
+
+static void __exit iwl_exit(void)
+{
+       iwl_opmode_deregister("iwldvm");
+       iwlagn_rate_control_unregister();
+}
+module_exit(iwl_exit);
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c
new file mode 100644 (file)
index 0000000..518cf37
--- /dev/null
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/slab.h>
+#include <linux/init.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-debug.h"
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+#include "commands.h"
+#include "power.h"
+
+/*
+ * Setting power level allows the card to go to sleep when not busy.
+ *
+ * We calculate a sleep command based on the required latency, which
+ * we get from mac80211. In order to handle thermal throttling, we can
+ * also use pre-defined power levels.
+ */
+
+/*
+ * This defines the old power levels. They are still used by default
+ * (level 1) and for thermal throttle (levels 3 through 5)
+ */
+
+struct iwl_power_vec_entry {
+       struct iwl_powertable_cmd cmd;
+       u8 no_dtim;     /* number of skip dtim */
+};
+
+#define IWL_DTIM_RANGE_0_MAX   2
+#define IWL_DTIM_RANGE_1_MAX   10
+
+#define NOSLP cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK |   \
+               IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
+               IWL_POWER_ADVANCE_PM_ENA_MSK)
+#define ASLP_TOUT(T) cpu_to_le32(T)
+#define TU_TO_USEC 1024
+#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
+                                    cpu_to_le32(X1), \
+                                    cpu_to_le32(X2), \
+                                    cpu_to_le32(X3), \
+                                    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, 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},
+       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
+};
+
+
+/* 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, 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},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+/* advance power management */
+/* DTIM 0 - 2 */
+static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
+
+/* 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 apm_range_1[IWL_POWER_NUM] = {
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
+};
+
+/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
+static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
+       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
+               SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
+};
+
+static void iwl_static_sleep_cmd(struct iwl_priv *priv,
+                                struct iwl_powertable_cmd *cmd,
+                                enum iwl_power_level lvl, int period)
+{
+       const struct iwl_power_vec_entry *table;
+       int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
+       int i;
+       u8 skip;
+       u32 slp_itrvl;
+
+       if (priv->cfg->adv_pm) {
+               table = apm_range_2;
+               if (period <= IWL_DTIM_RANGE_1_MAX)
+                       table = apm_range_1;
+               if (period <= IWL_DTIM_RANGE_0_MAX)
+                       table = apm_range_0;
+       } else {
+               table = range_2;
+               if (period <= IWL_DTIM_RANGE_1_MAX)
+                       table = range_1;
+               if (period <= IWL_DTIM_RANGE_0_MAX)
+                       table = range_0;
+       }
+
+       if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
+               memset(cmd, 0, sizeof(*cmd));
+       else
+               *cmd = table[lvl].cmd;
+
+       if (period == 0) {
+               skip = 0;
+               period = 1;
+               for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+                       max_sleep[i] =  1;
+
+       } else {
+               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;
+       }
+
+       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
+               cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+
+       if (priv->cfg->base_params->shadow_reg_enable)
+               cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
+       else
+               cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
+
+       if (iwl_advanced_bt_coexist(priv)) {
+               if (!priv->cfg->bt_params->bt_sco_disable)
+                       cmd->flags |= IWL_POWER_BT_SCO_ENA;
+               else
+                       cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
+       }
+
+
+       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.bus_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);
+       /* The power level here is 0-4 (used as array index), but user expects
+       to see 1-5 (according to spec). */
+       IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
+}
+
+static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
+                                   struct iwl_powertable_cmd *cmd)
+{
+       memset(cmd, 0, sizeof(*cmd));
+
+       if (priv->power_data.bus_pm)
+               cmd->flags |= IWL_POWER_PCI_PM_MSK;
+
+       IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
+}
+
+static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
+{
+       IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
+       IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
+       IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+       IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+       IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+                       le32_to_cpu(cmd->sleep_interval[0]),
+                       le32_to_cpu(cmd->sleep_interval[1]),
+                       le32_to_cpu(cmd->sleep_interval[2]),
+                       le32_to_cpu(cmd->sleep_interval[3]),
+                       le32_to_cpu(cmd->sleep_interval[4]));
+
+       return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
+                               sizeof(struct iwl_powertable_cmd), cmd);
+}
+
+static void iwl_power_build_cmd(struct iwl_priv *priv,
+                               struct iwl_powertable_cmd *cmd)
+{
+       bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
+       int dtimper;
+
+       dtimper = priv->hw->conf.ps_dtim_period ?: 1;
+
+       if (priv->wowlan)
+               iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
+       else if (!priv->cfg->base_params->no_idle_support &&
+                priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+               iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
+       else if (iwl_tt_is_low_power_state(priv)) {
+               /* in thermal throttling low power state */
+               iwl_static_sleep_cmd(priv, cmd,
+                   iwl_tt_current_power_mode(priv), dtimper);
+       } else if (!enabled)
+               iwl_power_sleep_cam_cmd(priv, cmd);
+       else if (priv->power_data.debug_sleep_level_override >= 0)
+               iwl_static_sleep_cmd(priv, cmd,
+                                    priv->power_data.debug_sleep_level_override,
+                                    dtimper);
+       else {
+               /* Note that the user parameter is 1-5 (according to spec),
+               but we pass 0-4 because it acts as an array index. */
+               if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
+                   iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
+                       iwl_static_sleep_cmd(priv, cmd,
+                               iwlwifi_mod_params.power_level - 1, dtimper);
+               else
+                       iwl_static_sleep_cmd(priv, cmd,
+                               IWL_POWER_INDEX_1, dtimper);
+       }
+}
+
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+                      bool force)
+{
+       int ret;
+       bool update_chains;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /* Don't update the RX chain when chain noise calibration is running */
+       update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
+                       priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
+
+       if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
+               return 0;
+
+       if (!iwl_is_ready_rf(priv))
+               return -EIO;
+
+       /* scan complete use sleep_power_next, need to be updated */
+       memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
+       if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
+               IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
+               return 0;
+       }
+
+       if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
+               iwl_dvm_set_pmi(priv, true);
+
+       ret = iwl_set_power(priv, cmd);
+       if (!ret) {
+               if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
+                       iwl_dvm_set_pmi(priv, false);
+
+               if (update_chains)
+                       iwl_update_chain_flags(priv);
+               else
+                       IWL_DEBUG_POWER(priv,
+                                       "Cannot update the power, chain noise "
+                                       "calibration running: %d\n",
+                                       priv->chain_noise_data.state);
+
+               memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
+       } else
+               IWL_ERR(priv, "set power fail, ret = %d", ret);
+
+       return ret;
+}
+
+int iwl_power_update_mode(struct iwl_priv *priv, bool force)
+{
+       struct iwl_powertable_cmd cmd;
+
+       iwl_power_build_cmd(priv, &cmd);
+       return iwl_power_set_mode(priv, &cmd, force);
+}
+
+/* initialize to default */
+void iwl_power_initialize(struct iwl_priv *priv)
+{
+       priv->power_data.bus_pm = priv->trans->pm_support;
+
+       priv->power_data.debug_sleep_level_override = -1;
+
+       memset(&priv->power_data.sleep_cmd, 0,
+               sizeof(priv->power_data.sleep_cmd));
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h
new file mode 100644 (file)
index 0000000..a2cee7f
--- /dev/null
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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_power_setting_h__
+#define __iwl_power_setting_h__
+
+#include "commands.h"
+
+struct iwl_power_mgr {
+       struct iwl_powertable_cmd sleep_cmd;
+       struct iwl_powertable_cmd sleep_cmd_next;
+       int debug_sleep_level_override;
+       bool bus_pm;
+};
+
+int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
+                      bool force);
+int iwl_power_update_mode(struct iwl_priv *priv, bool force);
+void iwl_power_initialize(struct iwl_priv *priv);
+
+extern bool no_sleep_autoadjust;
+
+#endif  /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
new file mode 100644 (file)
index 0000000..6fddd27
--- /dev/null
@@ -0,0 +1,3367 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2012 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/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/mac80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include "dev.h"
+#include "agn.h"
+
+#define RS_NAME "iwl-agn-rs"
+
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define IWL_NUMBER_TRY      1
+#define IWL_HT_NUMBER_TRY   3
+
+#define IWL_RATE_MAX_WINDOW            62      /* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH                6       /* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH                8       /* min successes to calc tpt */
+
+/* max allowed rate miss before sync LQ cmd */
+#define IWL_MISSED_RATE_MAX            15
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
+
+static u8 rs_ht_to_legacy[] = {
+       IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+       IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+       IWL_RATE_6M_INDEX,
+       IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+       IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+       IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+       IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+static const u8 ant_toggle_lookup[] = {
+       /*ANT_NONE -> */ ANT_NONE,
+       /*ANT_A    -> */ ANT_B,
+       /*ANT_B    -> */ ANT_C,
+       /*ANT_AB   -> */ ANT_BC,
+       /*ANT_C    -> */ ANT_A,
+       /*ANT_AC   -> */ ANT_AB,
+       /*ANT_BC   -> */ ANT_AC,
+       /*ANT_ABC  -> */ ANT_ABC,
+};
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+       [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
+                                   IWL_RATE_SISO_##s##M_PLCP, \
+                                   IWL_RATE_MIMO2_##s##M_PLCP,\
+                                   IWL_RATE_MIMO3_##s##M_PLCP,\
+                                   IWL_RATE_##r##M_IEEE,      \
+                                   IWL_RATE_##ip##M_INDEX,    \
+                                   IWL_RATE_##in##M_INDEX,    \
+                                   IWL_RATE_##rp##M_INDEX,    \
+                                   IWL_RATE_##rn##M_INDEX,    \
+                                   IWL_RATE_##pp##M_INDEX,    \
+                                   IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+       IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+       IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+       IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+       IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
+       IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+       IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
+       IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+       IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+       IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+       IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+       IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+       IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+       IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+       /* FIXME:RS:          ^^    should be INV (legacy) */
+};
+
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+       return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
+}
+
+static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
+{
+       int idx = 0;
+
+       /* HT rate format */
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               idx = rs_extract_rate(rate_n_flags);
+
+               if (idx >= IWL_RATE_MIMO3_6M_PLCP)
+                       idx = idx - IWL_RATE_MIMO3_6M_PLCP;
+               else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+                       idx = idx - IWL_RATE_MIMO2_6M_PLCP;
+
+               idx += IWL_FIRST_OFDM_RATE;
+               /* skip 9M not supported in ht*/
+               if (idx >= IWL_RATE_9M_INDEX)
+                       idx += 1;
+               if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
+                       return idx;
+
+       /* legacy rate format, search for match in table */
+       } else {
+               for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+                       if (iwl_rates[idx].plcp ==
+                                       rs_extract_rate(rate_n_flags))
+                               return idx;
+       }
+
+       return -1;
+}
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+                                  struct sk_buff *skb,
+                                  struct ieee80211_sta *sta,
+                                  struct iwl_lq_sta *lq_sta);
+static void rs_fill_link_cmd(struct iwl_priv *priv,
+                            struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+                            u32 *rate_n_flags, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+                            u32 *rate_n_flags, int index)
+{}
+#endif
+
+/**
+ * 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_legacy[IWL_RATE_COUNT] = {
+       7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
+};
+
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+       {0, 0, 0, 0, 42, 0,  76, 102, 124, 159, 183, 193, 202}, /* Norm */
+       {0, 0, 0, 0, 46, 0,  82, 110, 132, 168, 192, 202, 210}, /* SGI */
+       {0, 0, 0, 0, 47, 0,  91, 133, 171, 242, 305, 334, 362}, /* AGG */
+       {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
+};
+
+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,  94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
+       {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
+};
+
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+       {0, 0, 0, 0,  74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
+       {0, 0, 0, 0,  81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
+       {0, 0, 0, 0,  89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
+       {0, 0, 0, 0,  97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
+};
+
+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, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
+       {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
+};
+
+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_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 */
+static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
+       {  "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)
+
+static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+       window->data = 0;
+       window->success_counter = 0;
+       window->success_ratio = IWL_INVALID_VALUE;
+       window->counter = 0;
+       window->average_tpt = IWL_INVALID_VALUE;
+       window->stamp = 0;
+}
+
+static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
+{
+       return (ant_type & valid_antenna) == ant_type;
+}
+
+/*
+ *     removes the old data from the statistics. All data that is older than
+ *     TID_MAX_TIME_DIFF, will be deleted.
+ */
+static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
+{
+       /* The oldest age we want to keep */
+       u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
+
+       while (tl->queue_count &&
+              (tl->time_stamp < oldest_time)) {
+               tl->total -= tl->packet_count[tl->head];
+               tl->packet_count[tl->head] = 0;
+               tl->time_stamp += TID_QUEUE_CELL_SPACING;
+               tl->queue_count--;
+               tl->head++;
+               if (tl->head >= TID_QUEUE_MAX_SIZE)
+                       tl->head = 0;
+       }
+}
+
+/*
+ *     increment traffic load value for tid and also remove
+ *     any old values if passed the certain time period
+ */
+static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
+                          struct ieee80211_hdr *hdr)
+{
+       u32 curr_time = jiffies_to_msecs(jiffies);
+       u32 time_diff;
+       s32 index;
+       struct iwl_traffic_load *tl = NULL;
+       u8 tid;
+
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               u8 *qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & 0xf;
+       } else
+               return IWL_MAX_TID_COUNT;
+
+       if (unlikely(tid >= IWL_MAX_TID_COUNT))
+               return IWL_MAX_TID_COUNT;
+
+       tl = &lq_data->load[tid];
+
+       curr_time -= curr_time % TID_ROUND_VALUE;
+
+       /* Happens only for the first packet. Initialize the data */
+       if (!(tl->queue_count)) {
+               tl->total = 1;
+               tl->time_stamp = curr_time;
+               tl->queue_count = 1;
+               tl->head = 0;
+               tl->packet_count[0] = 1;
+               return IWL_MAX_TID_COUNT;
+       }
+
+       time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+       index = time_diff / TID_QUEUE_CELL_SPACING;
+
+       /* The history is too long: remove data that is older than */
+       /* TID_MAX_TIME_DIFF */
+       if (index >= TID_QUEUE_MAX_SIZE)
+               rs_tl_rm_old_stats(tl, curr_time);
+
+       index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
+       tl->packet_count[index] = tl->packet_count[index] + 1;
+       tl->total = tl->total + 1;
+
+       if ((index + 1) > tl->queue_count)
+               tl->queue_count = index + 1;
+
+       return tid;
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_priv *priv,
+                               struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
+       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+       /* testmode has higher priority to overwirte the fixed rate */
+       if (priv->tm_fixed_rate)
+               lq_sta->dbg_fixed_rate = priv->tm_fixed_rate;
+#endif
+
+       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
+               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+       if (lq_sta->dbg_fixed_rate) {
+               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
+               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+                               false);
+       }
+}
+#endif
+
+/*
+       get the traffic load value for tid
+*/
+static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
+{
+       u32 curr_time = jiffies_to_msecs(jiffies);
+       u32 time_diff;
+       s32 index;
+       struct iwl_traffic_load *tl = NULL;
+
+       if (tid >= IWL_MAX_TID_COUNT)
+               return 0;
+
+       tl = &(lq_data->load[tid]);
+
+       curr_time -= curr_time % TID_ROUND_VALUE;
+
+       if (!(tl->queue_count))
+               return 0;
+
+       time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
+       index = time_diff / TID_QUEUE_CELL_SPACING;
+
+       /* The history is too long: remove data that is older than */
+       /* TID_MAX_TIME_DIFF */
+       if (index >= TID_QUEUE_MAX_SIZE)
+               rs_tl_rm_old_stats(tl, curr_time);
+
+       return tl->total;
+}
+
+static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
+                                     struct iwl_lq_sta *lq_data, u8 tid,
+                                     struct ieee80211_sta *sta)
+{
+       int ret = -EAGAIN;
+       u32 load;
+
+       /*
+        * Don't create TX aggregation sessions when in high
+        * BT traffic, as they would just be disrupted by BT.
+        */
+       if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+               IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+                       priv->bt_traffic_load);
+               return ret;
+       }
+
+       load = rs_tl_get_load(lq_data, tid);
+
+       if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
+               IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
+                               sta->addr, tid);
+               ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
+               if (ret == -EAGAIN) {
+                       /*
+                        * driver and mac80211 is out of sync
+                        * this might be cause by reloading firmware
+                        * stop the tx ba session here
+                        */
+                       IWL_ERR(priv, "Fail start Tx agg on tid: %d\n",
+                               tid);
+                       ieee80211_stop_tx_ba_session(sta, tid);
+               }
+       } else {
+               IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d "
+                       "because load = %u\n", tid, load);
+       }
+       return ret;
+}
+
+static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
+                             struct iwl_lq_sta *lq_data,
+                             struct ieee80211_sta *sta)
+{
+       if (tid < IWL_MAX_TID_COUNT)
+               rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+       else
+               IWL_ERR(priv, "tid exceeds max TID count: %d/%d\n",
+                       tid, IWL_MAX_TID_COUNT);
+}
+
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+       return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+              !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+              !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
+}
+
+/*
+ * 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;
+}
+
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+                             int scale_index, int attempts, int successes)
+{
+       struct iwl_rate_scale_data *window = NULL;
+       static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
+       s32 fail_count, tpt;
+
+       if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+               return -EINVAL;
+
+       /* Select window for current tx bit rate */
+       window = &(tbl->win[scale_index]);
+
+       /* Get expected throughput */
+       tpt = get_expected_tpt(tbl, scale_index);
+
+       /*
+        * Keep track of only the latest 62 tx frame attempts in this rate's
+        * history window; anything older isn't really relevant any more.
+        * If we have filled up the sliding window, drop the oldest attempt;
+        * if the oldest attempt (highest bit in bitmap) shows "success",
+        * subtract "1" from the success counter (this is the main reason
+        * we keep these bitmaps!).
+        */
+       while (attempts > 0) {
+               if (window->counter >= IWL_RATE_MAX_WINDOW) {
+
+                       /* remove earliest */
+                       window->counter = IWL_RATE_MAX_WINDOW - 1;
+
+                       if (window->data & mask) {
+                               window->data &= ~mask;
+                               window->success_counter--;
+                       }
+               }
+
+               /* Increment frames-attempted counter */
+               window->counter++;
+
+               /* 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--;
+               }
+
+               attempts--;
+       }
+
+       /* Calculate current success ratio, avoid divide-by-0! */
+       if (window->counter > 0)
+               window->success_ratio = 128 * (100 * window->success_counter)
+                                       / window->counter;
+       else
+               window->success_ratio = IWL_INVALID_VALUE;
+
+       fail_count = window->counter - window->success_counter;
+
+       /* Calculate average throughput, if we have enough history. */
+       if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+           (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+               window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+       else
+               window->average_tpt = IWL_INVALID_VALUE;
+
+       /* Tag this window as having been updated */
+       window->stamp = jiffies;
+
+       return 0;
+}
+
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
+                                struct iwl_scale_tbl_info *tbl,
+                                int index, u8 use_green)
+{
+       u32 rate_n_flags = 0;
+
+       if (is_legacy(tbl->lq_type)) {
+               rate_n_flags = iwl_rates[index].plcp;
+               if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+                       rate_n_flags |= RATE_MCS_CCK_MSK;
+
+       } else if (is_Ht(tbl->lq_type)) {
+               if (index > IWL_LAST_OFDM_RATE) {
+                       IWL_ERR(priv, "Invalid HT rate index %d\n", index);
+                       index = IWL_LAST_OFDM_RATE;
+               }
+               rate_n_flags = RATE_MCS_HT_MSK;
+
+               if (is_siso(tbl->lq_type))
+                       rate_n_flags |= iwl_rates[index].plcp_siso;
+               else if (is_mimo2(tbl->lq_type))
+                       rate_n_flags |= iwl_rates[index].plcp_mimo2;
+               else
+                       rate_n_flags |= iwl_rates[index].plcp_mimo3;
+       } else {
+               IWL_ERR(priv, "Invalid tbl->lq_type %d\n", tbl->lq_type);
+       }
+
+       rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+                                                    RATE_MCS_ANT_ABC_MSK);
+
+       if (is_Ht(tbl->lq_type)) {
+               if (tbl->is_ht40) {
+                       if (tbl->is_dup)
+                               rate_n_flags |= RATE_MCS_DUP_MSK;
+                       else
+                               rate_n_flags |= RATE_MCS_HT40_MSK;
+               }
+               if (tbl->is_SGI)
+                       rate_n_flags |= RATE_MCS_SGI_MSK;
+
+               if (use_green) {
+                       rate_n_flags |= RATE_MCS_GF_MSK;
+                       if (is_siso(tbl->lq_type) && tbl->is_SGI) {
+                               rate_n_flags &= ~RATE_MCS_SGI_MSK;
+                               IWL_ERR(priv, "GF was set with SGI:SISO\n");
+                       }
+               }
+       }
+       return rate_n_flags;
+}
+
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
+                                   enum ieee80211_band band,
+                                   struct iwl_scale_tbl_info *tbl,
+                                   int *rate_idx)
+{
+       u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
+       u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+       u8 mcs;
+
+       memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
+       *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+
+       if (*rate_idx  == IWL_RATE_INVALID) {
+               *rate_idx = -1;
+               return -EINVAL;
+       }
+       tbl->is_SGI = 0;        /* default legacy setup */
+       tbl->is_ht40 = 0;
+       tbl->is_dup = 0;
+       tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
+       tbl->lq_type = LQ_NONE;
+       tbl->max_search = IWL_MAX_SEARCH;
+
+       /* legacy rate format */
+       if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
+               if (num_of_ant == 1) {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               tbl->lq_type = LQ_A;
+                       else
+                               tbl->lq_type = LQ_G;
+               }
+       /* HT rate format */
+       } else {
+               if (rate_n_flags & RATE_MCS_SGI_MSK)
+                       tbl->is_SGI = 1;
+
+               if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
+                   (rate_n_flags & RATE_MCS_DUP_MSK))
+                       tbl->is_ht40 = 1;
+
+               if (rate_n_flags & RATE_MCS_DUP_MSK)
+                       tbl->is_dup = 1;
+
+               mcs = rs_extract_rate(rate_n_flags);
+
+               /* SISO */
+               if (mcs <= IWL_RATE_SISO_60M_PLCP) {
+                       if (num_of_ant == 1)
+                               tbl->lq_type = LQ_SISO; /*else NONE*/
+               /* MIMO2 */
+               } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
+                       if (num_of_ant == 2)
+                               tbl->lq_type = LQ_MIMO2;
+               /* MIMO3 */
+               } else {
+                       if (num_of_ant == 3) {
+                               tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+                               tbl->lq_type = LQ_MIMO3;
+                       }
+               }
+       }
+       return 0;
+}
+
+/* switch to another antenna/antennas and return 1 */
+/* if no other valid antenna found, return 0 */
+static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
+                            struct iwl_scale_tbl_info *tbl)
+{
+       u8 new_ant_type;
+
+       if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+               return 0;
+
+       if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+               return 0;
+
+       new_ant_type = ant_toggle_lookup[tbl->ant_type];
+
+       while ((new_ant_type != tbl->ant_type) &&
+              !rs_is_valid_ant(valid_ant, new_ant_type))
+               new_ant_type = ant_toggle_lookup[new_ant_type];
+
+       if (new_ant_type == tbl->ant_type)
+               return 0;
+
+       tbl->ant_type = new_ant_type;
+       *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
+       *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+       return 1;
+}
+
+/**
+ * Green-field mode is valid if the station supports it and
+ * there are no non-GF stations present in the BSS.
+ */
+static bool rs_use_green(struct ieee80211_sta *sta)
+{
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
+               !(ctx->ht.non_gf_sta_present);
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
+                                 struct ieee80211_hdr *hdr,
+                                 enum iwl_table_type rate_type)
+{
+       if (is_legacy(rate_type)) {
+               return lq_sta->active_legacy_rate;
+       } else {
+               if (is_siso(rate_type))
+                       return lq_sta->active_siso_rate;
+               else if (is_mimo2(rate_type))
+                       return lq_sta->active_mimo2_rate;
+               else
+                       return lq_sta->active_mimo3_rate;
+       }
+}
+
+static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
+                               int rate_type)
+{
+       u8 high = IWL_RATE_INVALID;
+       u8 low = IWL_RATE_INVALID;
+
+       /* 802.11A or ht walks to the next literal adjacent rate in
+        * the rate table */
+       if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+               int i;
+               u32 mask;
+
+               /* Find the previous rate that is in the rate mask */
+               i = index - 1;
+               for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+                       if (rate_mask & mask) {
+                               low = i;
+                               break;
+                       }
+               }
+
+               /* Find the next rate that is in the rate mask */
+               i = index + 1;
+               for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+                       if (rate_mask & mask) {
+                               high = i;
+                               break;
+                       }
+               }
+
+               return (high << 8) | low;
+       }
+
+       low = index;
+       while (low != IWL_RATE_INVALID) {
+               low = iwl_rates[low].prev_rs;
+               if (low == IWL_RATE_INVALID)
+                       break;
+               if (rate_mask & (1 << low))
+                       break;
+               IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low);
+       }
+
+       high = index;
+       while (high != IWL_RATE_INVALID) {
+               high = iwl_rates[high].next_rs;
+               if (high == IWL_RATE_INVALID)
+                       break;
+               if (rate_mask & (1 << high))
+                       break;
+               IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high);
+       }
+
+       return (high << 8) | low;
+}
+
+static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+                            struct iwl_scale_tbl_info *tbl,
+                            u8 scale_index, u8 ht_possible)
+{
+       s32 low;
+       u16 rate_mask;
+       u16 high_low;
+       u8 switch_to_legacy = 0;
+       u8 is_green = lq_sta->is_green;
+       struct iwl_priv *priv = lq_sta->drv;
+
+       /* check if we need to switch from HT to legacy rates.
+        * assumption is that mandatory rates (1Mbps or 6Mbps)
+        * are always supported (spec demand) */
+       if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+               switch_to_legacy = 1;
+               scale_index = rs_ht_to_legacy[scale_index];
+               if (lq_sta->band == IEEE80211_BAND_5GHZ)
+                       tbl->lq_type = LQ_A;
+               else
+                       tbl->lq_type = LQ_G;
+
+               if (num_of_ant(tbl->ant_type) > 1)
+                       tbl->ant_type =
+                           first_antenna(priv->eeprom_data->valid_tx_ant);
+
+               tbl->is_ht40 = 0;
+               tbl->is_SGI = 0;
+               tbl->max_search = IWL_MAX_SEARCH;
+       }
+
+       rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
+
+       /* Mask with station rate restriction */
+       if (is_legacy(tbl->lq_type)) {
+               /* supp_rates has no CCK bits in A mode */
+               if (lq_sta->band == IEEE80211_BAND_5GHZ)
+                       rate_mask  = (u16)(rate_mask &
+                          (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+               else
+                       rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
+       }
+
+       /* If we switched from HT to legacy, check current rate */
+       if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
+               low = scale_index;
+               goto out;
+       }
+
+       high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+                                       tbl->lq_type);
+       low = high_low & 0xff;
+
+       if (low == IWL_RATE_INVALID)
+               low = scale_index;
+
+out:
+       return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
+}
+
+/*
+ * 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 void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_scale_tbl_info *tbl;
+       bool full_concurrent = priv->bt_full_concurrent;
+
+       if (priv->bt_ant_couple_ok) {
+               /*
+                * Is there a need to switch between
+                * full concurrency and 3-wire?
+                */
+               if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
+                       full_concurrent = true;
+               else
+                       full_concurrent = false;
+       }
+       if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
+           (priv->bt_full_concurrent != full_concurrent)) {
+               priv->bt_full_concurrent = full_concurrent;
+               priv->last_bt_traffic_load = priv->bt_traffic_load;
+
+               /* Update uCode's rate table. */
+               tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+               iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+
+               queue_work(priv->workqueue, &priv->bt_full_concurrency);
+       }
+}
+
+/*
+ * 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 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_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       enum mac80211_rate_control_flags mac_flags;
+       u32 tx_rate;
+       struct iwl_scale_tbl_info tbl_type;
+       struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
+
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (!lq_sta) {
+               IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n");
+               return;
+       } else if (!lq_sta->drv) {
+               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+               return;
+       }
+
+       if (!ieee80211_is_data(hdr->frame_control) ||
+           info->flags & IEEE80211_TX_CTL_NO_ACK)
+               return;
+
+       /* This packet was aggregated but doesn't carry status info */
+       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(info->flags & IEEE80211_TX_STAT_AMPDU))
+               return;
+
+       /*
+        * Ignore this Tx frame response if its initial rate doesn't match
+        * that of latest Link Quality command.  There may be stragglers
+        * from a previous Link Quality command, but we're no longer interested
+        * in those; they're either from the "active" mode while we're trying
+        * 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)
+               rs_index -= IWL_FIRST_OFDM_RATE;
+       mac_flags = info->status.rates[0].flags;
+       mac_index = info->status.rates[0].idx;
+       /* For HT packets, map MCS to PLCP */
+       if (mac_flags & IEEE80211_TX_RC_MCS) {
+               mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */
+               if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
+                       mac_index++;
+               /*
+                * mac80211 HT index is always zero-indexed; we need to move
+                * HT OFDM rates after CCK rates in 2.4 GHz band
+                */
+               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)) ||
+           (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
+           (tbl_type.ant_type != info->status.antenna) ||
+           (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
+           (!!(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);
+               /*
+                * 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, ctx, &lq_sta->lq, CMD_ASYNC, false);
+               }
+               /* 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");
+               tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
+                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+               tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+               IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
+                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+               IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
+                       tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
+               /*
+                * no matching table found, let's by-pass the data collection
+                * and continue to perform rate scale to find the rate table
+                */
+               rs_stay_in_table(lq_sta, true);
+               goto done;
+       }
+
+       /*
+        * 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);
+               rs_collect_tx_data(curr_tbl, rs_index,
+                                  info->status.ampdu_len,
+                                  info->status.ampdu_ack_len);
+
+               /* Update success/fail counts if not searching for new mode */
+               if (lq_sta->stay_in_tbl) {
+                       lq_sta->total_success += info->status.ampdu_ack_len;
+                       lq_sta->total_failed += (info->status.ampdu_len -
+                                       info->status.ampdu_ack_len);
+               }
+       } else {
+       /*
+        * For legacy, update frame history with for each Tx retry.
+        */
+               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))
+                               tmp_tbl = curr_tbl;
+                       else if (table_type_matches(&tbl_type, other_tbl))
+                               tmp_tbl = other_tbl;
+                       else
+                               continue;
+                       rs_collect_tx_data(tmp_tbl, rs_index, 1,
+                                          i < retries ? 0 : 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;
+done:
+       /* 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);
+
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_TESTMODE)
+       if ((priv->tm_fixed_rate) &&
+           (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
+               rs_program_fix_rate(priv, lq_sta);
+#endif
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
+               rs_bt_update_lq(priv, ctx, lq_sta);
+}
+
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
+static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
+                                struct iwl_lq_sta *lq_sta)
+{
+       IWL_DEBUG_RATE(priv, "we are staying in the same table\n");
+       lq_sta->stay_in_tbl = 1;        /* only place this gets set */
+       if (is_legacy) {
+               lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+               lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+               lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+       } else {
+               lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+               lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+               lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+       }
+       lq_sta->table_count = 0;
+       lq_sta->total_failed = 0;
+       lq_sta->total_success = 0;
+       lq_sta->flush_timer = jiffies;
+       lq_sta->action_counter = 0;
+}
+
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+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)) {
+               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];
+}
+
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput.  When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl_priv *priv,
+                           struct iwl_lq_sta *lq_sta,
+                           struct iwl_scale_tbl_info *tbl,     /* "search" */
+                           u16 rate_mask, s8 index)
+{
+       /* "active" values */
+       struct iwl_scale_tbl_info *active_tbl =
+           &(lq_sta->lq_info[lq_sta->active_tbl]);
+       s32 active_sr = active_tbl->win[index].success_ratio;
+       s32 active_tpt = active_tbl->expected_tpt[index];
+
+       /* expected "search" throughput */
+       s32 *tpt_tbl = tbl->expected_tpt;
+
+       s32 new_rate, high, low, start_hi;
+       u16 high_low;
+       s8 rate = index;
+
+       new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+       for (; ;) {
+               high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
+                                               tbl->lq_type);
+
+               low = high_low & 0xff;
+               high = (high_low >> 8) & 0xff;
+
+               /*
+                * Lower the "search" bit rate, to give new "search" mode
+                * approximately the same throughput as "active" if:
+                *
+                * 1) "Active" mode has been working modestly well (but not
+                *    great), and expected "search" throughput (under perfect
+                *    conditions) at candidate rate is above the actual
+                *    measured "active" throughput (but less than expected
+                *    "active" throughput under perfect conditions).
+                * OR
+                * 2) "Active" mode has been working perfectly or very well
+                *    and expected "search" throughput (under perfect
+                *    conditions) at candidate rate is above expected
+                *    "active" throughput (under perfect conditions).
+                */
+               if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
+                    ((active_sr > IWL_RATE_DECREASE_TH) &&
+                     (active_sr <= IWL_RATE_HIGH_TH) &&
+                     (tpt_tbl[rate] <= active_tpt))) ||
+                   ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+                    (tpt_tbl[rate] > active_tpt))) {
+
+                       /* (2nd or later pass)
+                        * If we've already tried to raise the rate, and are
+                        * now trying to lower it, use the higher rate. */
+                       if (start_hi != IWL_RATE_INVALID) {
+                               new_rate = start_hi;
+                               break;
+                       }
+
+                       new_rate = rate;
+
+                       /* Loop again with lower rate */
+                       if (low != IWL_RATE_INVALID)
+                               rate = low;
+
+                       /* Lower rate not available, use the original */
+                       else
+                               break;
+
+               /* Else try to raise the "search" rate to match "active" */
+               } else {
+                       /* (2nd or later pass)
+                        * If we've already tried to lower the rate, and are
+                        * now trying to raise it, use the lower rate. */
+                       if (new_rate != IWL_RATE_INVALID)
+                               break;
+
+                       /* Loop again with higher rate */
+                       else if (high != IWL_RATE_INVALID) {
+                               start_hi = high;
+                               rate = high;
+
+                       /* Higher rate not available, use the original */
+                       } else {
+                               new_rate = rate;
+                               break;
+                       }
+               }
+       }
+
+       return new_rate;
+}
+
+/*
+ * Set up search table for MIMO2
+ */
+static int rs_switch_to_mimo2(struct iwl_priv *priv,
+                            struct iwl_lq_sta *lq_sta,
+                            struct ieee80211_conf *conf,
+                            struct ieee80211_sta *sta,
+                            struct iwl_scale_tbl_info *tbl, int index)
+{
+       u16 rate_mask;
+       s32 rate;
+       s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+               return -1;
+
+       if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+                                               == WLAN_HT_CAP_SM_PS_STATIC)
+               return -1;
+
+       /* Need both Tx chains/antennas to support MIMO */
+       if (priv->hw_params.tx_chains_num < 2)
+               return -1;
+
+       IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
+
+       tbl->lq_type = LQ_MIMO2;
+       tbl->is_dup = lq_sta->is_dup;
+       tbl->action = 0;
+       tbl->max_search = IWL_MAX_SEARCH;
+       rate_mask = lq_sta->active_mimo2_rate;
+
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+               tbl->is_ht40 = 1;
+       else
+               tbl->is_ht40 = 0;
+
+       rs_set_expected_tpt_table(lq_sta, tbl);
+
+       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+       IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
+       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+               IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
+                                               rate, rate_mask);
+               return -1;
+       }
+       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+
+       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+                    tbl->current_rate, is_green);
+       return 0;
+}
+
+/*
+ * Set up search table for MIMO3
+ */
+static int rs_switch_to_mimo3(struct iwl_priv *priv,
+                            struct iwl_lq_sta *lq_sta,
+                            struct ieee80211_conf *conf,
+                            struct ieee80211_sta *sta,
+                            struct iwl_scale_tbl_info *tbl, int index)
+{
+       u16 rate_mask;
+       s32 rate;
+       s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+               return -1;
+
+       if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+                                               == WLAN_HT_CAP_SM_PS_STATIC)
+               return -1;
+
+       /* Need both Tx chains/antennas to support MIMO */
+       if (priv->hw_params.tx_chains_num < 3)
+               return -1;
+
+       IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
+
+       tbl->lq_type = LQ_MIMO3;
+       tbl->is_dup = lq_sta->is_dup;
+       tbl->action = 0;
+       tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
+       rate_mask = lq_sta->active_mimo3_rate;
+
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+               tbl->is_ht40 = 1;
+       else
+               tbl->is_ht40 = 0;
+
+       rs_set_expected_tpt_table(lq_sta, tbl);
+
+       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+       IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
+               rate, rate_mask);
+       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+               IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
+                                               rate, rate_mask);
+               return -1;
+       }
+       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+
+       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+                    tbl->current_rate, is_green);
+       return 0;
+}
+
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl_priv *priv,
+                            struct iwl_lq_sta *lq_sta,
+                            struct ieee80211_conf *conf,
+                            struct ieee80211_sta *sta,
+                            struct iwl_scale_tbl_info *tbl, int index)
+{
+       u16 rate_mask;
+       u8 is_green = lq_sta->is_green;
+       s32 rate;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
+               return -1;
+
+       IWL_DEBUG_RATE(priv, "LQ: try to switch to SISO\n");
+
+       tbl->is_dup = lq_sta->is_dup;
+       tbl->lq_type = LQ_SISO;
+       tbl->action = 0;
+       tbl->max_search = IWL_MAX_SEARCH;
+       rate_mask = lq_sta->active_siso_rate;
+
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+               tbl->is_ht40 = 1;
+       else
+               tbl->is_ht40 = 0;
+
+       if (is_green)
+               tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
+
+       rs_set_expected_tpt_table(lq_sta, tbl);
+       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
+
+       IWL_DEBUG_RATE(priv, "LQ: get best rate %d mask %X\n", rate, rate_mask);
+       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+               IWL_DEBUG_RATE(priv, "can not switch with index %d rate mask %x\n",
+                            rate, rate_mask);
+               return -1;
+       }
+       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
+       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
+                    tbl->current_rate, is_green);
+       return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl_priv *priv,
+                               struct iwl_lq_sta *lq_sta,
+                               struct ieee80211_conf *conf,
+                               struct ieee80211_sta *sta,
+                               int index)
+{
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+       struct iwl_scale_tbl_info *search_tbl =
+                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+       struct iwl_rate_scale_data *window = &(tbl->win[index]);
+       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+       u8 start_action;
+       u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+       int ret = 0;
+       u8 update_search_tbl_counter = 0;
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+                   tbl->action != IWL_LEGACY_SWITCH_SISO)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
+       if (!iwl_ht_enabled(priv))
+               /* stay in Legacy */
+               tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+       else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+                  tbl->action > IWL_LEGACY_SWITCH_SISO)
+               tbl->action = IWL_LEGACY_SWITCH_SISO;
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               if (!iwl_ht_enabled(priv))
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               valid_tx_ant =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+       }
+
+       start_action = tbl->action;
+       for (; ;) {
+               lq_sta->action_counter++;
+               switch (tbl->action) {
+               case IWL_LEGACY_SWITCH_ANTENNA1:
+               case IWL_LEGACY_SWITCH_ANTENNA2:
+                       IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
+
+                       if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
+                                                       tx_chains_num <= 1) ||
+                           (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
+                                                       tx_chains_num <= 2))
+                               break;
+
+                       /* Don't change antenna if success has been great */
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
+                               break;
+
+                       /* Set up search table to try other antenna */
+                       memcpy(search_tbl, tbl, sz);
+
+                       if (rs_toggle_antenna(valid_tx_ant,
+                               &search_tbl->current_rate, search_tbl)) {
+                               update_search_tbl_counter = 1;
+                               rs_set_expected_tpt_table(lq_sta, search_tbl);
+                               goto out;
+                       }
+                       break;
+               case IWL_LEGACY_SWITCH_SISO:
+                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to SISO\n");
+
+                       /* Set up search table to try SISO */
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret) {
+                               lq_sta->action_counter = 0;
+                               goto out;
+                       }
+
+                       break;
+               case IWL_LEGACY_SWITCH_MIMO2_AB:
+               case IWL_LEGACY_SWITCH_MIMO2_AC:
+               case IWL_LEGACY_SWITCH_MIMO2_BC:
+                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO2\n");
+
+                       /* Set up search table to try MIMO */
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+
+                       if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
+                               search_tbl->ant_type = ANT_AB;
+                       else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
+                               search_tbl->ant_type = ANT_AC;
+                       else
+                               search_tbl->ant_type = ANT_BC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret) {
+                               lq_sta->action_counter = 0;
+                               goto out;
+                       }
+                       break;
+
+               case IWL_LEGACY_SWITCH_MIMO3_ABC:
+                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
+
+                       /* Set up search table to try MIMO3 */
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+
+                       search_tbl->ant_type = ANT_ABC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret) {
+                               lq_sta->action_counter = 0;
+                               goto out;
+                       }
+                       break;
+               }
+               tbl->action++;
+               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+
+               if (tbl->action == start_action)
+                       break;
+
+       }
+       search_tbl->lq_type = LQ_NONE;
+       return 0;
+
+out:
+       lq_sta->search_better_tbl = 1;
+       tbl->action++;
+       if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+               tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+       if (update_search_tbl_counter)
+               search_tbl->action = tbl->action;
+       return 0;
+
+}
+
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl_priv *priv,
+                                struct iwl_lq_sta *lq_sta,
+                                struct ieee80211_conf *conf,
+                                struct ieee80211_sta *sta, int index)
+{
+       u8 is_green = lq_sta->is_green;
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+       struct iwl_scale_tbl_info *search_tbl =
+                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+       struct iwl_rate_scale_data *window = &(tbl->win[index]);
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+       u8 start_action;
+       u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+       u8 update_search_tbl_counter = 0;
+       int ret;
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+               if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
+       if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
+           tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
+               /* stay in SISO */
+               tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               valid_tx_ant =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       }
+
+       start_action = tbl->action;
+       for (;;) {
+               lq_sta->action_counter++;
+               switch (tbl->action) {
+               case IWL_SISO_SWITCH_ANTENNA1:
+               case IWL_SISO_SWITCH_ANTENNA2:
+                       IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
+                       if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
+                                               tx_chains_num <= 1) ||
+                           (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
+                                               tx_chains_num <= 2))
+                               break;
+
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
+                               break;
+
+                       memcpy(search_tbl, tbl, sz);
+                       if (rs_toggle_antenna(valid_tx_ant,
+                                      &search_tbl->current_rate, search_tbl)) {
+                               update_search_tbl_counter = 1;
+                               goto out;
+                       }
+                       break;
+               case IWL_SISO_SWITCH_MIMO2_AB:
+               case IWL_SISO_SWITCH_MIMO2_AC:
+               case IWL_SISO_SWITCH_MIMO2_BC:
+                       IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO2\n");
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+
+                       if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
+                               search_tbl->ant_type = ANT_AB;
+                       else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
+                               search_tbl->ant_type = ANT_AC;
+                       else
+                               search_tbl->ant_type = ANT_BC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+                       break;
+               case IWL_SISO_SWITCH_GI:
+                       if (!tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_20))
+                               break;
+                       if (tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_40))
+                               break;
+
+                       IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
+
+                       memcpy(search_tbl, tbl, sz);
+                       if (is_green) {
+                               if (!tbl->is_SGI)
+                                       break;
+                               else
+                                       IWL_ERR(priv,
+                                               "SGI was set in GF+SISO\n");
+                       }
+                       search_tbl->is_SGI = !tbl->is_SGI;
+                       rs_set_expected_tpt_table(lq_sta, search_tbl);
+                       if (tbl->is_SGI) {
+                               s32 tpt = lq_sta->last_tpt / 100;
+                               if (tpt >= search_tbl->expected_tpt[index])
+                                       break;
+                       }
+                       search_tbl->current_rate =
+                               rate_n_flags_from_tbl(priv, search_tbl,
+                                                     index, is_green);
+                       update_search_tbl_counter = 1;
+                       goto out;
+               case IWL_SISO_SWITCH_MIMO3_ABC:
+                       IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+                       search_tbl->ant_type = ANT_ABC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+                       break;
+               }
+               tbl->action++;
+               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+
+               if (tbl->action == start_action)
+                       break;
+       }
+       search_tbl->lq_type = LQ_NONE;
+       return 0;
+
+ out:
+       lq_sta->search_better_tbl = 1;
+       tbl->action++;
+       if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
+               tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       if (update_search_tbl_counter)
+               search_tbl->action = tbl->action;
+
+       return 0;
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO2
+ */
+static int rs_move_mimo2_to_other(struct iwl_priv *priv,
+                                struct iwl_lq_sta *lq_sta,
+                                struct ieee80211_conf *conf,
+                                struct ieee80211_sta *sta, int index)
+{
+       s8 is_green = lq_sta->is_green;
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+       struct iwl_scale_tbl_info *search_tbl =
+                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+       struct iwl_rate_scale_data *window = &(tbl->win[index]);
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+       u8 start_action;
+       u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+       u8 update_search_tbl_counter = 0;
+       int ret;
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
+       if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
+               /* switch in SISO */
+               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+       }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO2_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+
+       start_action = tbl->action;
+       for (;;) {
+               lq_sta->action_counter++;
+               switch (tbl->action) {
+               case IWL_MIMO2_SWITCH_ANTENNA1:
+               case IWL_MIMO2_SWITCH_ANTENNA2:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
+
+                       if (tx_chains_num <= 2)
+                               break;
+
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                               break;
+
+                       memcpy(search_tbl, tbl, sz);
+                       if (rs_toggle_antenna(valid_tx_ant,
+                                      &search_tbl->current_rate, search_tbl)) {
+                               update_search_tbl_counter = 1;
+                               goto out;
+                       }
+                       break;
+               case IWL_MIMO2_SWITCH_SISO_A:
+               case IWL_MIMO2_SWITCH_SISO_B:
+               case IWL_MIMO2_SWITCH_SISO_C:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to SISO\n");
+
+                       /* Set up new search table for SISO */
+                       memcpy(search_tbl, tbl, sz);
+
+                       if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
+                               search_tbl->ant_type = ANT_A;
+                       else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+                               search_tbl->ant_type = ANT_B;
+                       else
+                               search_tbl->ant_type = ANT_C;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+
+                       break;
+
+               case IWL_MIMO2_SWITCH_GI:
+                       if (!tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_20))
+                               break;
+                       if (tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_40))
+                               break;
+
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
+
+                       /* Set up new search table for MIMO2 */
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = !tbl->is_SGI;
+                       rs_set_expected_tpt_table(lq_sta, search_tbl);
+                       /*
+                        * If active table already uses the fastest possible
+                        * modulation (dual stream with short guard interval),
+                        * and it's working well, there's no need to look
+                        * for a better type of modulation!
+                        */
+                       if (tbl->is_SGI) {
+                               s32 tpt = lq_sta->last_tpt / 100;
+                               if (tpt >= search_tbl->expected_tpt[index])
+                                       break;
+                       }
+                       search_tbl->current_rate =
+                               rate_n_flags_from_tbl(priv, search_tbl,
+                                                     index, is_green);
+                       update_search_tbl_counter = 1;
+                       goto out;
+
+               case IWL_MIMO2_SWITCH_MIMO3_ABC:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+                       search_tbl->ant_type = ANT_ABC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+
+                       break;
+               }
+               tbl->action++;
+               if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+                       tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+
+               if (tbl->action == start_action)
+                       break;
+       }
+       search_tbl->lq_type = LQ_NONE;
+       return 0;
+ out:
+       lq_sta->search_better_tbl = 1;
+       tbl->action++;
+       if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
+               tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+       if (update_search_tbl_counter)
+               search_tbl->action = tbl->action;
+
+       return 0;
+
+}
+
+/*
+ * Try to switch to new modulation mode from MIMO3
+ */
+static int rs_move_mimo3_to_other(struct iwl_priv *priv,
+                                struct iwl_lq_sta *lq_sta,
+                                struct ieee80211_conf *conf,
+                                struct ieee80211_sta *sta, int index)
+{
+       s8 is_green = lq_sta->is_green;
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+       struct iwl_scale_tbl_info *search_tbl =
+                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+       struct iwl_rate_scale_data *window = &(tbl->win[index]);
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+       u8 start_action;
+       u8 valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+       int ret;
+       u8 update_search_tbl_counter = 0;
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
+       if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
+           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
+               /* switch in SISO */
+               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+       }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO3_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+
+       start_action = tbl->action;
+       for (;;) {
+               lq_sta->action_counter++;
+               switch (tbl->action) {
+               case IWL_MIMO3_SWITCH_ANTENNA1:
+               case IWL_MIMO3_SWITCH_ANTENNA2:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
+
+                       if (tx_chains_num <= 3)
+                               break;
+
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                               break;
+
+                       memcpy(search_tbl, tbl, sz);
+                       if (rs_toggle_antenna(valid_tx_ant,
+                                      &search_tbl->current_rate, search_tbl))
+                               goto out;
+                       break;
+               case IWL_MIMO3_SWITCH_SISO_A:
+               case IWL_MIMO3_SWITCH_SISO_B:
+               case IWL_MIMO3_SWITCH_SISO_C:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
+
+                       /* Set up new search table for SISO */
+                       memcpy(search_tbl, tbl, sz);
+
+                       if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
+                               search_tbl->ant_type = ANT_A;
+                       else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+                               search_tbl->ant_type = ANT_B;
+                       else
+                               search_tbl->ant_type = ANT_C;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+
+                       break;
+
+               case IWL_MIMO3_SWITCH_MIMO2_AB:
+               case IWL_MIMO3_SWITCH_MIMO2_AC:
+               case IWL_MIMO3_SWITCH_MIMO2_BC:
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
+
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = 0;
+                       if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
+                               search_tbl->ant_type = ANT_AB;
+                       else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
+                               search_tbl->ant_type = ANT_AC;
+                       else
+                               search_tbl->ant_type = ANT_BC;
+
+                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
+                               break;
+
+                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
+                                                search_tbl, index);
+                       if (!ret)
+                               goto out;
+
+                       break;
+
+               case IWL_MIMO3_SWITCH_GI:
+                       if (!tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_20))
+                               break;
+                       if (tbl->is_ht40 && !(ht_cap->cap &
+                                               IEEE80211_HT_CAP_SGI_40))
+                               break;
+
+                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
+
+                       /* Set up new search table for MIMO */
+                       memcpy(search_tbl, tbl, sz);
+                       search_tbl->is_SGI = !tbl->is_SGI;
+                       rs_set_expected_tpt_table(lq_sta, search_tbl);
+                       /*
+                        * If active table already uses the fastest possible
+                        * modulation (dual stream with short guard interval),
+                        * and it's working well, there's no need to look
+                        * for a better type of modulation!
+                        */
+                       if (tbl->is_SGI) {
+                               s32 tpt = lq_sta->last_tpt / 100;
+                               if (tpt >= search_tbl->expected_tpt[index])
+                                       break;
+                       }
+                       search_tbl->current_rate =
+                               rate_n_flags_from_tbl(priv, search_tbl,
+                                                     index, is_green);
+                       update_search_tbl_counter = 1;
+                       goto out;
+               }
+               tbl->action++;
+               if (tbl->action > IWL_MIMO3_SWITCH_GI)
+                       tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+
+               if (tbl->action == start_action)
+                       break;
+       }
+       search_tbl->lq_type = LQ_NONE;
+       return 0;
+ out:
+       lq_sta->search_better_tbl = 1;
+       tbl->action++;
+       if (tbl->action > IWL_MIMO3_SWITCH_GI)
+               tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+       if (update_search_tbl_counter)
+               search_tbl->action = tbl->action;
+
+       return 0;
+
+}
+
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
+{
+       struct iwl_scale_tbl_info *tbl;
+       int i;
+       int active_tbl;
+       int flush_interval_passed = 0;
+       struct iwl_priv *priv;
+
+       priv = lq_sta->drv;
+       active_tbl = lq_sta->active_tbl;
+
+       tbl = &(lq_sta->lq_info[active_tbl]);
+
+       /* If we've been disallowing search, see if we should now allow it */
+       if (lq_sta->stay_in_tbl) {
+
+               /* Elapsed time using current modulation mode */
+               if (lq_sta->flush_timer)
+                       flush_interval_passed =
+                       time_after(jiffies,
+                                       (unsigned long)(lq_sta->flush_timer +
+                                       IWL_RATE_SCALE_FLUSH_INTVL));
+
+               /*
+                * Check if we should allow search for new modulation mode.
+                * If many frames have failed or succeeded, or we've used
+                * this same modulation for a long time, allow search, and
+                * reset history stats that keep track of whether we should
+                * allow a new search.  Also (below) reset all bitmaps and
+                * stats in active history.
+                */
+               if (force_search ||
+                   (lq_sta->total_failed > lq_sta->max_failure_limit) ||
+                   (lq_sta->total_success > lq_sta->max_success_limit) ||
+                   ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
+                    && (flush_interval_passed))) {
+                       IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n",
+                                    lq_sta->total_failed,
+                                    lq_sta->total_success,
+                                    flush_interval_passed);
+
+                       /* Allow search for new mode */
+                       lq_sta->stay_in_tbl = 0;        /* only place reset */
+                       lq_sta->total_failed = 0;
+                       lq_sta->total_success = 0;
+                       lq_sta->flush_timer = 0;
+
+               /*
+                * Else if we've used this modulation mode enough repetitions
+                * (regardless of elapsed time or success/failure), reset
+                * history bitmaps and rate-specific stats for all rates in
+                * active table.
+                */
+               } else {
+                       lq_sta->table_count++;
+                       if (lq_sta->table_count >=
+                           lq_sta->table_count_limit) {
+                               lq_sta->table_count = 0;
+
+                               IWL_DEBUG_RATE(priv, "LQ: stay in table clear win\n");
+                               for (i = 0; i < IWL_RATE_COUNT; i++)
+                                       rs_rate_scale_clear_window(
+                                               &(tbl->win[i]));
+                       }
+               }
+
+               /* If transitioning to allow "search", reset all history
+                * bitmaps and stats in active table (this will become the new
+                * "search" table). */
+               if (!lq_sta->stay_in_tbl) {
+                       for (i = 0; i < IWL_RATE_COUNT; i++)
+                               rs_rate_scale_clear_window(&(tbl->win[i]));
+               }
+       }
+}
+
+/*
+ * setup rate table in uCode
+ */
+static void rs_update_rate_tbl(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
+                              struct iwl_lq_sta *lq_sta,
+                              struct iwl_scale_tbl_info *tbl,
+                              int index, u8 is_green)
+{
+       u32 rate;
+
+       /* Update uCode's rate table. */
+       rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+       rs_fill_link_cmd(priv, lq_sta, rate);
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+}
+
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+                                 struct sk_buff *skb,
+                                 struct ieee80211_sta *sta,
+                                 struct iwl_lq_sta *lq_sta)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       int low = IWL_RATE_INVALID;
+       int high = IWL_RATE_INVALID;
+       int index;
+       int i;
+       struct iwl_rate_scale_data *window = NULL;
+       int current_tpt = IWL_INVALID_VALUE;
+       int low_tpt = IWL_INVALID_VALUE;
+       int high_tpt = IWL_INVALID_VALUE;
+       u32 fail_count;
+       s8 scale_action = 0;
+       u16 rate_mask;
+       u8 update_lq = 0;
+       struct iwl_scale_tbl_info *tbl, *tbl1;
+       u16 rate_scale_index_msk = 0;
+       u8 is_green = 0;
+       u8 active_tbl = 0;
+       u8 done_search = 0;
+       u16 high_low;
+       s32 sr;
+       u8 tid = IWL_MAX_TID_COUNT;
+       struct iwl_tid_data *tid_data;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
+
+       IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
+
+       /* Send management frames and NO_ACK data using lowest rate. */
+       /* TODO: this could probably be improved.. */
+       if (!ieee80211_is_data(hdr->frame_control) ||
+           info->flags & IEEE80211_TX_CTL_NO_ACK)
+               return;
+
+       lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
+
+       tid = rs_tl_add_packet(lq_sta, hdr);
+       if ((tid != IWL_MAX_TID_COUNT) &&
+           (lq_sta->tx_agg_tid_en & (1 << tid))) {
+               tid_data = &priv->tid_data[lq_sta->lq.sta_id][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
+        * the rest of this function:  "search" if searching for better
+        * modulation mode, or "active" if doing rate scaling within a mode.
+        */
+       if (!lq_sta->search_better_tbl)
+               active_tbl = lq_sta->active_tbl;
+       else
+               active_tbl = 1 - lq_sta->active_tbl;
+
+       tbl = &(lq_sta->lq_info[active_tbl]);
+       if (is_legacy(tbl->lq_type))
+               lq_sta->is_green = 0;
+       else
+               lq_sta->is_green = rs_use_green(sta);
+       is_green = lq_sta->is_green;
+
+       /* current tx rate */
+       index = lq_sta->last_txrate_idx;
+
+       IWL_DEBUG_RATE(priv, "Rate scale index %d for type %d\n", index,
+                      tbl->lq_type);
+
+       /* rates available for this association, and for modulation mode */
+       rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
+
+       IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
+
+       /* mask with station rate restriction */
+       if (is_legacy(tbl->lq_type)) {
+               if (lq_sta->band == IEEE80211_BAND_5GHZ)
+                       /* supp_rates has no CCK bits in A mode */
+                       rate_scale_index_msk = (u16) (rate_mask &
+                               (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
+               else
+                       rate_scale_index_msk = (u16) (rate_mask &
+                                                     lq_sta->supp_rates);
+
+       } else
+               rate_scale_index_msk = rate_mask;
+
+       if (!rate_scale_index_msk)
+               rate_scale_index_msk = rate_mask;
+
+       if (!((1 << index) & rate_scale_index_msk)) {
+               IWL_ERR(priv, "Current Rate is not valid\n");
+               if (lq_sta->search_better_tbl) {
+                       /* revert to active table if search table is not valid*/
+                       tbl->lq_type = LQ_NONE;
+                       lq_sta->search_better_tbl = 0;
+                       tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+                       /* get "active" rate info */
+                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+                       rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
+                                          index, is_green);
+               }
+               return;
+       }
+
+       /* Get expected throughput table and history window for current rate */
+       if (!tbl->expected_tpt) {
+               IWL_ERR(priv, "tbl->expected_tpt is NULL\n");
+               return;
+       }
+
+       /* force user max rate if set by user */
+       if ((lq_sta->max_rate_idx != -1) &&
+           (lq_sta->max_rate_idx < index)) {
+               index = lq_sta->max_rate_idx;
+               update_lq = 1;
+               window = &(tbl->win[index]);
+               goto lq_update;
+       }
+
+       window = &(tbl->win[index]);
+
+       /*
+        * If there is not enough history to calculate actual average
+        * throughput, keep analyzing results of more tx frames, without
+        * changing rate or mode (bypass most of the rest of this function).
+        * Set up new rate table in uCode only if old rate is not supported
+        * in current association (use new rate found above).
+        */
+       fail_count = window->counter - window->success_counter;
+       if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+                       (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+               IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
+                              "for index %d\n",
+                              window->success_counter, window->counter, index);
+
+               /* Can't calculate this yet; not enough history */
+               window->average_tpt = IWL_INVALID_VALUE;
+
+               /* Should we stay with this modulation mode,
+                * or search for a new one? */
+               rs_stay_in_table(lq_sta, false);
+
+               goto out;
+       }
+       /* Else we have enough samples; calculate estimate of
+        * actual average throughput */
+       if (window->average_tpt != ((window->success_ratio *
+                       tbl->expected_tpt[index] + 64) / 128)) {
+               IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
+               window->average_tpt = ((window->success_ratio *
+                                       tbl->expected_tpt[index] + 64) / 128);
+       }
+
+       /* If we are searching for better modulation mode, check success. */
+       if (lq_sta->search_better_tbl &&
+           (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
+               /* If good success, continue using the "search" mode;
+                * no need to send new link quality command, since we're
+                * continuing to use the setup that we've been trying. */
+               if (window->average_tpt > lq_sta->last_tpt) {
+
+                       IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
+                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
+                                       window->success_ratio,
+                                       window->average_tpt,
+                                       lq_sta->last_tpt);
+
+                       if (!is_legacy(tbl->lq_type))
+                               lq_sta->enable_counter = 1;
+
+                       /* Swap tables; "search" becomes "active" */
+                       lq_sta->active_tbl = active_tbl;
+                       current_tpt = window->average_tpt;
+
+               /* Else poor success; go back to mode in "active" table */
+               } else {
+
+                       IWL_DEBUG_RATE(priv, "LQ: GOING BACK TO THE OLD TABLE "
+                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
+                                       window->success_ratio,
+                                       window->average_tpt,
+                                       lq_sta->last_tpt);
+
+                       /* Nullify "search" table */
+                       tbl->lq_type = LQ_NONE;
+
+                       /* Revert to "active" table */
+                       active_tbl = lq_sta->active_tbl;
+                       tbl = &(lq_sta->lq_info[active_tbl]);
+
+                       /* Revert to "active" rate and throughput info */
+                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+                       current_tpt = lq_sta->last_tpt;
+
+                       /* Need to set up a new rate table in uCode */
+                       update_lq = 1;
+               }
+
+               /* Either way, we've made a decision; modulation mode
+                * search is done, allow rate adjustment next time. */
+               lq_sta->search_better_tbl = 0;
+               done_search = 1;        /* Don't switch modes below! */
+               goto lq_update;
+       }
+
+       /* (Else) not in search of better modulation mode, try for better
+        * starting rate, while staying in this mode. */
+       high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
+                                       tbl->lq_type);
+       low = high_low & 0xff;
+       high = (high_low >> 8) & 0xff;
+
+       /* If user set max rate, dont allow higher than user constrain */
+       if ((lq_sta->max_rate_idx != -1) &&
+           (lq_sta->max_rate_idx < high))
+               high = IWL_RATE_INVALID;
+
+       sr = window->success_ratio;
+
+       /* Collect measured throughputs for current and adjacent rates */
+       current_tpt = window->average_tpt;
+       if (low != IWL_RATE_INVALID)
+               low_tpt = tbl->win[low].average_tpt;
+       if (high != IWL_RATE_INVALID)
+               high_tpt = tbl->win[high].average_tpt;
+
+       scale_action = 0;
+
+       /* Too many failures, decrease rate */
+       if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
+               IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
+               scale_action = -1;
+
+       /* No throughput measured yet for adjacent rates; try increase. */
+       } else if ((low_tpt == IWL_INVALID_VALUE) &&
+                  (high_tpt == IWL_INVALID_VALUE)) {
+
+               if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+                       scale_action = 1;
+               else if (low != IWL_RATE_INVALID)
+                       scale_action = 0;
+       }
+
+       /* Both adjacent throughputs are measured, but neither one has better
+        * throughput; we're using the best rate, don't change it! */
+       else if ((low_tpt != IWL_INVALID_VALUE) &&
+                (high_tpt != IWL_INVALID_VALUE) &&
+                (low_tpt < current_tpt) &&
+                (high_tpt < current_tpt))
+               scale_action = 0;
+
+       /* At least one adjacent rate's throughput is measured,
+        * and may have better performance. */
+       else {
+               /* Higher adjacent rate's throughput is measured */
+               if (high_tpt != IWL_INVALID_VALUE) {
+                       /* Higher rate has better throughput */
+                       if (high_tpt > current_tpt &&
+                                       sr >= IWL_RATE_INCREASE_TH) {
+                               scale_action = 1;
+                       } else {
+                               scale_action = 0;
+                       }
+
+               /* Lower adjacent rate's throughput is measured */
+               } else if (low_tpt != IWL_INVALID_VALUE) {
+                       /* Lower rate has better throughput */
+                       if (low_tpt > current_tpt) {
+                               IWL_DEBUG_RATE(priv,
+                                   "decrease rate because of low tpt\n");
+                               scale_action = -1;
+                       } else if (sr >= IWL_RATE_INCREASE_TH) {
+                               scale_action = 1;
+                       }
+               }
+       }
+
+       /* Sanity check; asked for decrease, but success rate or throughput
+        * has been good at old rate.  Don't change it. */
+       if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+                   ((sr > IWL_RATE_HIGH_TH) ||
+                    (current_tpt > (100 * tbl->expected_tpt[low]))))
+               scale_action = 0;
+       if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
+               scale_action = -1;
+       if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
+               (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
+               scale_action = -1;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+                       /*
+                        * don't set scale_action, don't want to scale up if
+                        * the rate scale doesn't otherwise think that is a
+                        * good idea.
+                        */
+               } else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
+                       scale_action = -1;
+               }
+       }
+       lq_sta->last_bt_traffic = priv->bt_traffic_load;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               /* search for a new modulation */
+               rs_stay_in_table(lq_sta, true);
+               goto lq_update;
+       }
+
+       switch (scale_action) {
+       case -1:
+               /* Decrease starting rate, update uCode's rate table */
+               if (low != IWL_RATE_INVALID) {
+                       update_lq = 1;
+                       index = low;
+               }
+
+               break;
+       case 1:
+               /* Increase starting rate, update uCode's rate table */
+               if (high != IWL_RATE_INVALID) {
+                       update_lq = 1;
+                       index = high;
+               }
+
+               break;
+       case 0:
+               /* No change */
+       default:
+               break;
+       }
+
+       IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
+                   "high %d type %d\n",
+                    index, scale_action, low, high, tbl->lq_type);
+
+lq_update:
+       /* Replace uCode's rate table for the destination station. */
+       if (update_lq)
+               rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
+
+       if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
+               /* Should we stay with this modulation mode,
+                * or search for a new one? */
+         rs_stay_in_table(lq_sta, false);
+       }
+       /*
+        * Search for new modulation mode if we're:
+        * 1)  Not changing rates right now
+        * 2)  Not just finishing up a search
+        * 3)  Allowing a new search
+        */
+       if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
+               /* Save current throughput to compare with "search" throughput*/
+               lq_sta->last_tpt = current_tpt;
+
+               /* Select a new "search" modulation mode to try.
+                * If one is found, set up the new "search" table. */
+               if (is_legacy(tbl->lq_type))
+                       rs_move_legacy_other(priv, lq_sta, conf, sta, index);
+               else if (is_siso(tbl->lq_type))
+                       rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
+               else if (is_mimo2(tbl->lq_type))
+                       rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
+               else
+                       rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
+
+               /* If new "search" mode was selected, set up in uCode table */
+               if (lq_sta->search_better_tbl) {
+                       /* Access the "search" table, clear its history. */
+                       tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+                       for (i = 0; i < IWL_RATE_COUNT; i++)
+                               rs_rate_scale_clear_window(&(tbl->win[i]));
+
+                       /* Use new "search" start rate */
+                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+
+                       IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
+                                    tbl->current_rate, index);
+                       rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+               } else
+                       done_search = 1;
+       }
+
+       if (done_search && !lq_sta->stay_in_tbl) {
+               /* If the "active" (non-search) mode was legacy,
+                * and we've tried switching antennas,
+                * but we haven't been able to try HT modes (not available),
+                * stay with best antenna legacy modulation for a while
+                * before next round of mode comparisons. */
+               tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
+                   lq_sta->action_counter > tbl1->max_search) {
+                       IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
+                       rs_set_stay_in_table(priv, 1, lq_sta);
+               }
+
+               /* If we're in an HT mode, and all 3 mode switch actions
+                * have been tried and compared, stay in this best modulation
+                * mode for a while before next round of mode comparisons. */
+               if (lq_sta->enable_counter &&
+                   (lq_sta->action_counter >= tbl1->max_search) &&
+                   iwl_ht_enabled(priv)) {
+                       if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
+                           (lq_sta->tx_agg_tid_en & (1 << tid)) &&
+                           (tid != IWL_MAX_TID_COUNT)) {
+                               u8 sta_id = lq_sta->lq.sta_id;
+                               tid_data = &priv->tid_data[sta_id][tid];
+                               if (tid_data->agg.state == IWL_AGG_OFF) {
+                                       IWL_DEBUG_RATE(priv,
+                                                      "try to aggregate tid %d\n",
+                                                      tid);
+                                       rs_tl_turn_on_agg(priv, tid,
+                                                         lq_sta, sta);
+                               }
+                       }
+                       rs_set_stay_in_table(priv, 0, lq_sta);
+               }
+       }
+
+out:
+       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
+       lq_sta->last_txrate_idx = index;
+}
+
+/**
+ * rs_initialize_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
+ */
+static void rs_initialize_lq(struct iwl_priv *priv,
+                            struct ieee80211_sta *sta,
+                            struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_scale_tbl_info *tbl;
+       int rate_idx;
+       int i;
+       u32 rate;
+       u8 use_green = rs_use_green(sta);
+       u8 active_tbl = 0;
+       u8 valid_tx_ant;
+       struct iwl_station_priv *sta_priv;
+       struct iwl_rxon_context *ctx;
+
+       if (!sta || !lq_sta)
+               return;
+
+       sta_priv = (void *)sta->drv_priv;
+       ctx = sta_priv->ctx;
+
+       i = lq_sta->last_txrate_idx;
+
+       valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+
+       if (!lq_sta->search_better_tbl)
+               active_tbl = lq_sta->active_tbl;
+       else
+               active_tbl = 1 - lq_sta->active_tbl;
+
+       tbl = &(lq_sta->lq_info[active_tbl]);
+
+       if ((i < 0) || (i >= IWL_RATE_COUNT))
+               i = 0;
+
+       rate = iwl_rates[i].plcp;
+       tbl->ant_type = first_antenna(valid_tx_ant);
+       rate |= tbl->ant_type << RATE_MCS_ANT_POS;
+
+       if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+               rate |= RATE_MCS_CCK_MSK;
+
+       rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
+       if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+           rs_toggle_antenna(valid_tx_ant, &rate, tbl);
+
+       rate = rate_n_flags_from_tbl(priv, tbl, rate_idx, use_green);
+       tbl->current_rate = rate;
+       rs_set_expected_tpt_table(lq_sta, tbl);
+       rs_fill_link_cmd(NULL, lq_sta, rate);
+       priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
+}
+
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
+                       struct ieee80211_tx_rate_control *txrc)
+{
+
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_supported_band *sband = txrc->sband;
+       struct iwl_op_mode *op_mode __maybe_unused =
+                       (struct iwl_op_mode *)priv_r;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       int rate_idx;
+
+       IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
+
+       /* Get max rate if user set max rate */
+       if (lq_sta) {
+               lq_sta->max_rate_idx = txrc->max_rate_idx;
+               if ((sband->band == IEEE80211_BAND_5GHZ) &&
+                   (lq_sta->max_rate_idx != -1))
+                       lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
+               if ((lq_sta->max_rate_idx < 0) ||
+                   (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
+                       lq_sta->max_rate_idx = -1;
+       }
+
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (lq_sta && !lq_sta->drv) {
+               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+               priv_sta = NULL;
+       }
+
+       /* Send management frames and NO_ACK data using lowest rate. */
+       if (rate_control_send_low(sta, priv_sta, txrc))
+               return;
+
+       rate_idx  = lq_sta->last_txrate_idx;
+
+       if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
+               rate_idx -= IWL_FIRST_OFDM_RATE;
+               /* 6M and 9M shared same MCS index */
+               rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
+               if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+                   IWL_RATE_MIMO3_6M_PLCP)
+                       rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
+               else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
+                        IWL_RATE_MIMO2_6M_PLCP)
+                       rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
+               info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
+               if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
+                       info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
+               if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
+                       info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
+               if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
+                       info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+               if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
+                       info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
+       } else {
+               /* Check for invalid rates */
+               if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
+                               ((sband->band == IEEE80211_BAND_5GHZ) &&
+                                (rate_idx < IWL_FIRST_OFDM_RATE)))
+                       rate_idx = rate_lowest_index(sband, sta);
+               /* On valid 5 GHz rate, adjust index */
+               else if (sband->band == IEEE80211_BAND_5GHZ)
+                       rate_idx -= IWL_FIRST_OFDM_RATE;
+               info->control.rates[0].flags = 0;
+       }
+       info->control.rates[0].idx = rate_idx;
+
+}
+
+static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
+                         gfp_t gfp)
+{
+       struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
+       struct iwl_op_mode *op_mode __maybe_unused =
+                       (struct iwl_op_mode *)priv_rate;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+
+       IWL_DEBUG_RATE(priv, "create station rate scale window\n");
+
+       return &sta_priv->lq_sta;
+}
+
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
+{
+       int i, j;
+       struct ieee80211_hw *hw = priv->hw;
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       struct iwl_station_priv *sta_priv;
+       struct iwl_lq_sta *lq_sta;
+       struct ieee80211_supported_band *sband;
+       unsigned long supp; /* must be unsigned long for for_each_set_bit */
+
+       sta_priv = (struct iwl_station_priv *) sta->drv_priv;
+       lq_sta = &sta_priv->lq_sta;
+       sband = hw->wiphy->bands[conf->channel->band];
+
+
+       lq_sta->lq.sta_id = sta_id;
+
+       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]);
+
+       lq_sta->flush_timer = 0;
+       lq_sta->supp_rates = sta->supp_rates[sband->band];
+       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]);
+
+       IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n",
+                      sta_id);
+       /* TODO: what is a good starting rate for STA? About middle? Maybe not
+        * the lowest or the highest rate.. Could consider using RSSI from
+        * previous packets? Need to have IEEE 802.1X auth succeed immediately
+        * after assoc.. */
+
+       lq_sta->is_dup = 0;
+       lq_sta->max_rate_idx = -1;
+       lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+       lq_sta->is_green = rs_use_green(sta);
+       lq_sta->band = sband->band;
+       /*
+        * active legacy rates as per supported rates bitmap
+        */
+       supp = sta->supp_rates[sband->band];
+       lq_sta->active_legacy_rate = 0;
+       for_each_set_bit(i, &supp, BITS_PER_LONG)
+               lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
+
+       /*
+        * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+        * supp_rates[] does not; shift to convert format, force 9 MBits off.
+        */
+       lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+       lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+       lq_sta->active_siso_rate &= ~((u16)0x2);
+       lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+       /* Same here */
+       lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+       lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+       lq_sta->active_mimo2_rate &= ~((u16)0x2);
+       lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+       lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
+       lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
+       lq_sta->active_mimo3_rate &= ~((u16)0x2);
+       lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+
+       IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
+                    lq_sta->active_siso_rate,
+                    lq_sta->active_mimo2_rate,
+                    lq_sta->active_mimo3_rate);
+
+       /* These values will be overridden later */
+       lq_sta->lq.general_params.single_stream_ant_msk =
+               first_antenna(priv->eeprom_data->valid_tx_ant);
+       lq_sta->lq.general_params.dual_stream_ant_msk =
+               priv->eeprom_data->valid_tx_ant &
+               ~first_antenna(priv->eeprom_data->valid_tx_ant);
+       if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
+               lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
+       } else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
+               lq_sta->lq.general_params.dual_stream_ant_msk =
+                       priv->eeprom_data->valid_tx_ant;
+       }
+
+       /* as default allow aggregation for all tids */
+       lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
+       lq_sta->drv = priv;
+
+       /* Set last_txrate_idx to lowest rate */
+       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;
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+       priv->tm_fixed_rate = 0;
+#endif
+#ifdef CONFIG_MAC80211_DEBUGFS
+       lq_sta->dbg_fixed_rate = 0;
+#endif
+
+       rs_initialize_lq(priv, sta, lq_sta);
+}
+
+static void rs_fill_link_cmd(struct iwl_priv *priv,
+                            struct iwl_lq_sta *lq_sta, u32 new_rate)
+{
+       struct iwl_scale_tbl_info tbl_type;
+       int index = 0;
+       int rate_idx;
+       int repeat_rate = 0;
+       u8 ant_toggle_cnt = 0;
+       u8 use_ht_possible = 1;
+       u8 valid_tx_ant = 0;
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
+
+       /* Override starting rate (index 0) if needed for debug purposes */
+       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+       /* Interpret new_rate (rate_n_flags) */
+       rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
+                                 &tbl_type, &rate_idx);
+
+       if (priv && priv->bt_full_concurrent) {
+               /* 1x1 only */
+               tbl_type.ant_type =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+       }
+
+       /* How many times should we repeat the initial rate? */
+       if (is_legacy(tbl_type.lq_type)) {
+               ant_toggle_cnt = 1;
+               repeat_rate = IWL_NUMBER_TRY;
+       } else {
+               repeat_rate = min(IWL_HT_NUMBER_TRY,
+                                 LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+       }
+
+       lq_cmd->general_params.mimo_delimiter =
+                       is_mimo(tbl_type.lq_type) ? 1 : 0;
+
+       /* Fill 1st table entry (index 0) */
+       lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
+
+       if (num_of_ant(tbl_type.ant_type) == 1) {
+               lq_cmd->general_params.single_stream_ant_msk =
+                                               tbl_type.ant_type;
+       } else if (num_of_ant(tbl_type.ant_type) == 2) {
+               lq_cmd->general_params.dual_stream_ant_msk =
+                                               tbl_type.ant_type;
+       } /* otherwise we don't modify the existing value */
+
+       index++;
+       repeat_rate--;
+       if (priv) {
+               if (priv->bt_full_concurrent)
+                       valid_tx_ant = ANT_A;
+               else
+                       valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       }
+
+       /* Fill rest of rate table */
+       while (index < LINK_QUAL_MAX_RETRY_NUM) {
+               /* Repeat initial/next rate.
+                * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+                * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
+               while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+                       if (is_legacy(tbl_type.lq_type)) {
+                               if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+                                       ant_toggle_cnt++;
+                               else if (priv &&
+                                        rs_toggle_antenna(valid_tx_ant,
+                                                       &new_rate, &tbl_type))
+                                       ant_toggle_cnt = 1;
+                       }
+
+                       /* Override next rate if needed for debug purposes */
+                       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+                       /* Fill next table entry */
+                       lq_cmd->rs_table[index].rate_n_flags =
+                                       cpu_to_le32(new_rate);
+                       repeat_rate--;
+                       index++;
+               }
+
+               rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
+                                               &rate_idx);
+
+               if (priv && priv->bt_full_concurrent) {
+                       /* 1x1 only */
+                       tbl_type.ant_type =
+                           first_antenna(priv->eeprom_data->valid_tx_ant);
+               }
+
+               /* Indicate to uCode which entries might be MIMO.
+                * If initial rate was MIMO, this will finally end up
+                * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
+               if (is_mimo(tbl_type.lq_type))
+                       lq_cmd->general_params.mimo_delimiter = index;
+
+               /* Get next rate */
+               new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+                                            use_ht_possible);
+
+               /* How many times should we repeat the next rate? */
+               if (is_legacy(tbl_type.lq_type)) {
+                       if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+                               ant_toggle_cnt++;
+                       else if (priv &&
+                                rs_toggle_antenna(valid_tx_ant,
+                                                  &new_rate, &tbl_type))
+                               ant_toggle_cnt = 1;
+
+                       repeat_rate = IWL_NUMBER_TRY;
+               } else {
+                       repeat_rate = IWL_HT_NUMBER_TRY;
+               }
+
+               /* Don't allow HT rates after next pass.
+                * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
+               use_ht_possible = 0;
+
+               /* Override next rate if needed for debug purposes */
+               rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+               /* Fill next table entry */
+               lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
+
+               index++;
+               repeat_rate--;
+       }
+
+       lq_cmd->agg_params.agg_frame_cnt_limit =
+               sta_priv->max_agg_bufsize ?: 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);
+       /*
+        * overwrite if needed, pass aggregation time limit
+        * to uCode in uSec
+        */
+       if (priv && priv->cfg->bt_params &&
+           priv->cfg->bt_params->agg_time_limit &&
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+               lq_cmd->agg_params.agg_time_limit =
+                       cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
+}
+
+static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+       return hw->priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+       return;
+}
+
+static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
+                       void *priv_sta)
+{
+       struct iwl_op_mode *op_mode __maybe_unused = priv_r;
+       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
+
+       IWL_DEBUG_RATE(priv, "enter\n");
+       IWL_DEBUG_RATE(priv, "leave\n");
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+                            u32 *rate_n_flags, int index)
+{
+       struct iwl_priv *priv;
+       u8 valid_tx_ant;
+       u8 ant_sel_tx;
+
+       priv = lq_sta->drv;
+       valid_tx_ant = priv->eeprom_data->valid_tx_ant;
+       if (lq_sta->dbg_fixed_rate) {
+               ant_sel_tx =
+                 ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
+                 >> RATE_MCS_ANT_POS);
+               if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
+                       *rate_n_flags = lq_sta->dbg_fixed_rate;
+                       IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
+               } else {
+                       lq_sta->dbg_fixed_rate = 0;
+                       IWL_ERR(priv,
+                           "Invalid antenna selection 0x%X, Valid is 0x%X\n",
+                           ant_sel_tx, valid_tx_ant);
+                       IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
+               }
+       } else {
+               IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
+       }
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+                       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+       struct iwl_lq_sta *lq_sta = file->private_data;
+       struct iwl_priv *priv;
+       char buf[64];
+       size_t buf_size;
+       u32 parsed_rate;
+
+
+       priv = lq_sta->drv;
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       if (sscanf(buf, "%x", &parsed_rate) == 1)
+               lq_sta->dbg_fixed_rate = parsed_rate;
+       else
+               lq_sta->dbg_fixed_rate = 0;
+
+       rs_program_fix_rate(priv, lq_sta);
+
+       return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+                       char __user *user_buf, size_t count, loff_t *ppos)
+{
+       char *buff;
+       int desc = 0;
+       int i = 0;
+       int index = 0;
+       ssize_t ret;
+
+       struct iwl_lq_sta *lq_sta = file->private_data;
+       struct iwl_priv *priv;
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+
+       priv = lq_sta->drv;
+       buff = kmalloc(1024, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
+       desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
+       desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+                       lq_sta->total_failed, lq_sta->total_success,
+                       lq_sta->active_legacy_rate);
+       desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+                       lq_sta->dbg_fixed_rate);
+       desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
+           (priv->eeprom_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
+           (priv->eeprom_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
+           (priv->eeprom_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+       desc += sprintf(buff+desc, "lq type %s\n",
+          (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
+       if (is_Ht(tbl->lq_type)) {
+               desc += sprintf(buff+desc, " %s",
+                  (is_siso(tbl->lq_type)) ? "SISO" :
+                  ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+                  desc += sprintf(buff+desc, " %s",
+                  (tbl->is_ht40) ? "40MHz" : "20MHz");
+                  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);
+       desc += sprintf(buff+desc, "general:"
+               "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+               lq_sta->lq.general_params.flags,
+               lq_sta->lq.general_params.mimo_delimiter,
+               lq_sta->lq.general_params.single_stream_ant_msk,
+               lq_sta->lq.general_params.dual_stream_ant_msk);
+
+       desc += sprintf(buff+desc, "agg:"
+                       "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+                       le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
+                       lq_sta->lq.agg_params.agg_dis_start_th,
+                       lq_sta->lq.agg_params.agg_frame_cnt_limit);
+
+       desc += sprintf(buff+desc,
+                       "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+                       lq_sta->lq.general_params.start_rate_index[0],
+                       lq_sta->lq.general_params.start_rate_index[1],
+                       lq_sta->lq.general_params.start_rate_index[2],
+                       lq_sta->lq.general_params.start_rate_index[3]);
+
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+               index = iwl_hwrate_to_plcp_idx(
+                       le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
+               if (is_legacy(tbl->lq_type)) {
+                       desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
+                               i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+                               iwl_rate_mcs[index].mbps);
+               } else {
+                       desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
+                               i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
+                               iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
+               }
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       kfree(buff);
+       return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+       .write = rs_sta_dbgfs_scale_table_write,
+       .read = rs_sta_dbgfs_scale_table_read,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+                       char __user *user_buf, size_t count, loff_t *ppos)
+{
+       char *buff;
+       int desc = 0;
+       int i, j;
+       ssize_t ret;
+
+       struct iwl_lq_sta *lq_sta = file->private_data;
+
+       buff = kmalloc(1024, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
+       for (i = 0; i < LQ_SIZE; i++) {
+               desc += sprintf(buff+desc,
+                               "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
+                               "rate=0x%X\n",
+                               lq_sta->active_tbl == i ? "*" : "x",
+                               lq_sta->lq_info[i].lq_type,
+                               lq_sta->lq_info[i].is_SGI,
+                               lq_sta->lq_info[i].is_ht40,
+                               lq_sta->lq_info[i].is_dup,
+                               lq_sta->is_green,
+                               lq_sta->lq_info[i].current_rate);
+               for (j = 0; j < IWL_RATE_COUNT; j++) {
+                       desc += sprintf(buff+desc,
+                               "counter=%d success=%d %%=%d\n",
+                               lq_sta->lq_info[i].win[j].counter,
+                               lq_sta->lq_info[i].win[j].success_counter,
+                               lq_sta->lq_info[i].win[j].success_ratio);
+               }
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       kfree(buff);
+       return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+       .read = rs_sta_dbgfs_stats_table_read,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
+                       char __user *user_buf, size_t count, loff_t *ppos)
+{
+       struct iwl_lq_sta *lq_sta = file->private_data;
+       struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+       char buff[120];
+       int desc = 0;
+
+       if (is_Ht(tbl->lq_type))
+               desc += sprintf(buff+desc,
+                               "Bit Rate= %d Mb/s\n",
+                               tbl->expected_tpt[lq_sta->last_txrate_idx]);
+       else
+               desc += sprintf(buff+desc,
+                               "Bit Rate= %d Mb/s\n",
+                               iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
+       .read = rs_sta_dbgfs_rate_scale_data_read,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+                                       struct dentry *dir)
+{
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       lq_sta->rs_sta_dbgfs_scale_table_file =
+               debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
+                               lq_sta, &rs_sta_dbgfs_scale_table_ops);
+       lq_sta->rs_sta_dbgfs_stats_table_file =
+               debugfs_create_file("rate_stats_table", S_IRUSR, dir,
+                       lq_sta, &rs_sta_dbgfs_stats_table_ops);
+       lq_sta->rs_sta_dbgfs_rate_scale_data_file =
+               debugfs_create_file("rate_scale_data", S_IRUSR, dir,
+                       lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
+       lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
+               debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
+               &lq_sta->tx_agg_tid_en);
+
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+       struct iwl_lq_sta *lq_sta = priv_sta;
+       debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
+       debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+       debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
+       debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
+}
+#endif
+
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
+                        struct ieee80211_sta *sta, void *priv_sta)
+{
+}
+static struct rate_control_ops rs_ops = {
+       .module = NULL,
+       .name = RS_NAME,
+       .tx_status = rs_tx_status,
+       .get_rate = rs_get_rate,
+       .rate_init = rs_rate_init_stub,
+       .alloc = rs_alloc,
+       .free = rs_free,
+       .alloc_sta = rs_alloc_sta,
+       .free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+       .add_sta_debugfs = rs_add_debugfs,
+       .remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwlagn_rate_control_register(void)
+{
+       return ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwlagn_rate_control_unregister(void)
+{
+       ieee80211_rate_control_unregister(&rs_ops);
+}
+
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h
new file mode 100644 (file)
index 0000000..ad3aea8
--- /dev/null
@@ -0,0 +1,433 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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_rs_h__
+#define __iwl_agn_rs_h__
+
+#include <net/mac80211.h>
+
+#include "iwl-config.h"
+
+#include "commands.h"
+
+struct iwl_rate_info {
+       u8 plcp;        /* uCode API:  IWL_RATE_6M_PLCP, etc. */
+       u8 plcp_siso;   /* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+       u8 plcp_mimo2;  /* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
+       u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
+       u8 ieee;        /* MAC header:  IWL_RATE_6M_IEEE, etc. */
+       u8 prev_ieee;    /* previous rate in IEEE speeds */
+       u8 next_ieee;    /* next rate in IEEE speeds */
+       u8 prev_rs;      /* previous rate used in rs algo */
+       u8 next_rs;      /* next rate used in rs algo */
+       u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
+       u8 next_rs_tgg;  /* next rate used in TGG rs algo */
+};
+
+/*
+ * These serve as indexes into
+ * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+ */
+enum {
+       IWL_RATE_1M_INDEX = 0,
+       IWL_RATE_2M_INDEX,
+       IWL_RATE_5M_INDEX,
+       IWL_RATE_11M_INDEX,
+       IWL_RATE_6M_INDEX,
+       IWL_RATE_9M_INDEX,
+       IWL_RATE_12M_INDEX,
+       IWL_RATE_18M_INDEX,
+       IWL_RATE_24M_INDEX,
+       IWL_RATE_36M_INDEX,
+       IWL_RATE_48M_INDEX,
+       IWL_RATE_54M_INDEX,
+       IWL_RATE_60M_INDEX,
+       IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
+       IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1,     /* Excluding 60M */
+       IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+       IWL_RATE_INVALID = IWL_RATE_COUNT,
+};
+
+enum {
+       IWL_RATE_6M_INDEX_TABLE = 0,
+       IWL_RATE_9M_INDEX_TABLE,
+       IWL_RATE_12M_INDEX_TABLE,
+       IWL_RATE_18M_INDEX_TABLE,
+       IWL_RATE_24M_INDEX_TABLE,
+       IWL_RATE_36M_INDEX_TABLE,
+       IWL_RATE_48M_INDEX_TABLE,
+       IWL_RATE_54M_INDEX_TABLE,
+       IWL_RATE_1M_INDEX_TABLE,
+       IWL_RATE_2M_INDEX_TABLE,
+       IWL_RATE_5M_INDEX_TABLE,
+       IWL_RATE_11M_INDEX_TABLE,
+       IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
+};
+
+enum {
+       IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+       IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+       IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+       IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define        IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
+#define        IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
+#define        IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
+#define        IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
+#define        IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
+#define        IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
+#define        IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
+#define        IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
+#define        IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
+#define        IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
+#define        IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
+#define        IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
+
+/* uCode API values for legacy bit rates, both OFDM and CCK */
+enum {
+       IWL_RATE_6M_PLCP  = 13,
+       IWL_RATE_9M_PLCP  = 15,
+       IWL_RATE_12M_PLCP = 5,
+       IWL_RATE_18M_PLCP = 7,
+       IWL_RATE_24M_PLCP = 9,
+       IWL_RATE_36M_PLCP = 11,
+       IWL_RATE_48M_PLCP = 1,
+       IWL_RATE_54M_PLCP = 3,
+       IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
+       IWL_RATE_1M_PLCP  = 10,
+       IWL_RATE_2M_PLCP  = 20,
+       IWL_RATE_5M_PLCP  = 55,
+       IWL_RATE_11M_PLCP = 110,
+       /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */
+       /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
+};
+
+/* uCode API values for OFDM high-throughput (HT) bit rates */
+enum {
+       IWL_RATE_SISO_6M_PLCP = 0,
+       IWL_RATE_SISO_12M_PLCP = 1,
+       IWL_RATE_SISO_18M_PLCP = 2,
+       IWL_RATE_SISO_24M_PLCP = 3,
+       IWL_RATE_SISO_36M_PLCP = 4,
+       IWL_RATE_SISO_48M_PLCP = 5,
+       IWL_RATE_SISO_54M_PLCP = 6,
+       IWL_RATE_SISO_60M_PLCP = 7,
+       IWL_RATE_MIMO2_6M_PLCP  = 0x8,
+       IWL_RATE_MIMO2_12M_PLCP = 0x9,
+       IWL_RATE_MIMO2_18M_PLCP = 0xa,
+       IWL_RATE_MIMO2_24M_PLCP = 0xb,
+       IWL_RATE_MIMO2_36M_PLCP = 0xc,
+       IWL_RATE_MIMO2_48M_PLCP = 0xd,
+       IWL_RATE_MIMO2_54M_PLCP = 0xe,
+       IWL_RATE_MIMO2_60M_PLCP = 0xf,
+       IWL_RATE_MIMO3_6M_PLCP  = 0x10,
+       IWL_RATE_MIMO3_12M_PLCP = 0x11,
+       IWL_RATE_MIMO3_18M_PLCP = 0x12,
+       IWL_RATE_MIMO3_24M_PLCP = 0x13,
+       IWL_RATE_MIMO3_36M_PLCP = 0x14,
+       IWL_RATE_MIMO3_48M_PLCP = 0x15,
+       IWL_RATE_MIMO3_54M_PLCP = 0x16,
+       IWL_RATE_MIMO3_60M_PLCP = 0x17,
+       IWL_RATE_SISO_INVM_PLCP,
+       IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+       IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+/* MAC header values for bit rates */
+enum {
+       IWL_RATE_6M_IEEE  = 12,
+       IWL_RATE_9M_IEEE  = 18,
+       IWL_RATE_12M_IEEE = 24,
+       IWL_RATE_18M_IEEE = 36,
+       IWL_RATE_24M_IEEE = 48,
+       IWL_RATE_36M_IEEE = 72,
+       IWL_RATE_48M_IEEE = 96,
+       IWL_RATE_54M_IEEE = 108,
+       IWL_RATE_60M_IEEE = 120,
+       IWL_RATE_1M_IEEE  = 2,
+       IWL_RATE_2M_IEEE  = 4,
+       IWL_RATE_5M_IEEE  = 11,
+       IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
+
+#define IWL_INVALID_VALUE    -1
+
+#define IWL_MIN_RSSI_VAL                 -100
+#define IWL_MAX_RSSI_VAL                    0
+
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
+#define IWL_LEGACY_FAILURE_LIMIT       160
+#define IWL_LEGACY_SUCCESS_LIMIT       480
+#define IWL_LEGACY_TABLE_COUNT         160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT  400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT  4500
+#define IWL_NONE_LEGACY_TABLE_COUNT    1500
+
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO              12800   /* 100% */
+#define IWL_RATE_SCALE_SWITCH          10880   /*  85% */
+#define IWL_RATE_HIGH_TH               10880   /*  85% */
+#define IWL_RATE_INCREASE_TH           6400    /*  50% */
+#define IWL_RATE_DECREASE_TH           1920    /*  15% */
+
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA1      0
+#define IWL_LEGACY_SWITCH_ANTENNA2      1
+#define IWL_LEGACY_SWITCH_SISO          2
+#define IWL_LEGACY_SWITCH_MIMO2_AB      3
+#define IWL_LEGACY_SWITCH_MIMO2_AC      4
+#define IWL_LEGACY_SWITCH_MIMO2_BC      5
+#define IWL_LEGACY_SWITCH_MIMO3_ABC     6
+
+/* possible actions when in siso mode */
+#define IWL_SISO_SWITCH_ANTENNA1        0
+#define IWL_SISO_SWITCH_ANTENNA2        1
+#define IWL_SISO_SWITCH_MIMO2_AB        2
+#define IWL_SISO_SWITCH_MIMO2_AC        3
+#define IWL_SISO_SWITCH_MIMO2_BC        4
+#define IWL_SISO_SWITCH_GI              5
+#define IWL_SISO_SWITCH_MIMO3_ABC       6
+
+
+/* possible actions when in mimo mode */
+#define IWL_MIMO2_SWITCH_ANTENNA1       0
+#define IWL_MIMO2_SWITCH_ANTENNA2       1
+#define IWL_MIMO2_SWITCH_SISO_A         2
+#define IWL_MIMO2_SWITCH_SISO_B         3
+#define IWL_MIMO2_SWITCH_SISO_C         4
+#define IWL_MIMO2_SWITCH_GI             5
+#define IWL_MIMO2_SWITCH_MIMO3_ABC      6
+
+
+/* possible actions when in mimo3 mode */
+#define IWL_MIMO3_SWITCH_ANTENNA1       0
+#define IWL_MIMO3_SWITCH_ANTENNA2       1
+#define IWL_MIMO3_SWITCH_SISO_A         2
+#define IWL_MIMO3_SWITCH_SISO_B         3
+#define IWL_MIMO3_SWITCH_SISO_C         4
+#define IWL_MIMO3_SWITCH_MIMO2_AB       5
+#define IWL_MIMO3_SWITCH_MIMO2_AC       6
+#define IWL_MIMO3_SWITCH_MIMO2_BC       7
+#define IWL_MIMO3_SWITCH_GI             8
+
+
+#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
+#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
+
+/*FIXME:RS:add possible actions for MIMO3*/
+
+#define IWL_ACTION_LIMIT               3       /* # possible actions */
+
+#define LQ_SIZE                2       /* 2 mode tables:  "Active" and "Search" */
+
+/* load per tid defines for A-MPDU activation */
+#define IWL_AGG_TPT_THREHOLD   0
+#define IWL_AGG_LOAD_THRESHOLD 10
+#define IWL_AGG_ALL_TID                0xff
+#define TID_QUEUE_CELL_SPACING 50      /*mS */
+#define TID_QUEUE_MAX_SIZE     20
+#define TID_ROUND_VALUE                5       /* mS */
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+enum iwl_table_type {
+       LQ_NONE,
+       LQ_G,           /* legacy types */
+       LQ_A,
+       LQ_SISO,        /* high-throughput types */
+       LQ_MIMO2,
+       LQ_MIMO3,
+       LQ_MAX,
+};
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) ((tbl) == LQ_A)
+#define is_g_and(tbl) ((tbl) == LQ_G)
+
+#define IWL_MAX_MCS_DISPLAY_SIZE       12
+
+struct iwl_rate_mcs_info {
+       char    mbps[IWL_MAX_MCS_DISPLAY_SIZE];
+       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;
+
+       /* 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;
+       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[IWL_MAX_TID_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;
+       /* BT traffic this sta was last updated in */
+       u8 last_bt_traffic;
+};
+
+static inline u8 num_of_ant(u8 mask)
+{
+       return  !!((mask) & ANT_A) +
+               !!((mask) & ANT_B) +
+               !!((mask) & ANT_C);
+}
+
+static inline u8 first_antenna(u8 mask)
+{
+       if (mask & ANT_A)
+               return ANT_A;
+       if (mask & ANT_B)
+               return ANT_B;
+       return ANT_C;
+}
+
+
+/* Initialize station's rate scaling information after adding station */
+extern void iwl_rs_rate_init(struct iwl_priv *priv,
+                            struct ieee80211_sta *sta, u8 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module.  The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem.  This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern int iwlagn_rate_control_register(void);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwlagn_rate_control_unregister(void);
+
+#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c
new file mode 100644 (file)
index 0000000..c1f7a18
--- /dev/null
@@ -0,0 +1,1164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portionhelp of the ieee80211 subsystem header files.
+ *
+ * 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/etherdevice.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+#include "iwl-io.h"
+#include "dev.h"
+#include "calib.h"
+#include "agn.h"
+
+#define IWL_CMD_ENTRY(x) [x] = #x
+
+const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
+       IWL_CMD_ENTRY(REPLY_ALIVE),
+       IWL_CMD_ENTRY(REPLY_ERROR),
+       IWL_CMD_ENTRY(REPLY_ECHO),
+       IWL_CMD_ENTRY(REPLY_RXON),
+       IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
+       IWL_CMD_ENTRY(REPLY_QOS_PARAM),
+       IWL_CMD_ENTRY(REPLY_RXON_TIMING),
+       IWL_CMD_ENTRY(REPLY_ADD_STA),
+       IWL_CMD_ENTRY(REPLY_REMOVE_STA),
+       IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
+       IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
+       IWL_CMD_ENTRY(REPLY_WEPKEY),
+       IWL_CMD_ENTRY(REPLY_TX),
+       IWL_CMD_ENTRY(REPLY_LEDS_CMD),
+       IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
+       IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
+       IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
+       IWL_CMD_ENTRY(COEX_EVENT_CMD),
+       IWL_CMD_ENTRY(REPLY_QUIET_CMD),
+       IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
+       IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
+       IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
+       IWL_CMD_ENTRY(POWER_TABLE_CMD),
+       IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
+       IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
+       IWL_CMD_ENTRY(REPLY_SCAN_CMD),
+       IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
+       IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
+       IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
+       IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
+       IWL_CMD_ENTRY(BEACON_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_TX_BEACON),
+       IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
+       IWL_CMD_ENTRY(QUIET_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
+       IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_BT_CONFIG),
+       IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
+       IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
+       IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
+       IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
+       IWL_CMD_ENTRY(SENSITIVITY_CMD),
+       IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
+       IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
+       IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
+       IWL_CMD_ENTRY(REPLY_RX),
+       IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
+       IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
+       IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
+       IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
+       IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
+       IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
+       IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
+       IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
+       IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
+       IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
+       IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
+       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
+       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
+       IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
+       IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
+       IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
+       IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
+       IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
+       IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
+       IWL_CMD_ENTRY(REPLY_D3_CONFIG),
+};
+#undef IWL_CMD_ENTRY
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+
+static int iwlagn_rx_reply_error(struct iwl_priv *priv,
+                              struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_error_resp *err_resp = (void *)pkt->data;
+
+       IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
+               "seq 0x%04X ser 0x%08X\n",
+               le32_to_cpu(err_resp->error_type),
+               err_resp->cmd_id,
+               le16_to_cpu(err_resp->bad_cmd_seq_num),
+               le32_to_cpu(err_resp->error_info));
+       return 0;
+}
+
+static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_csa_notification *csa = (void *)pkt->data;
+       /*
+        * MULTI-FIXME
+        * See iwlagn_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
+
+       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               return 0;
+
+       if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
+               rxon->channel = csa->channel;
+               ctx->staging.channel = csa->channel;
+               IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
+                             le16_to_cpu(csa->channel));
+               iwl_chswitch_done(priv, true);
+       } else {
+               IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+                       le16_to_cpu(csa->channel));
+               iwl_chswitch_done(priv, false);
+       }
+       return 0;
+}
+
+
+static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
+                                         struct iwl_rx_cmd_buffer *rxb,
+                                         struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_spectrum_notification *report = (void *)pkt->data;
+
+       if (!report->state) {
+               IWL_DEBUG_11H(priv,
+                       "Spectrum Measure Notification: Start\n");
+               return 0;
+       }
+
+       memcpy(&priv->measure_report, report, sizeof(*report));
+       priv->measurement_status |= MEASUREMENT_READY;
+       return 0;
+}
+
+static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_cmd_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_sleep_notification *sleep = (void *)pkt->data;
+       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
+                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+       return 0;
+}
+
+static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                            struct iwl_rx_cmd_buffer *rxb,
+                                            struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       u32 __maybe_unused len =
+               le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
+                       "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
+       return 0;
+}
+
+static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_cmd_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwlagn_beacon_notif *beacon = (void *)pkt->data;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
+       u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+       IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d "
+               "tsf:0x%.8x%.8x rate:%d\n",
+               status & TX_STATUS_MSK,
+               beacon->beacon_notify_hdr.failure_frame,
+               le32_to_cpu(beacon->ibss_mgr_status),
+               le32_to_cpu(beacon->high_tsf),
+               le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+       priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
+       return 0;
+}
+
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
+                                struct statistics_rx_phy *cur_ofdm,
+                                struct statistics_rx_ht_phy *cur_ofdm_ht,
+                                unsigned int msecs)
+{
+       int delta;
+       int threshold = priv->plcp_delta_threshold;
+
+       if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
+               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
+               return true;
+       }
+
+       delta = le32_to_cpu(cur_ofdm->plcp_err) -
+               le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
+               le32_to_cpu(cur_ofdm_ht->plcp_err) -
+               le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
+
+       /* Can be negative if firmware reset statistics */
+       if (delta <= 0)
+               return true;
+
+       if ((delta * 100 / msecs) > threshold) {
+               IWL_DEBUG_RADIO(priv,
+                               "plcp health threshold %u delta %d msecs %u\n",
+                               threshold, delta, msecs);
+               return false;
+       }
+
+       return true;
+}
+
+int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
+{
+       struct iwl_rf_reset *rf_reset;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return -EAGAIN;
+
+       if (!iwl_is_any_associated(priv)) {
+               IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
+               return -ENOLINK;
+       }
+
+       rf_reset = &priv->rf_reset;
+       rf_reset->reset_request_count++;
+       if (!external && rf_reset->last_reset_jiffies &&
+           time_after(rf_reset->last_reset_jiffies +
+                      IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
+               IWL_DEBUG_INFO(priv, "RF reset rejected\n");
+               rf_reset->reset_reject_count++;
+               return -EAGAIN;
+       }
+       rf_reset->reset_success_count++;
+       rf_reset->last_reset_jiffies = jiffies;
+
+       /*
+        * There is no easy and better way to force reset the radio,
+        * the only known method is switching channel which will force to
+        * reset and tune the radio.
+        * Use internal short scan (single channel) operation to should
+        * achieve this objective.
+        * Driver should reset the radio when number of consecutive missed
+        * beacon, or any other uCode error condition detected.
+        */
+       IWL_DEBUG_INFO(priv, "perform radio reset.\n");
+       iwl_internal_short_hw_scan(priv);
+       return 0;
+}
+
+
+static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
+                               struct statistics_rx_phy *cur_ofdm,
+                               struct statistics_rx_ht_phy *cur_ofdm_ht,
+                               struct statistics_tx *tx,
+                               unsigned long stamp)
+{
+       unsigned int msecs;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
+
+       /* Only gather statistics and update time stamp when not associated */
+       if (!iwl_is_any_associated(priv))
+               return;
+
+       /* Do not check/recover when do not have enough statistics data */
+       if (msecs < 99)
+               return;
+
+       if (iwlwifi_mod_params.plcp_check &&
+           !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
+               iwl_force_rf_reset(priv, false);
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ *   before arriving beacon.  This measurement can be done only if we know
+ *   exactly when to expect beacons, therefore only when we're associated. */
+static void iwlagn_rx_calc_noise(struct iwl_priv *priv)
+{
+       struct statistics_rx_non_phy *rx_info;
+       int num_active_rx = 0;
+       int total_silence = 0;
+       int bcn_silence_a, bcn_silence_b, bcn_silence_c;
+       int last_rx_noise;
+
+       rx_info = &priv->statistics.rx_non_phy;
+
+       bcn_silence_a =
+               le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+       bcn_silence_b =
+               le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+       bcn_silence_c =
+               le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+       if (bcn_silence_a) {
+               total_silence += bcn_silence_a;
+               num_active_rx++;
+       }
+       if (bcn_silence_b) {
+               total_silence += bcn_silence_b;
+               num_active_rx++;
+       }
+       if (bcn_silence_c) {
+               total_silence += bcn_silence_c;
+               num_active_rx++;
+       }
+
+       /* Average among active antennas */
+       if (num_active_rx)
+               last_rx_noise = (total_silence / num_active_rx) - 107;
+       else
+               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+       IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
+                       bcn_silence_a, bcn_silence_b, bcn_silence_c,
+                       last_rx_noise);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/*
+ *  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 accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
+                       __le32 *max_delta, __le32 *accum, int size)
+{
+       int i;
+
+       for (i = 0;
+            i < size / sizeof(__le32);
+            i++, prev++, cur++, delta++, max_delta++, accum++) {
+               if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
+                       *delta = cpu_to_le32(
+                               le32_to_cpu(*cur) - le32_to_cpu(*prev));
+                       le32_add_cpu(accum, le32_to_cpu(*delta));
+                       if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
+                               *max_delta = *delta;
+               }
+       }
+}
+
+static void
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
+                           struct statistics_general_common *common,
+                           struct statistics_rx_non_phy *rx_non_phy,
+                           struct statistics_rx_phy *rx_ofdm,
+                           struct statistics_rx_ht_phy *rx_ofdm_ht,
+                           struct statistics_rx_phy *rx_cck,
+                           struct statistics_tx *tx,
+                           struct statistics_bt_activity *bt_activity)
+{
+#define ACCUM(_name)   \
+       accum_stats((__le32 *)&priv->statistics._name,          \
+                   (__le32 *)_name,                            \
+                   (__le32 *)&priv->delta_stats._name,         \
+                   (__le32 *)&priv->max_delta_stats._name,     \
+                   (__le32 *)&priv->accum_stats._name,         \
+                   sizeof(*_name));
+
+       ACCUM(common);
+       ACCUM(rx_non_phy);
+       ACCUM(rx_ofdm);
+       ACCUM(rx_ofdm_ht);
+       ACCUM(rx_cck);
+       ACCUM(tx);
+       if (bt_activity)
+               ACCUM(bt_activity);
+#undef ACCUM
+}
+#else
+static inline void
+iwlagn_accumulative_statistics(struct iwl_priv *priv,
+                           struct statistics_general_common *common,
+                           struct statistics_rx_non_phy *rx_non_phy,
+                           struct statistics_rx_phy *rx_ofdm,
+                           struct statistics_rx_ht_phy *rx_ofdm_ht,
+                           struct statistics_rx_phy *rx_cck,
+                           struct statistics_tx *tx,
+                           struct statistics_bt_activity *bt_activity)
+{
+}
+#endif
+
+static int iwlagn_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_cmd_buffer *rxb,
+                             struct iwl_device_cmd *cmd)
+{
+       unsigned long stamp = jiffies;
+       const int reg_recalib_period = 60;
+       int change;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       __le32 *flag;
+       struct statistics_general_common *common;
+       struct statistics_rx_non_phy *rx_non_phy;
+       struct statistics_rx_phy *rx_ofdm;
+       struct statistics_rx_ht_phy *rx_ofdm_ht;
+       struct statistics_rx_phy *rx_cck;
+       struct statistics_tx *tx;
+       struct statistics_bt_activity *bt_activity;
+
+       len -= sizeof(struct iwl_cmd_header); /* skip header */
+
+       IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
+                    len);
+
+       spin_lock(&priv->statistics.lock);
+
+       if (len == sizeof(struct iwl_bt_notif_statistics)) {
+               struct iwl_bt_notif_statistics *stats;
+               stats = (void *)&pkt->data;
+               flag = &stats->flag;
+               common = &stats->general.common;
+               rx_non_phy = &stats->rx.general.common;
+               rx_ofdm = &stats->rx.ofdm;
+               rx_ofdm_ht = &stats->rx.ofdm_ht;
+               rx_cck = &stats->rx.cck;
+               tx = &stats->tx;
+               bt_activity = &stats->general.activity;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               /* handle this exception directly */
+               priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
+               le32_add_cpu(&priv->statistics.accum_num_bt_kills,
+                            le32_to_cpu(stats->rx.general.num_bt_kills));
+#endif
+       } else if (len == sizeof(struct iwl_notif_statistics)) {
+               struct iwl_notif_statistics *stats;
+               stats = (void *)&pkt->data;
+               flag = &stats->flag;
+               common = &stats->general.common;
+               rx_non_phy = &stats->rx.general;
+               rx_ofdm = &stats->rx.ofdm;
+               rx_ofdm_ht = &stats->rx.ofdm_ht;
+               rx_cck = &stats->rx.cck;
+               tx = &stats->tx;
+               bt_activity = NULL;
+       } else {
+               WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
+                         len, sizeof(struct iwl_bt_notif_statistics),
+                         sizeof(struct iwl_notif_statistics));
+               spin_unlock(&priv->statistics.lock);
+               return 0;
+       }
+
+       change = common->temperature != priv->statistics.common.temperature ||
+                (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+                (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
+
+       iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
+                                   rx_ofdm_ht, rx_cck, tx, bt_activity);
+
+       iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
+
+       priv->statistics.flag = *flag;
+       memcpy(&priv->statistics.common, common, sizeof(*common));
+       memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
+       memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
+       memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
+       memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
+       memcpy(&priv->statistics.tx, tx, sizeof(*tx));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (bt_activity)
+               memcpy(&priv->statistics.bt_activity, bt_activity,
+                       sizeof(*bt_activity));
+#endif
+
+       priv->rx_statistics_jiffies = stamp;
+
+       set_bit(STATUS_STATISTICS, &priv->status);
+
+       /* Reschedule the statistics timer to occur in
+        * reg_recalib_period seconds to ensure we get a
+        * thermal update even if the uCode doesn't give
+        * us one */
+       mod_timer(&priv->statistics_periodic, jiffies +
+                 msecs_to_jiffies(reg_recalib_period * 1000));
+
+       if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+           (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+               iwlagn_rx_calc_noise(priv);
+               queue_work(priv->workqueue, &priv->run_time_calib_work);
+       }
+       if (priv->lib->temperature && change)
+               priv->lib->temperature(priv);
+
+       spin_unlock(&priv->statistics.lock);
+
+       return 0;
+}
+
+static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
+                                   struct iwl_rx_cmd_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_notif_statistics *stats = (void *)pkt->data;
+
+       if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               memset(&priv->accum_stats, 0,
+                       sizeof(priv->accum_stats));
+               memset(&priv->delta_stats, 0,
+                       sizeof(priv->delta_stats));
+               memset(&priv->max_delta_stats, 0,
+                       sizeof(priv->max_delta_stats));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwlagn_rx_statistics(priv, rxb, cmd);
+       return 0;
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
+                                   struct iwl_rx_cmd_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
+       u32 flags = le32_to_cpu(card_state_notif->flags);
+       unsigned long status = priv->status;
+
+       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
+                         (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+                         (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+                         (flags & CT_CARD_DISABLED) ?
+                         "Reached" : "Not reached");
+
+       if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+                    CT_CARD_DISABLED)) {
+
+               iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
+                           CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+               iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
+                                       HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+               if (!(flags & RXON_CARD_DISABLED)) {
+                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+                                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+                       iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
+                                       HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+               }
+               if (flags & CT_CARD_DISABLED)
+                       iwl_tt_enter_ct_kill(priv);
+       }
+       if (!(flags & CT_CARD_DISABLED))
+               iwl_tt_exit_ct_kill(priv);
+
+       if (flags & HW_CARD_DISABLED)
+               set_bit(STATUS_RF_KILL_HW, &priv->status);
+       else
+               clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+       if (!(flags & RXON_CARD_DISABLED))
+               iwl_scan_cancel(priv);
+
+       if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+            test_bit(STATUS_RF_KILL_HW, &priv->status)))
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+                       test_bit(STATUS_RF_KILL_HW, &priv->status));
+       else
+               wake_up(&priv->trans->wait_command_queue);
+       return 0;
+}
+
+static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
+                                      struct iwl_rx_cmd_buffer *rxb,
+                                      struct iwl_device_cmd *cmd)
+
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data;
+
+       if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+           priv->missed_beacon_threshold) {
+               IWL_DEBUG_CALIB(priv,
+                   "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+                   le32_to_cpu(missed_beacon->consecutive_missed_beacons),
+                   le32_to_cpu(missed_beacon->total_missed_becons),
+                   le32_to_cpu(missed_beacon->num_recvd_beacons),
+                   le32_to_cpu(missed_beacon->num_expected_beacons));
+               if (!test_bit(STATUS_SCANNING, &priv->status))
+                       iwl_init_sensitivity(priv);
+       }
+       return 0;
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+                               struct iwl_rx_cmd_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+       priv->last_phy_res_valid = true;
+       memcpy(&priv->last_phy_res, pkt->data,
+              sizeof(struct iwl_rx_phy_res));
+       return 0;
+}
+
+/*
+ * returns non-zero if packet should be dropped
+ */
+static int iwlagn_set_decrypted_flag(struct iwl_priv *priv,
+                                 struct ieee80211_hdr *hdr,
+                                 u32 decrypt_res,
+                                 struct ieee80211_rx_status *stats)
+{
+       u16 fc = le16_to_cpu(hdr->frame_control);
+
+       /*
+        * All contexts have the same setting here due to it being
+        * a module parameter, so OK to check any context.
+        */
+       if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
+                                               RXON_FILTER_DIS_DECRYPT_MSK)
+               return 0;
+
+       if (!(fc & IEEE80211_FCTL_PROTECTED))
+               return 0;
+
+       IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res);
+       switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+       case RX_RES_STATUS_SEC_TYPE_TKIP:
+               /* The uCode has got a bad phase 1 Key, pushes the packet.
+                * Decryption will be done in SW. */
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_BAD_KEY_TTAK)
+                       break;
+
+       case RX_RES_STATUS_SEC_TYPE_WEP:
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_BAD_ICV_MIC) {
+                       /* bad ICV, the packet is destroyed since the
+                        * decryption is inplace, drop it */
+                       IWL_DEBUG_RX(priv, "Packet destroyed\n");
+                       return -1;
+               }
+       case RX_RES_STATUS_SEC_TYPE_CCMP:
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_DECRYPT_OK) {
+                       IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
+                       stats->flag |= RX_FLAG_DECRYPTED;
+               }
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
+                                       struct ieee80211_hdr *hdr,
+                                       u16 len,
+                                       u32 ampdu_status,
+                                       struct iwl_rx_cmd_buffer *rxb,
+                                       struct ieee80211_rx_status *stats)
+{
+       struct sk_buff *skb;
+       __le16 fc = hdr->frame_control;
+       struct iwl_rxon_context *ctx;
+       unsigned int hdrlen, fraglen;
+
+       /* We only process data packets if the interface is open */
+       if (unlikely(!priv->is_open)) {
+               IWL_DEBUG_DROP_LIMIT(priv,
+                   "Dropping packet while interface is not open.\n");
+               return;
+       }
+
+       /* In case of HW accelerated crypto and bad decryption, drop */
+       if (!iwlwifi_mod_params.sw_crypto &&
+           iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+               return;
+
+       /* Dont use dev_alloc_skb(), we'll have enough headroom once
+        * ieee80211_hdr pulled.
+        */
+       skb = alloc_skb(128, GFP_ATOMIC);
+       if (!skb) {
+               IWL_ERR(priv, "alloc_skb failed\n");
+               return;
+       }
+       /* If frame is small enough to fit in skb->head, pull it completely.
+        * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
+        * are more efficient.
+        */
+       hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+
+       memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
+       fraglen = len - hdrlen;
+
+       if (fraglen) {
+               int offset = (void *)hdr + hdrlen -
+                            rxb_addr(rxb) + rxb_offset(rxb);
+
+               skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
+                               fraglen, rxb->truesize);
+       }
+
+       /*
+       * Wake any queues that were stopped due to a passive channel tx
+       * failure. This can happen because the regulatory enforcement in
+       * the device waits for a beacon before allowing transmission,
+       * sometimes even after already having transmitted frames for the
+       * association because the new RXON may reset the information.
+       */
+       if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
+               for_each_context(priv, ctx) {
+                       if (!ether_addr_equal(hdr->addr3,
+                                             ctx->active.bssid_addr))
+                               continue;
+                       iwlagn_lift_passive_no_rx(priv);
+               }
+       }
+
+       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+       ieee80211_rx(priv->hw, skb);
+}
+
+static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
+{
+       u32 decrypt_out = 0;
+
+       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
+                                       RX_RES_STATUS_STATION_FOUND)
+               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
+                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
+
+       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
+
+       /* packet was not encrypted */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_NONE)
+               return decrypt_out;
+
+       /* packet was encrypted with unknown alg */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_ERR)
+               return decrypt_out;
+
+       /* decryption was not done in HW */
+       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
+                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
+               return decrypt_out;
+
+       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
+
+       case RX_RES_STATUS_SEC_TYPE_CCMP:
+               /* alg is CCM: check MIC only */
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
+                       /* Bad MIC */
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+
+               break;
+
+       case RX_RES_STATUS_SEC_TYPE_TKIP:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
+                       /* Bad TTAK */
+                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
+                       break;
+               }
+               /* fall through if TTAK OK */
+       default:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+               break;
+       }
+
+       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
+                                       decrypt_in, decrypt_out);
+
+       return decrypt_out;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwlagn_calc_rssi(struct iwl_priv *priv,
+                            struct iwl_rx_phy_res *rx_resp)
+{
+       /* data from PHY/DSP regarding signal strength, etc.,
+        *   contents are always there, not configurable by host
+        */
+       struct iwlagn_non_cfg_phy *ncphy =
+               (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+       u8 agc;
+
+       val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
+       agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
+
+       /* Find max rssi among 3 possible receivers.
+        * These values are measured by the digital signal processor (DSP).
+        * They should stay fairly constant even as the signal strength varies,
+        *   if the radio's automatic gain control (AGC) is working right.
+        * AGC value (see below) will provide the "interesting" info.
+        */
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
+       rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
+               IWLAGN_OFDM_RSSI_A_BIT_POS;
+       rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
+               IWLAGN_OFDM_RSSI_B_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
+       rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
+               IWLAGN_OFDM_RSSI_C_BIT_POS;
+
+       max_rssi = max_t(u32, rssi_a, rssi_b);
+       max_rssi = max_t(u32, max_rssi, rssi_c);
+
+       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+               rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+       /* dBm = max_rssi dB - agc dB - constant.
+        * Higher AGC (higher radio gain) means lower signal. */
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
+}
+
+/* Called for REPLY_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
+                           struct iwl_rx_cmd_buffer *rxb,
+                           struct iwl_device_cmd *cmd)
+{
+       struct ieee80211_hdr *header;
+       struct ieee80211_rx_status rx_status;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rx_phy_res *phy_res;
+       __le32 rx_pkt_status;
+       struct iwl_rx_mpdu_res_start *amsdu;
+       u32 len;
+       u32 ampdu_status;
+       u32 rate_n_flags;
+
+       /**
+        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+        *      REPLY_RX: physical layer info is in this buffer
+        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+        *              command and cached in priv->last_phy_res
+        *
+        * Here we set up local variables depending on which command is
+        * received.
+        */
+       if (pkt->hdr.cmd == REPLY_RX) {
+               phy_res = (struct iwl_rx_phy_res *)pkt->data;
+               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res)
+                               + phy_res->cfg_phy_cnt);
+
+               len = le16_to_cpu(phy_res->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) +
+                               phy_res->cfg_phy_cnt + len);
+               ampdu_status = le32_to_cpu(rx_pkt_status);
+       } else {
+               if (!priv->last_phy_res_valid) {
+                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+                       return 0;
+               }
+               phy_res = &priv->last_phy_res;
+               amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data;
+               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu));
+               len = le16_to_cpu(amsdu->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len);
+               ampdu_status = iwlagn_translate_rx_status(priv,
+                                               le32_to_cpu(rx_pkt_status));
+       }
+
+       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
+               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",
+                               phy_res->cfg_phy_cnt);
+               return 0;
+       }
+
+       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+                               le32_to_cpu(rx_pkt_status));
+               return 0;
+       }
+
+       /* This will be used in several places later */
+       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+       /* rx_status carries information about the packet to mac80211 */
+       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+       rx_status.freq =
+               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
+                                              rx_status.band);
+       rx_status.rate_idx =
+               iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
+       rx_status.flag = 0;
+
+       /* TSF isn't reliable. In order to allow smooth user experience,
+        * this W/A doesn't propagate it to the mac80211 */
+       /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
+
+       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
+
+       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+       rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
+
+       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
+               rx_status.signal, (unsigned long long)rx_status.mactime);
+
+       /*
+        * "antenna number"
+        *
+        * It seems that the antenna field in the phy flags value
+        * is actually a bit field. This is undefined by radiotap,
+        * it wants an actual antenna number but I always get "7"
+        * for most legacy frames I receive indicating that the
+        * same frame was received on all three RX chains.
+        *
+        * I think this field should be removed in favor of a
+        * new 802.11n radiotap field "RX chains" that is defined
+        * as a bitmask.
+        */
+       rx_status.antenna =
+               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+       /* set the preamble flag if appropriate */
+       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+               rx_status.flag |= RX_FLAG_SHORTPRE;
+
+       /* Set up the HT phy flags */
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               rx_status.flag |= RX_FLAG_HT;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               rx_status.flag |= RX_FLAG_40MHZ;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               rx_status.flag |= RX_FLAG_SHORT_GI;
+       if (rate_n_flags & RATE_MCS_GF_MSK)
+               rx_status.flag |= RX_FLAG_HT_GF;
+
+       iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+                                   rxb, &rx_status);
+       return 0;
+}
+
+static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
+                                     struct iwl_rx_cmd_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
+{
+       struct iwl_wipan_noa_data *new_data, *old_data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data;
+
+       /* no condition -- we're in softirq */
+       old_data = rcu_dereference_protected(priv->noa_data, true);
+
+       if (noa_notif->noa_active) {
+               u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
+               u32 copylen = len;
+
+               /* EID, len, OUI, subtype */
+               len += 1 + 1 + 3 + 1;
+               /* P2P id, P2P length */
+               len += 1 + 2;
+               copylen += 1 + 2;
+
+               new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
+               if (new_data) {
+                       new_data->length = len;
+                       new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
+                       new_data->data[1] = len - 2; /* not counting EID, len */
+                       new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+                       new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+                       new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+                       new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
+                       memcpy(&new_data->data[6], &noa_notif->noa_attribute,
+                              copylen);
+               }
+       } else
+               new_data = NULL;
+
+       rcu_assign_pointer(priv->noa_data, new_data);
+
+       if (old_data)
+               kfree_rcu(old_data, rcu_head);
+
+       return 0;
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ */
+void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
+
+       handlers = priv->rx_handlers;
+
+       handlers[REPLY_ERROR]                   = iwlagn_rx_reply_error;
+       handlers[CHANNEL_SWITCH_NOTIFICATION]   = iwlagn_rx_csa;
+       handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+               iwlagn_rx_spectrum_measure_notif;
+       handlers[PM_SLEEP_NOTIFICATION]         = iwlagn_rx_pm_sleep_notif;
+       handlers[PM_DEBUG_STATISTIC_NOTIFIC]    =
+               iwlagn_rx_pm_debug_statistics_notif;
+       handlers[BEACON_NOTIFICATION]           = iwlagn_rx_beacon_notif;
+       handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
+
+       handlers[REPLY_WIPAN_NOA_NOTIFICATION]  = iwlagn_rx_noa_notification;
+
+       /*
+        * The same handler is used for both the REPLY to a discrete
+        * statistics request from the host as well as for the periodic
+        * statistics notifications (after received beacons) from the uCode.
+        */
+       handlers[REPLY_STATISTICS_CMD]          = iwlagn_rx_reply_statistics;
+       handlers[STATISTICS_NOTIFICATION]       = iwlagn_rx_statistics;
+
+       iwl_setup_rx_scan_handlers(priv);
+
+       handlers[CARD_STATE_NOTIFICATION]       = iwlagn_rx_card_state_notif;
+       handlers[MISSED_BEACONS_NOTIFICATION]   =
+               iwlagn_rx_missed_beacon_notif;
+
+       /* Rx handlers */
+       handlers[REPLY_RX_PHY_CMD]              = iwlagn_rx_reply_rx_phy;
+       handlers[REPLY_RX_MPDU_CMD]             = iwlagn_rx_reply_rx;
+
+       /* block ack */
+       handlers[REPLY_COMPRESSED_BA]           =
+               iwlagn_rx_reply_compressed_ba;
+
+       priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
+
+       /* set up notification wait support */
+       iwl_notification_wait_init(&priv->notif_wait);
+
+       /* Set up BT Rx handlers */
+       if (priv->cfg->bt_params)
+               iwlagn_bt_rx_handler_setup(priv);
+}
+
+int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
+                   struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       int err = 0;
+
+       /*
+        * Do the notification wait before RX handlers so
+        * even if the RX handler consumes the RXB we have
+        * access to it in the notification wait entry.
+        */
+       iwl_notification_wait_notify(&priv->notif_wait, pkt);
+
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+       /*
+        * RX data may be forwarded to userspace in one
+        * of two cases: the user owns the fw through testmode or when
+        * the user requested to monitor the rx w/o affecting the regular flow.
+        * In these cases the iwl_test object will handle forwarding the rx
+        * data to user space.
+        * Note that if the ownership flag != IWL_OWNERSHIP_TM the flow
+        * continues.
+        */
+       iwl_test_rx(&priv->tst, rxb);
+#endif
+
+       if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
+               /* Based on type of command response or notification,
+                *   handle those that need handling via function in
+                *   rx_handlers table.  See iwl_setup_rx_handlers() */
+               if (priv->rx_handlers[pkt->hdr.cmd]) {
+                       priv->rx_handlers_stats[pkt->hdr.cmd]++;
+                       err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
+               } else {
+                       /* No handling needed */
+                       IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
+                                    iwl_dvm_get_cmd_string(pkt->hdr.cmd),
+                                    pkt->hdr.cmd);
+               }
+       }
+       return err;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
new file mode 100644 (file)
index 0000000..6ee940f
--- /dev/null
@@ -0,0 +1,1577 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 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/etherdevice.h>
+#include "iwl-trans.h"
+#include "iwl-modparams.h"
+#include "dev.h"
+#include "agn.h"
+#include "calib.h"
+
+/*
+ * initialize rxon structure with default values from eeprom
+ */
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx)
+{
+       memset(&ctx->staging, 0, sizeof(ctx->staging));
+
+       if (!ctx->vif) {
+               ctx->staging.dev_type = ctx->unused_devtype;
+       } else
+       switch (ctx->vif->type) {
+       case NL80211_IFTYPE_AP:
+               ctx->staging.dev_type = ctx->ap_devtype;
+               break;
+
+       case NL80211_IFTYPE_STATION:
+               ctx->staging.dev_type = ctx->station_devtype;
+               ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+               break;
+
+       case NL80211_IFTYPE_ADHOC:
+               ctx->staging.dev_type = ctx->ibss_devtype;
+               ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+                                                 RXON_FILTER_ACCEPT_GRP_MSK;
+               break;
+
+       case NL80211_IFTYPE_MONITOR:
+               ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
+               break;
+
+       default:
+               IWL_ERR(priv, "Unsupported interface type %d\n",
+                       ctx->vif->type);
+               break;
+       }
+
+#if 0
+       /* TODO:  Figure out when short_preamble would be set and cache from
+        * that */
+       if (!hw_to_local(priv->hw)->short_preamble)
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+       else
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+       ctx->staging.channel = cpu_to_le16(priv->hw->conf.channel->hw_value);
+       priv->band = priv->hw->conf.channel->band;
+
+       iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
+
+       /* clear both MIX and PURE40 mode flag */
+       ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+                                       RXON_FLG_CHANNEL_MODE_PURE_40);
+       if (ctx->vif)
+               memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
+
+       ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
+}
+
+static int iwlagn_disable_bss(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_rxon_cmd *send)
+{
+       __le32 old_filter = send->filter_flags;
+       int ret;
+
+       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
+                               CMD_SYNC, sizeof(*send), send);
+
+       send->filter_flags = old_filter;
+
+       if (ret)
+               IWL_DEBUG_QUIET_RFKILL(priv,
+                       "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+
+       return ret;
+}
+
+static int iwlagn_disable_pan(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_rxon_cmd *send)
+{
+       struct iwl_notification_wait disable_wait;
+       __le32 old_filter = send->filter_flags;
+       u8 old_dev_type = send->dev_type;
+       int ret;
+       static const u8 deactivate_cmd[] = {
+               REPLY_WIPAN_DEACTIVATION_COMPLETE
+       };
+
+       iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
+                                  deactivate_cmd, ARRAY_SIZE(deactivate_cmd),
+                                  NULL, NULL);
+
+       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       send->dev_type = RXON_DEV_TYPE_P2P;
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
+                               CMD_SYNC, sizeof(*send), send);
+
+       send->filter_flags = old_filter;
+       send->dev_type = old_dev_type;
+
+       if (ret) {
+               IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
+               iwl_remove_notification(&priv->notif_wait, &disable_wait);
+       } else {
+               ret = iwl_wait_notification(&priv->notif_wait,
+                                           &disable_wait, HZ);
+               if (ret)
+                       IWL_ERR(priv, "Timed out waiting for PAN disable\n");
+       }
+
+       return ret;
+}
+
+static int iwlagn_disconn_pan(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_rxon_cmd *send)
+{
+       __le32 old_filter = send->filter_flags;
+       int ret;
+
+       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
+                               sizeof(*send), send);
+
+       send->filter_flags = old_filter;
+
+       return ret;
+}
+
+static void iwlagn_update_qos(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx)
+{
+       int ret;
+
+       if (!ctx->is_active)
+               return;
+
+       ctx->qos_data.def_qos_parm.qos_flags = 0;
+
+       if (ctx->qos_data.qos_active)
+               ctx->qos_data.def_qos_parm.qos_flags |=
+                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+       if (ctx->ht.enabled)
+               ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+       IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+                     ctx->qos_data.qos_active,
+                     ctx->qos_data.def_qos_parm.qos_flags);
+
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
+                              sizeof(struct iwl_qosparam_cmd),
+                              &ctx->qos_data.def_qos_parm);
+       if (ret)
+               IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
+}
+
+static int iwlagn_update_beacon(struct iwl_priv *priv,
+                               struct ieee80211_vif *vif)
+{
+       lockdep_assert_held(&priv->mutex);
+
+       dev_kfree_skb(priv->beacon_skb);
+       priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
+       if (!priv->beacon_skb)
+               return -ENOMEM;
+       return iwlagn_send_beacon_cmd(priv);
+}
+
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+                                 struct iwl_rxon_context *ctx)
+{
+       int ret = 0;
+       struct iwl_rxon_assoc_cmd rxon_assoc;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
+
+       if ((rxon1->flags == rxon2->flags) &&
+           (rxon1->filter_flags == rxon2->filter_flags) &&
+           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+           (rxon1->ofdm_ht_single_stream_basic_rates ==
+            rxon2->ofdm_ht_single_stream_basic_rates) &&
+           (rxon1->ofdm_ht_dual_stream_basic_rates ==
+            rxon2->ofdm_ht_dual_stream_basic_rates) &&
+           (rxon1->ofdm_ht_triple_stream_basic_rates ==
+            rxon2->ofdm_ht_triple_stream_basic_rates) &&
+           (rxon1->acquisition_data == rxon2->acquisition_data) &&
+           (rxon1->rx_chain == rxon2->rx_chain) &&
+           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
+               return 0;
+       }
+
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
+       rxon_assoc.reserved1 = 0;
+       rxon_assoc.reserved2 = 0;
+       rxon_assoc.reserved3 = 0;
+       rxon_assoc.ofdm_ht_single_stream_basic_rates =
+           ctx->staging.ofdm_ht_single_stream_basic_rates;
+       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+           ctx->staging.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
+       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+                ctx->staging.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
+
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
+                               CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
+       return ret;
+}
+
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+       u16 new_val;
+       u16 beacon_factor;
+
+       /*
+        * If mac80211 hasn't given us a beacon interval, program
+        * the default into the device (not checking this here
+        * would cause the adjustment below to return the maximum
+        * value, which may break PAN.)
+        */
+       if (!beacon_val)
+               return DEFAULT_BEACON_INTERVAL;
+
+       /*
+        * If the beacon interval we obtained from the peer
+        * is too large, we'll have to wake up more often
+        * (and in IBSS case, we'll beacon too much)
+        *
+        * For example, if max_beacon_val is 4096, and the
+        * requested beacon interval is 7000, we'll have to
+        * use 3500 to be able to wake up on the beacons.
+        *
+        * This could badly influence beacon detection stats.
+        */
+
+       beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+       new_val = beacon_val / beacon_factor;
+
+       if (!new_val)
+               new_val = max_beacon_val;
+
+       return new_val;
+}
+
+static int iwl_send_rxon_timing(struct iwl_priv *priv,
+                               struct iwl_rxon_context *ctx)
+{
+       u64 tsf;
+       s32 interval_tm, rem;
+       struct ieee80211_conf *conf = NULL;
+       u16 beacon_int;
+       struct ieee80211_vif *vif = ctx->vif;
+
+       conf = &priv->hw->conf;
+
+       lockdep_assert_held(&priv->mutex);
+
+       memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
+
+       ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
+       ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+       beacon_int = vif ? vif->bss_conf.beacon_int : 0;
+
+       /*
+        * TODO: For IBSS we need to get atim_window from mac80211,
+        *       for now just always use 0
+        */
+       ctx->timing.atim_window = 0;
+
+       if (ctx->ctxid == IWL_RXON_CTX_PAN &&
+           (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
+           iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
+           priv->contexts[IWL_RXON_CTX_BSS].vif &&
+           priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
+               ctx->timing.beacon_interval =
+                       priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
+               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+       } else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
+                  iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+                  priv->contexts[IWL_RXON_CTX_PAN].vif &&
+                  priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
+                  (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
+                   !ctx->vif->bss_conf.beacon_int)) {
+               ctx->timing.beacon_interval =
+                       priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
+               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+       } else {
+               beacon_int = iwl_adjust_beacon_interval(beacon_int,
+                       IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
+               ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
+       }
+
+       ctx->beacon_int = beacon_int;
+
+       tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+       interval_tm = beacon_int * TIME_UNIT;
+       rem = do_div(tsf, interval_tm);
+       ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+       ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
+
+       IWL_DEBUG_ASSOC(priv,
+                       "beacon interval %d beacon timer %d beacon tim %d\n",
+                       le16_to_cpu(ctx->timing.beacon_interval),
+                       le32_to_cpu(ctx->timing.beacon_init_val),
+                       le16_to_cpu(ctx->timing.atim_window));
+
+       return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+                               CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
+}
+
+static int iwlagn_rxon_disconn(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       int ret;
+       struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+               ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
+       } else {
+               ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+               if (ret)
+                       return ret;
+               if (ctx->vif) {
+                       ret = iwl_send_rxon_timing(priv, ctx);
+                       if (ret) {
+                               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                               return ret;
+                       }
+                       ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
+               }
+       }
+       if (ret)
+               return ret;
+
+       /*
+        * Un-assoc RXON clears the station table and WEP
+        * keys, so we have to restore those afterwards.
+        */
+       iwl_clear_ucode_stations(priv, ctx);
+       /* update -- might need P2P now */
+       iwl_update_bcast_station(priv, ctx);
+       iwl_restore_stations(priv, ctx);
+       ret = iwl_restore_default_wep_keys(priv, ctx);
+       if (ret) {
+               IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+               return ret;
+       }
+
+       memcpy(active, &ctx->staging, sizeof(*active));
+       return 0;
+}
+
+static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
+{
+       int ret;
+       s8 prev_tx_power;
+       bool defer;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
+       if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
+               return 0;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (priv->tx_power_user_lmt == tx_power && !force)
+               return 0;
+
+       if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
+               IWL_WARN(priv,
+                        "Requested user TXPOWER %d below lower limit %d.\n",
+                        tx_power,
+                        IWLAGN_TX_POWER_TARGET_POWER_MIN);
+               return -EINVAL;
+       }
+
+       if (tx_power > DIV_ROUND_UP(priv->eeprom_data->max_tx_pwr_half_dbm, 2)) {
+               IWL_WARN(priv,
+                       "Requested user TXPOWER %d above upper limit %d.\n",
+                        tx_power, priv->eeprom_data->max_tx_pwr_half_dbm);
+               return -EINVAL;
+       }
+
+       if (!iwl_is_ready_rf(priv))
+               return -EIO;
+
+       /* scan complete and commit_rxon use tx_power_next value,
+        * it always need to be updated for newest request */
+       priv->tx_power_next = tx_power;
+
+       /* do not set tx power when scanning or channel changing */
+       defer = test_bit(STATUS_SCANNING, &priv->status) ||
+               memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
+       if (defer && !force) {
+               IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
+               return 0;
+       }
+
+       prev_tx_power = priv->tx_power_user_lmt;
+       priv->tx_power_user_lmt = tx_power;
+
+       ret = iwlagn_send_tx_power(priv);
+
+       /* if fail to set tx_power, restore the orig. tx power */
+       if (ret) {
+               priv->tx_power_user_lmt = prev_tx_power;
+               priv->tx_power_next = prev_tx_power;
+       }
+       return ret;
+}
+
+static int iwlagn_rxon_connect(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       int ret;
+       struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+       /* RXON timing must be before associated RXON */
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+               ret = iwl_send_rxon_timing(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                       return ret;
+               }
+       }
+       /* QoS info may be cleared by previous un-assoc RXON */
+       iwlagn_update_qos(priv, ctx);
+
+       /*
+        * We'll run into this code path when beaconing is
+        * enabled, but then we also need to send the beacon
+        * to the device.
+        */
+       if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
+               ret = iwlagn_update_beacon(priv, ctx->vif);
+               if (ret) {
+                       IWL_ERR(priv,
+                               "Error sending required beacon (%d)!\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       priv->start_calib = 0;
+       /*
+        * Apply the new configuration.
+        *
+        * Associated RXON doesn't clear the station table in uCode,
+        * so we don't need to restore stations etc. after this.
+        */
+       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
+                     sizeof(struct iwl_rxon_cmd), &ctx->staging);
+       if (ret) {
+               IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+               return ret;
+       }
+       memcpy(active, &ctx->staging, sizeof(*active));
+
+       /* IBSS beacon needs to be sent after setting assoc */
+       if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
+               if (iwlagn_update_beacon(priv, ctx->vif))
+                       IWL_ERR(priv, "Error sending IBSS beacon\n");
+       iwl_init_sensitivity(priv);
+
+       /*
+        * If we issue a new RXON command which required a tune then
+        * we must send a new TXPOWER command or we won't be able to
+        * Tx any frames.
+        *
+        * It's expected we set power here if channel is changing.
+        */
+       ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
+       if (ret) {
+               IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+               return ret;
+       }
+
+       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+           priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
+               ieee80211_request_smps(ctx->vif,
+                                      priv->cfg->ht_params->smps_mode);
+
+       return 0;
+}
+
+int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+       struct iwl_wipan_params_cmd cmd;
+       struct iwl_rxon_context *ctx_bss, *ctx_pan;
+       int slot0 = 300, slot1 = 0;
+       int ret;
+
+       if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+               return 0;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       lockdep_assert_held(&priv->mutex);
+
+       ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+       ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+       /*
+        * If the PAN context is inactive, then we don't need
+        * to update the PAN parameters, the last thing we'll
+        * have done before it goes inactive is making the PAN
+        * parameters be WLAN-only.
+        */
+       if (!ctx_pan->is_active)
+               return 0;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       /* only 2 slots are currently allowed */
+       cmd.num_slots = 2;
+
+       cmd.slots[0].type = 0; /* BSS */
+       cmd.slots[1].type = 1; /* PAN */
+
+       if (priv->hw_roc_setup) {
+               /* both contexts must be used for this to happen */
+               slot1 = IWL_MIN_SLOT_TIME;
+               slot0 = 3000;
+       } else if (ctx_bss->vif && ctx_pan->vif) {
+               int bcnint = ctx_pan->beacon_int;
+               int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
+
+               /* should be set, but seems unused?? */
+               cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+               if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+                   bcnint &&
+                   bcnint != ctx_bss->beacon_int) {
+                       IWL_ERR(priv,
+                               "beacon intervals don't match (%d, %d)\n",
+                               ctx_bss->beacon_int, ctx_pan->beacon_int);
+               } else
+                       bcnint = max_t(int, bcnint,
+                                      ctx_bss->beacon_int);
+               if (!bcnint)
+                       bcnint = DEFAULT_BEACON_INTERVAL;
+               slot0 = bcnint / 2;
+               slot1 = bcnint - slot0;
+
+               if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+                   (!ctx_bss->vif->bss_conf.idle &&
+                    !ctx_bss->vif->bss_conf.assoc)) {
+                       slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
+                       slot1 = IWL_MIN_SLOT_TIME;
+               } else if (!ctx_pan->vif->bss_conf.idle &&
+                          !ctx_pan->vif->bss_conf.assoc) {
+                       slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
+                       slot0 = IWL_MIN_SLOT_TIME;
+               }
+       } else if (ctx_pan->vif) {
+               slot0 = 0;
+               slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+                                       ctx_pan->beacon_int;
+               slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
+
+               if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+                       slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
+                       slot1 = IWL_MIN_SLOT_TIME;
+               }
+       }
+
+       cmd.slots[0].width = cpu_to_le16(slot0);
+       cmd.slots[1].width = cpu_to_le16(slot1);
+
+       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
+                       sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+       return ret;
+}
+
+static void _iwl_set_rxon_ht(struct iwl_priv *priv,
+                            struct iwl_ht_config *ht_conf,
+                            struct iwl_rxon_context *ctx)
+{
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+       if (!ctx->ht.enabled) {
+               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+                       RXON_FLG_HT40_PROT_MSK |
+                       RXON_FLG_HT_PROT_MSK);
+               return;
+       }
+
+       /* FIXME: if the definition of ht.protection changed, the "translation"
+        * will be needed for rxon->flags
+        */
+       rxon->flags |= cpu_to_le32(ctx->ht.protection <<
+                                  RXON_FLG_HT_OPERATING_MODE_POS);
+
+       /* Set up channel bandwidth:
+        * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
+       /* clear the HT channel mode before set the mode */
+       rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
+                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+       if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
+               /* pure ht40 */
+               if (ctx->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 (ctx->ht.extension_chan_offset) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               rxon->flags &=
+                                       ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               rxon->flags |=
+                                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               break;
+                       }
+               } else {
+                       /*
+                        * Note: control channel is opposite of extension
+                        * channel
+                        */
+                       switch (ctx->ht.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;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+                               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+                       default:
+                               /*
+                                * channel location only valid if in Mixed
+                                * mode
+                                */
+                               IWL_ERR(priv,
+                                       "invalid extension channel offset\n");
+                               break;
+                       }
+               }
+       } else {
+               rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
+       }
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
+                       "extension channel offset 0x%x\n",
+                       le32_to_cpu(rxon->flags), ctx->ht.protection,
+                       ctx->ht.extension_chan_offset);
+}
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+{
+       struct iwl_rxon_context *ctx;
+
+       for_each_context(priv, ctx)
+               _iwl_set_rxon_ht(priv, ht_conf, ctx);
+}
+
+/**
+ * iwl_set_rxon_channel - Set the band and channel values in staging RXON
+ * @ch: requested channel as a pointer to struct ieee80211_channel
+
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the ch->band
+ */
+void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx)
+{
+       enum ieee80211_band band = ch->band;
+       u16 channel = ch->hw_value;
+
+       if ((le16_to_cpu(ctx->staging.channel) == channel) &&
+           (priv->band == band))
+               return;
+
+       ctx->staging.channel = cpu_to_le16(channel);
+       if (band == IEEE80211_BAND_5GHZ)
+               ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
+       else
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+
+       priv->band = band;
+
+       IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
+
+}
+
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           enum ieee80211_band band,
+                           struct ieee80211_vif *vif)
+{
+       if (band == IEEE80211_BAND_5GHZ) {
+               ctx->staging.flags &=
+                   ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+                     | RXON_FLG_CCK_MSK);
+               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+       } else {
+               /* Copied from iwl_post_associate() */
+               if (vif && vif->bss_conf.use_short_slot)
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+               else
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
+               ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
+       }
+}
+
+static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
+                                 struct iwl_rxon_context *ctx, int hw_decrypt)
+{
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+       if (hw_decrypt)
+               rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+       else
+               rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+}
+
+/* validate RXON structure is valid */
+static int iwl_check_rxon_cmd(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx)
+{
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
+       u32 errors = 0;
+
+       if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+               if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
+                       IWL_WARN(priv, "check 2.4G: wrong narrow\n");
+                       errors |= BIT(0);
+               }
+               if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
+                       IWL_WARN(priv, "check 2.4G: wrong radar\n");
+                       errors |= BIT(1);
+               }
+       } else {
+               if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
+                       IWL_WARN(priv, "check 5.2G: not short slot!\n");
+                       errors |= BIT(2);
+               }
+               if (rxon->flags & RXON_FLG_CCK_MSK) {
+                       IWL_WARN(priv, "check 5.2G: CCK!\n");
+                       errors |= BIT(3);
+               }
+       }
+       if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
+               IWL_WARN(priv, "mac/bssid mcast!\n");
+               errors |= BIT(4);
+       }
+
+       /* make sure basic rates 6Mbps and 1Mbps are supported */
+       if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
+           (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
+               IWL_WARN(priv, "neither 1 nor 6 are basic\n");
+               errors |= BIT(5);
+       }
+
+       if (le16_to_cpu(rxon->assoc_id) > 2007) {
+               IWL_WARN(priv, "aid > 2007\n");
+               errors |= BIT(6);
+       }
+
+       if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+                       == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
+               IWL_WARN(priv, "CCK and short slot\n");
+               errors |= BIT(7);
+       }
+
+       if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+                       == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
+               IWL_WARN(priv, "CCK and auto detect");
+               errors |= BIT(8);
+       }
+
+       if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+                           RXON_FLG_TGG_PROTECT_MSK)) ==
+                           RXON_FLG_TGG_PROTECT_MSK) {
+               IWL_WARN(priv, "TGg but no auto-detect\n");
+               errors |= BIT(9);
+       }
+
+       if (rxon->channel == 0) {
+               IWL_WARN(priv, "zero channel is invalid\n");
+               errors |= BIT(10);
+       }
+
+       WARN(errors, "Invalid RXON (%#x), channel %d",
+            errors, le16_to_cpu(rxon->channel));
+
+       return errors ? -EINVAL : 0;
+}
+
+/**
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
+ *
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv,
+                                 struct iwl_rxon_context *ctx)
+{
+       const struct iwl_rxon_cmd *staging = &ctx->staging;
+       const struct iwl_rxon_cmd *active = &ctx->active;
+
+#define CHK(cond)                                                      \
+       if ((cond)) {                                                   \
+               IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");   \
+               return 1;                                               \
+       }
+
+#define CHK_NEQ(c1, c2)                                                \
+       if ((c1) != (c2)) {                                     \
+               IWL_DEBUG_INFO(priv, "need full RXON - "        \
+                              #c1 " != " #c2 " - %d != %d\n",  \
+                              (c1), (c2));                     \
+               return 1;                                       \
+       }
+
+       /* These items are only settable from the full RXON command */
+       CHK(!iwl_is_associated_ctx(ctx));
+       CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
+       CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
+       CHK(!ether_addr_equal(staging->wlap_bssid_addr,
+                             active->wlap_bssid_addr));
+       CHK_NEQ(staging->dev_type, active->dev_type);
+       CHK_NEQ(staging->channel, active->channel);
+       CHK_NEQ(staging->air_propagation, active->air_propagation);
+       CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
+               active->ofdm_ht_single_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
+               active->ofdm_ht_dual_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
+               active->ofdm_ht_triple_stream_basic_rates);
+       CHK_NEQ(staging->assoc_id, active->assoc_id);
+
+       /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+        * be updated with the RXON_ASSOC command -- however only some
+        * flag transitions are allowed using RXON_ASSOC */
+
+       /* Check if we are not switching bands */
+       CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
+               active->flags & RXON_FLG_BAND_24G_MSK);
+
+       /* Check if we are switching association toggle */
+       CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
+               active->filter_flags & RXON_FILTER_ASSOC_MSK);
+
+#undef CHK
+#undef CHK_NEQ
+
+       return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            enum iwl_rxon_context_id ctxid)
+{
+       struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
+
+       IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+       IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n",
+                       le16_to_cpu(rxon->channel));
+       IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n",
+                       le32_to_cpu(rxon->flags));
+       IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
+                       le32_to_cpu(rxon->filter_flags));
+       IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
+       IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
+                       rxon->ofdm_basic_rates);
+       IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n",
+                       rxon->cck_basic_rates);
+       IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
+       IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
+       IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n",
+                       le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_calc_basic_rates(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx)
+{
+       int lowest_present_ofdm = 100;
+       int lowest_present_cck = 100;
+       u8 cck = 0;
+       u8 ofdm = 0;
+
+       if (ctx->vif) {
+               struct ieee80211_supported_band *sband;
+               unsigned long basic = ctx->vif->bss_conf.basic_rates;
+               int i;
+
+               sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
+
+               for_each_set_bit(i, &basic, BITS_PER_LONG) {
+                       int hw = sband->bitrates[i].hw_value;
+                       if (hw >= IWL_FIRST_OFDM_RATE) {
+                               ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
+                               if (lowest_present_ofdm > hw)
+                                       lowest_present_ofdm = hw;
+                       } else {
+                               BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
+
+                               cck |= BIT(hw);
+                               if (lowest_present_cck > hw)
+                                       lowest_present_cck = hw;
+                       }
+               }
+       }
+
+       /*
+        * Now we've got the basic rates as bitmaps in the ofdm and cck
+        * variables. This isn't sufficient though, as there might not
+        * be all the right rates in the bitmap. E.g. if the only basic
+        * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
+        * and 6 Mbps because the 802.11-2007 standard says in 9.6:
+        *
+        *    [...] a STA responding to a received frame shall transmit
+        *    its Control Response frame [...] at the highest rate in the
+        *    BSSBasicRateSet parameter that is less than or equal to the
+        *    rate of the immediately previous frame in the frame exchange
+        *    sequence ([...]) and that is of the same modulation class
+        *    ([...]) as the received frame. If no rate contained in the
+        *    BSSBasicRateSet parameter meets these conditions, then the
+        *    control frame sent in response to a received frame shall be
+        *    transmitted at the highest mandatory rate of the PHY that is
+        *    less than or equal to the rate of the received frame, and
+        *    that is of the same modulation class as the received frame.
+        *
+        * As a consequence, we need to add all mandatory rates that are
+        * lower than all of the basic rates to these bitmaps.
+        */
+
+       if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
+               ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE;
+       if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
+               ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE;
+       /* 6M already there or needed so always add */
+       ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
+
+       /*
+        * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
+        * Note, however:
+        *  - if no CCK rates are basic, it must be ERP since there must
+        *    be some basic rates at all, so they're OFDM => ERP PHY
+        *    (or we're in 5 GHz, and the cck bitmap will never be used)
+        *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
+        *  - if 5.5M is basic, 1M and 2M are mandatory
+        *  - if 2M is basic, 1M is mandatory
+        *  - if 1M is basic, that's the only valid ACK rate.
+        * As a consequence, it's not as complicated as it sounds, just add
+        * any lower rates to the ACK rate bitmap.
+        */
+       if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
+               ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
+       if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
+               ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
+       if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
+               ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
+       /* 1M already there or needed so always add */
+       cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
+
+       IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n",
+                      cck, ofdm);
+
+       /* "basic_rates" is a misnomer here -- should be called ACK rates */
+       ctx->staging.cck_basic_rates = cck;
+       ctx->staging.ofdm_basic_rates = ofdm;
+}
+
+/**
+ * iwlagn_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is committed to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ *
+ * The connect/disconnect flow should be as the following:
+ *
+ * 1. make sure send RXON command with association bit unset if not connect
+ *     this should include the channel and the band for the candidate
+ *     to be connected to
+ * 2. Add Station before RXON association with the AP
+ * 3. RXON_timing has to send before RXON for connection
+ * 4. full RXON command - associated bit set
+ * 5. use RXON_ASSOC command to update any flags changes
+ */
+int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       /* cast away the const for active_rxon in this function */
+       struct iwl_rxon_cmd *active = (void *)&ctx->active;
+       bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (!iwl_is_alive(priv))
+               return -EBUSY;
+
+       /* This function hardcodes a bunch of dual-mode assumptions */
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (!ctx->is_active)
+               return 0;
+
+       /* always get timestamp with Rx frame */
+       ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
+
+       /* recalculate basic rates */
+       iwl_calc_basic_rates(priv, ctx);
+
+       /*
+        * force CTS-to-self frames protection if RTS-CTS is not preferred
+        * one aggregation protection method
+        */
+       if (!priv->hw_params.use_rts_for_aggregation)
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
+       if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
+           !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
+               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
+       else
+               ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+       iwl_print_rx_config_cmd(priv, ctx->ctxid);
+       ret = iwl_check_rxon_cmd(priv, ctx);
+       if (ret) {
+               IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * receive commit_rxon request
+        * abort any previous channel switch if still in process
+        */
+       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
+           (priv->switch_channel != ctx->staging.channel)) {
+               IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
+                             le16_to_cpu(priv->switch_channel));
+               iwl_chswitch_done(priv, false);
+       }
+
+       /*
+        * If we don't need to send a full RXON, we can use
+        * iwl_rxon_assoc_cmd which is used to reconfigure filter
+        * and other flags for the current radio configuration.
+        */
+       if (!iwl_full_rxon_required(priv, ctx)) {
+               ret = iwlagn_send_rxon_assoc(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
+                       return ret;
+               }
+
+               memcpy(active, &ctx->staging, sizeof(*active));
+               /*
+                * We do not commit tx power settings while channel changing,
+                * do it now if after settings changed.
+                */
+               iwl_set_tx_power(priv, priv->tx_power_next, false);
+
+               /* make sure we are in the right PS state */
+               iwl_power_update_mode(priv, true);
+
+               return 0;
+       }
+
+       iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto);
+
+       IWL_DEBUG_INFO(priv,
+                      "Going to commit RXON\n"
+                      "  * with%s RXON_FILTER_ASSOC_MSK\n"
+                      "  * channel = %d\n"
+                      "  * bssid = %pM\n",
+                      (new_assoc ? "" : "out"),
+                      le16_to_cpu(ctx->staging.channel),
+                      ctx->staging.bssid_addr);
+
+       /*
+        * Always clear associated first, but with the correct config.
+        * This is required as for example station addition for the
+        * AP station must be done after the BSSID is set to correctly
+        * set up filters in the device.
+        */
+       ret = iwlagn_rxon_disconn(priv, ctx);
+       if (ret)
+               return ret;
+
+       ret = iwlagn_set_pan_params(priv);
+       if (ret)
+               return ret;
+
+       if (new_assoc)
+               return iwlagn_rxon_connect(priv, ctx);
+
+       return 0;
+}
+
+void iwlagn_config_ht40(struct ieee80211_conf *conf,
+       struct iwl_rxon_context *ctx)
+{
+       if (conf_is_ht40_minus(conf)) {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+               ctx->ht.is_40mhz = true;
+       } else if (conf_is_ht40_plus(conf)) {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               ctx->ht.is_40mhz = true;
+       } else {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               ctx->ht.is_40mhz = false;
+       }
+}
+
+int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = conf->channel;
+       int ret = 0;
+
+       IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
+
+       mutex_lock(&priv->mutex);
+
+       if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+               IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+               goto out;
+       }
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+               goto out;
+       }
+
+       if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+                      IEEE80211_CONF_CHANGE_CHANNEL)) {
+               /* mac80211 uses static for non-HT which is what we want */
+               priv->current_ht_config.smps = conf->smps_mode;
+
+               /*
+                * Recalculate chain counts.
+                *
+                * If monitor mode is enabled then mac80211 will
+                * set up the SM PS mode to OFF if an HT channel is
+                * configured.
+                */
+               for_each_context(priv, ctx)
+                       iwlagn_set_rxon_chain(priv, ctx);
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               for_each_context(priv, ctx) {
+                       /* Configure HT40 channels */
+                       if (ctx->ht.enabled != conf_is_ht(conf))
+                               ctx->ht.enabled = conf_is_ht(conf);
+
+                       if (ctx->ht.enabled) {
+                               /* if HT40 is used, it should not change
+                                * after associated except channel switch */
+                               if (!ctx->ht.is_40mhz ||
+                                               !iwl_is_associated_ctx(ctx))
+                                       iwlagn_config_ht40(conf, ctx);
+                       } else
+                               ctx->ht.is_40mhz = false;
+
+                       /*
+                        * Default to no protection. Protection mode will
+                        * later be set from BSS config in iwl_ht_conf
+                        */
+                       ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+                       /* if we are switching from ht to 2.4 clear flags
+                        * from any ht related info since 2.4 does not
+                        * support ht */
+                       if (le16_to_cpu(ctx->staging.channel) !=
+                           channel->hw_value)
+                               ctx->staging.flags = 0;
+
+                       iwl_set_rxon_channel(priv, channel, ctx);
+                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
+
+                       iwl_set_flags_for_band(priv, ctx, channel->band,
+                                              ctx->vif);
+               }
+
+               iwl_update_bcast_stations(priv);
+       }
+
+       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");
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_POWER) {
+               IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
+                       priv->tx_power_user_lmt, conf->power_level);
+
+               iwl_set_tx_power(priv, conf->power_level, false);
+       }
+
+       for_each_context(priv, ctx) {
+               if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+                       continue;
+               iwlagn_commit_rxon(priv, ctx);
+       }
+ out:
+       mutex_unlock(&priv->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_check_needed_chains(struct iwl_priv *priv,
+                                      struct iwl_rxon_context *ctx,
+                                      struct ieee80211_bss_conf *bss_conf)
+{
+       struct ieee80211_vif *vif = ctx->vif;
+       struct iwl_rxon_context *tmp;
+       struct ieee80211_sta *sta;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       struct ieee80211_sta_ht_cap *ht_cap;
+       bool need_multiple;
+
+       lockdep_assert_held(&priv->mutex);
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               rcu_read_lock();
+               sta = ieee80211_find_sta(vif, bss_conf->bssid);
+               if (!sta) {
+                       /*
+                        * 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.
+                        */
+                       need_multiple = false;
+                       rcu_read_unlock();
+                       break;
+               }
+
+               ht_cap = &sta->ht_cap;
+
+               need_multiple = true;
+
+               /*
+                * If the peer advertises no support for receiving 2 and 3
+                * stream MCS rates, it can't be transmitting them either.
+                */
+               if (ht_cap->mcs.rx_mask[1] == 0 &&
+                   ht_cap->mcs.rx_mask[2] == 0) {
+                       need_multiple = false;
+               } else if (!(ht_cap->mcs.tx_params &
+                                               IEEE80211_HT_MCS_TX_DEFINED)) {
+                       /* If it can't TX MCS at all ... */
+                       need_multiple = false;
+               } else if (ht_cap->mcs.tx_params &
+                                               IEEE80211_HT_MCS_TX_RX_DIFF) {
+                       int maxstreams;
+
+                       /*
+                        * But if it can receive them, it might still not
+                        * be able to transmit them, which is what we need
+                        * to check here -- so check the number of streams
+                        * it advertises for TX (if different from RX).
+                        */
+
+                       maxstreams = (ht_cap->mcs.tx_params &
+                                IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
+                       maxstreams >>=
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+                       maxstreams += 1;
+
+                       if (maxstreams <= 1)
+                               need_multiple = false;
+               }
+
+               rcu_read_unlock();
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               /* currently */
+               need_multiple = false;
+               break;
+       default:
+               /* only AP really */
+               need_multiple = true;
+               break;
+       }
+
+       ctx->ht_need_multiple_chains = need_multiple;
+
+       if (!need_multiple) {
+               /* check all contexts */
+               for_each_context(priv, tmp) {
+                       if (!tmp->vif)
+                               continue;
+                       if (tmp->ht_need_multiple_chains) {
+                               need_multiple = true;
+                               break;
+                       }
+               }
+       }
+
+       ht_conf->single_chain_sufficient = !need_multiple;
+}
+
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+       int ret;
+
+       if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
+               return;
+
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+           iwl_is_any_associated(priv)) {
+               struct iwl_calib_chain_noise_reset_cmd cmd;
+
+               /* clear data for chain noise calibration algorithm */
+               data->chain_noise_a = 0;
+               data->chain_noise_b = 0;
+               data->chain_noise_c = 0;
+               data->chain_signal_a = 0;
+               data->chain_signal_b = 0;
+               data->chain_signal_c = 0;
+               data->beacon_count = 0;
+
+               memset(&cmd, 0, sizeof(cmd));
+               iwl_set_calib_hdr(&cmd.hdr,
+                       priv->phy_calib_chain_noise_reset_cmd);
+               ret = iwl_dvm_send_cmd_pdu(priv,
+                                       REPLY_PHY_CALIBRATION_CMD,
+                                       CMD_SYNC, sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv,
+                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+       }
+}
+
+void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_bss_conf *bss_conf,
+                            u32 changes)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       int ret;
+       bool force = false;
+
+       mutex_lock(&priv->mutex);
+
+       if (unlikely(!iwl_is_ready(priv))) {
+               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
+               mutex_unlock(&priv->mutex);
+               return;
+        }
+
+       if (unlikely(!ctx->vif)) {
+               IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
+       if (changes & BSS_CHANGED_BEACON_INT)
+               force = true;
+
+       if (changes & BSS_CHANGED_QOS) {
+               ctx->qos_data.qos_active = bss_conf->qos;
+               iwlagn_update_qos(priv, ctx);
+       }
+
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       if (vif->bss_conf.use_short_preamble)
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+       else
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+       if (changes & BSS_CHANGED_ASSOC) {
+               if (bss_conf->assoc) {
+                       priv->timestamp = bss_conf->last_tsf;
+                       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               } else {
+                       /*
+                        * If we disassociate while there are pending
+                        * frames, just wake up the queues and let the
+                        * frames "escape" ... This shouldn't really
+                        * be happening to start with, but we should
+                        * not get stuck in this case either since it
+                        * can happen if userspace gets confused.
+                        */
+                       iwlagn_lift_passive_no_rx(priv);
+
+                       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+                       if (ctx->ctxid == IWL_RXON_CTX_BSS)
+                               priv->have_rekey_data = false;
+               }
+
+               iwlagn_bt_coex_rssi_monitor(priv);
+       }
+
+       if (ctx->ht.enabled) {
+               ctx->ht.protection = bss_conf->ht_operation_mode &
+                                       IEEE80211_HT_OP_MODE_PROTECTION;
+               ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
+                                       IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+               iwlagn_check_needed_chains(priv, ctx, bss_conf);
+               iwl_set_rxon_ht(priv, &priv->current_ht_config);
+       }
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
+               ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
+       else
+               ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+
+       if (bss_conf->use_cts_prot)
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+       else
+               ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+
+       memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
+
+       if (vif->type == NL80211_IFTYPE_AP ||
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               if (vif->bss_conf.enable_beacon) {
+                       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+                       priv->beacon_ctx = ctx;
+               } else {
+                       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+                       priv->beacon_ctx = NULL;
+               }
+       }
+
+       /*
+        * If the ucode decides to do beacon filtering before
+        * association, it will lose beacons that are needed
+        * before sending frames out on passive channels. This
+        * causes association failures on those channels. Enable
+        * receiving beacons in such cases.
+        */
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               if (!bss_conf->assoc)
+                       ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+               else
+                       ctx->staging.filter_flags &=
+                                                   ~RXON_FILTER_BCON_AWARE_MSK;
+       }
+
+       if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+               iwlagn_commit_rxon(priv, ctx);
+
+       if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
+               /*
+                * The chain noise calibration will enable PM upon
+                * completion. If calibration has already been run
+                * then we need to enable power management here.
+                */
+               if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+                       iwl_power_update_mode(priv, false);
+
+               /* Enable RX differential gain and sensitivity calibrations */
+               iwlagn_chain_noise_reset(priv);
+               priv->start_calib = 1;
+       }
+
+       if (changes & BSS_CHANGED_IBSS) {
+               ret = iwlagn_manage_ibss_station(priv, vif,
+                                                bss_conf->ibss_joined);
+               if (ret)
+                       IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+                               bss_conf->ibss_joined ? "add" : "remove",
+                               bss_conf->bssid);
+       }
+
+       if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
+           priv->beacon_ctx) {
+               if (iwlagn_update_beacon(priv, vif))
+                       IWL_ERR(priv, "Error sending IBSS beacon\n");
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+void iwlagn_post_scan(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+
+       /*
+        * We do not commit power settings while scan is pending,
+        * do it now if the settings changed.
+        */
+       iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
+       iwl_set_tx_power(priv, priv->tx_power_next, false);
+
+       /*
+        * Since setting the RXON may have been deferred while
+        * performing the scan, fire one off if needed
+        */
+       for_each_context(priv, ctx)
+               if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
+                       iwlagn_commit_rxon(priv, ctx);
+
+       iwlagn_set_pan_params(priv);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c
new file mode 100644 (file)
index 0000000..6633074
--- /dev/null
@@ -0,0 +1,1170 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
+#include "dev.h"
+#include "agn.h"
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+#define MAX_SCAN_CHANNEL           50
+
+/* For reset radio, need minimal dwell time only */
+#define IWL_RADIO_RESET_DWELL_TIME     5
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+       int ret;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_SCAN_ABORT_CMD,
+               .flags = CMD_SYNC | CMD_WANT_SKB,
+       };
+       __le32 *status;
+
+       /* Exit instantly with error when device is not ready
+        * to receive scan abort command or it does not perform
+        * hardware scan currently */
+       if (!test_bit(STATUS_READY, &priv->status) ||
+           !test_bit(STATUS_SCAN_HW, &priv->status) ||
+           test_bit(STATUS_FW_ERROR, &priv->status))
+               return -EIO;
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+       if (ret)
+               return ret;
+
+       status = (void *)cmd.resp_pkt->data;
+       if (*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_SCAN(priv, "SCAN_ABORT ret %d.\n",
+                              le32_to_cpu(*status));
+               ret = -EIO;
+       }
+
+       iwl_free_resp(&cmd);
+       return ret;
+}
+
+static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
+{
+       /* check if scan was requested from mac80211 */
+       if (priv->scan_request) {
+               IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
+               ieee80211_scan_completed(priv->hw, aborted);
+       }
+
+       if (priv->scan_type == IWL_SCAN_ROC)
+               iwl_scan_roc_expired(priv);
+
+       priv->scan_type = IWL_SCAN_NORMAL;
+       priv->scan_vif = NULL;
+       priv->scan_request = NULL;
+}
+
+static void iwl_process_scan_complete(struct iwl_priv *priv)
+{
+       bool aborted;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
+               return;
+
+       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
+
+       cancel_delayed_work(&priv->scan_check);
+
+       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+       if (aborted)
+               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
+
+       if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
+               goto out_settings;
+       }
+
+       if (priv->scan_type == IWL_SCAN_ROC)
+               iwl_scan_roc_expired(priv);
+
+       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
+               int err;
+
+               /* Check if mac80211 requested scan during our internal scan */
+               if (priv->scan_request == NULL)
+                       goto out_complete;
+
+               /* If so request a new scan */
+               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
+                                       priv->scan_request->channels[0]->band);
+               if (err) {
+                       IWL_DEBUG_SCAN(priv,
+                               "failed to initiate pending scan: %d\n", err);
+                       aborted = true;
+                       goto out_complete;
+               }
+
+               return;
+       }
+
+out_complete:
+       iwl_complete_scan(priv, aborted);
+
+out_settings:
+       /* Can we still talk to firmware ? */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       iwlagn_post_scan(priv);
+}
+
+void iwl_force_scan_end(struct iwl_priv *priv)
+{
+       lockdep_assert_held(&priv->mutex);
+
+       if (!test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
+               return;
+       }
+
+       IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
+       clear_bit(STATUS_SCANNING, &priv->status);
+       clear_bit(STATUS_SCAN_HW, &priv->status);
+       clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+       clear_bit(STATUS_SCAN_COMPLETE, &priv->status);
+       iwl_complete_scan(priv, true);
+}
+
+static void iwl_do_scan_abort(struct iwl_priv *priv)
+{
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (!test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
+               return;
+       }
+
+       if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
+               return;
+       }
+
+       ret = iwl_send_scan_abort(priv);
+       if (ret) {
+               IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
+               iwl_force_scan_end(priv);
+       } else
+               IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n");
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ */
+int iwl_scan_cancel(struct iwl_priv *priv)
+{
+       IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
+       queue_work(priv->workqueue, &priv->abort_scan);
+       return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ */
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(ms);
+
+       lockdep_assert_held(&priv->mutex);
+
+       IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
+
+       iwl_do_scan_abort(priv);
+
+       while (time_before_eq(jiffies, timeout)) {
+               if (!test_bit(STATUS_SCAN_HW, &priv->status))
+                       goto finished;
+               msleep(20);
+       }
+
+       return;
+
+ finished:
+       /*
+        * Now STATUS_SCAN_HW is clear. This means that the
+        * device finished, but the background work is going
+        * to execute at best as soon as we release the mutex.
+        * Since we need to be able to issue a new scan right
+        * after this function returns, run the complete here.
+        * The STATUS_SCAN_COMPLETE bit will then be cleared
+        * and prevent the background work from "completing"
+        * a possible new scan.
+        */
+       iwl_process_scan_complete(priv);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static int iwl_rx_reply_scan(struct iwl_priv *priv,
+                             struct iwl_rx_cmd_buffer *rxb,
+                             struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_scanreq_notification *notif = (void *)pkt->data;
+
+       IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
+#endif
+       return 0;
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
+                                   struct iwl_rx_cmd_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_scanstart_notification *notif = (void *)pkt->data;
+
+       priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+       IWL_DEBUG_SCAN(priv, "Scan start: "
+                      "%d [802.11%s] "
+                      "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+                      notif->channel,
+                      notif->band ? "bg" : "a",
+                      le32_to_cpu(notif->tsf_high),
+                      le32_to_cpu(notif->tsf_low),
+                      notif->status, notif->beacon_timer);
+
+       if (priv->scan_type == IWL_SCAN_ROC &&
+           !priv->hw_roc_start_notified) {
+               ieee80211_ready_on_channel(priv->hw);
+               priv->hw_roc_start_notified = true;
+       }
+
+       return 0;
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
+                                     struct iwl_rx_cmd_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_scanresults_notification *notif = (void *)pkt->data;
+
+       IWL_DEBUG_SCAN(priv, "Scan ch.res: "
+                      "%d [802.11%s] "
+                      "probe status: %u:%u "
+                      "(TSF: 0x%08X:%08X) - %d "
+                      "elapsed=%lu usec\n",
+                      notif->channel,
+                      notif->band ? "bg" : "a",
+                      notif->probe_status, notif->num_probe_not_sent,
+                      le32_to_cpu(notif->tsf_high),
+                      le32_to_cpu(notif->tsf_low),
+                      le32_to_cpu(notif->statistics[0]),
+                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
+#endif
+       return 0;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+                                      struct iwl_rx_cmd_buffer *rxb,
+                                      struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data;
+
+       IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+                      scan_notif->scanned_channels,
+                      scan_notif->tsf_low,
+                      scan_notif->tsf_high, scan_notif->status);
+
+       IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
+                      (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
+                      jiffies_to_msecs(jiffies - priv->scan_start));
+
+       /*
+        * When aborting, we run the scan completed background work inline
+        * and the background work must then do nothing. The SCAN_COMPLETE
+        * bit helps implement that logic and thus needs to be set before
+        * queueing the work. Also, since the scan abort waits for SCAN_HW
+        * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
+        * to avoid a race there.
+        */
+       set_bit(STATUS_SCAN_COMPLETE, &priv->status);
+       clear_bit(STATUS_SCAN_HW, &priv->status);
+       queue_work(priv->workqueue, &priv->scan_completed);
+
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
+           iwl_advanced_bt_coexist(priv) &&
+           priv->bt_status != scan_notif->bt_status) {
+               if (scan_notif->bt_status) {
+                       /* BT on */
+                       if (!priv->bt_ch_announce)
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                       /*
+                        * otherwise, no traffic load information provided
+                        * no changes made
+                        */
+               } else {
+                       /* BT off */
+                       priv->bt_traffic_load =
+                               IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+               }
+               priv->bt_status = scan_notif->bt_status;
+               queue_work(priv->workqueue,
+                          &priv->bt_traffic_change_work);
+       }
+       return 0;
+}
+
+void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
+{
+       /* scan handlers */
+       priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+       priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+       priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+                                       iwl_rx_scan_results_notif;
+       priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+                                       iwl_rx_scan_complete_notif;
+}
+
+static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
+                                    enum ieee80211_band band, u8 n_probes)
+{
+       if (band == IEEE80211_BAND_5GHZ)
+               return IWL_ACTIVE_DWELL_TIME_52 +
+                       IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
+       else
+               return IWL_ACTIVE_DWELL_TIME_24 +
+                       IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
+}
+
+static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
+{
+       struct iwl_rxon_context *ctx;
+
+       /*
+        * If we're associated, we clamp the dwell time 98%
+        * of the smallest beacon interval (minus 2 * channel
+        * tune time)
+        */
+       for_each_context(priv, ctx) {
+               u16 value;
+
+               switch (ctx->staging.dev_type) {
+               case RXON_DEV_TYPE_P2P:
+                       /* no timing constraints */
+                       continue;
+               case RXON_DEV_TYPE_ESS:
+               default:
+                       /* timing constraints if associated */
+                       if (!iwl_is_associated_ctx(ctx))
+                               continue;
+                       break;
+               case RXON_DEV_TYPE_CP:
+               case RXON_DEV_TYPE_2STA:
+                       /*
+                        * These seem to always have timers for TBTT
+                        * active in uCode even when not associated yet.
+                        */
+                       break;
+               }
+
+               value = ctx->beacon_int;
+               if (!value)
+                       value = IWL_PASSIVE_DWELL_BASE;
+               value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+               dwell_time = min(value, dwell_time);
+       }
+
+       return dwell_time;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
+                                     enum ieee80211_band band)
+{
+       u16 passive = (band == IEEE80211_BAND_2GHZ) ?
+           IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+           IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+       return iwl_limit_dwell(priv, passive);
+}
+
+/* Return valid, unused, channel for a passive scan to reset the RF */
+static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+                                       enum ieee80211_band band)
+{
+       struct ieee80211_supported_band *sband = priv->hw->wiphy->bands[band];
+       struct iwl_rxon_context *ctx;
+       int i;
+
+       for (i = 0; i < sband->n_channels; i++) {
+               bool busy = false;
+
+               for_each_context(priv, ctx) {
+                       busy = sband->channels[i].hw_value ==
+                               le16_to_cpu(ctx->staging.channel);
+                       if (busy)
+                               break;
+               }
+
+               if (busy)
+                       continue;
+
+               if (!(sband->channels[i].flags & IEEE80211_CHAN_DISABLED))
+                       return sband->channels[i].hw_value;
+       }
+
+       return 0;
+}
+
+static int iwl_get_channel_for_reset_scan(struct iwl_priv *priv,
+                                         struct ieee80211_vif *vif,
+                                         enum ieee80211_band band,
+                                         struct iwl_scan_channel *scan_ch)
+{
+       const struct ieee80211_supported_band *sband;
+       u16 channel;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband) {
+               IWL_ERR(priv, "invalid band\n");
+               return 0;
+       }
+
+       channel = iwl_get_single_channel_number(priv, band);
+       if (channel) {
+               scan_ch->channel = cpu_to_le16(channel);
+               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               scan_ch->active_dwell =
+                       cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+               scan_ch->passive_dwell =
+                       cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+               return 1;
+       }
+
+       IWL_ERR(priv, "no valid channel found\n");
+       return 0;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv,
+                                    struct ieee80211_vif *vif,
+                                    enum ieee80211_band band,
+                                    u8 is_active, u8 n_probes,
+                                    struct iwl_scan_channel *scan_ch)
+{
+       struct ieee80211_channel *chan;
+       const struct ieee80211_supported_band *sband;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int added, i;
+       u16 channel;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband)
+               return 0;
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+               chan = priv->scan_request->channels[i];
+
+               if (chan->band != band)
+                       continue;
+
+               channel = chan->hw_value;
+               scan_ch->channel = cpu_to_le16(channel);
+
+               if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               else
+                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+
+               if (n_probes)
+                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+
+               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                * power level:
+                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                */
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
+                              channel, le32_to_cpu(scan_ch->type),
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                               "ACTIVE" : "PASSIVE",
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                              active_dwell : passive_dwell);
+
+               scan_ch++;
+               added++;
+       }
+
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
+       return added;
+}
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+
+static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
+                             const u8 *ies, int ie_len, const u8 *ssid,
+                             u8 ssid_len, int left)
+{
+       int len = 0;
+       u8 *pos = NULL;
+
+       /* Make sure there is enough space for the probe request,
+        * two mandatory IEs and the data */
+       left -= 24;
+       if (left < 0)
+               return 0;
+
+       frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+       memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
+       memcpy(frame->sa, ta, ETH_ALEN);
+       memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
+       frame->seq_ctrl = 0;
+
+       len += 24;
+
+       /* ...next IE... */
+       pos = &frame->u.probe_req.variable[0];
+
+       /* fill in our SSID IE */
+       left -= ssid_len + 2;
+       if (left < 0)
+               return 0;
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = ssid_len;
+       if (ssid && ssid_len) {
+               memcpy(pos, ssid, ssid_len);
+               pos += ssid_len;
+       }
+
+       len += ssid_len + 2;
+
+       if (WARN_ON(left < ie_len))
+               return len;
+
+       if (ies && ie_len) {
+               memcpy(pos, ies, ie_len);
+               len += ie_len;
+       }
+
+       return (u16)len;
+}
+
+static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_SCAN_CMD,
+               .len = { sizeof(struct iwl_scan_cmd), },
+               .flags = CMD_SYNC,
+       };
+       struct iwl_scan_cmd *scan;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u32 rate_flags = 0;
+       u16 cmd_len = 0;
+       u16 rx_chain = 0;
+       enum ieee80211_band band;
+       u8 n_probes = 0;
+       u8 rx_ant = priv->eeprom_data->valid_rx_ant;
+       u8 rate;
+       bool is_active = false;
+       int  chan_mod;
+       u8 active_chains;
+       u8 scan_tx_antennas = priv->eeprom_data->valid_tx_ant;
+       int ret;
+       int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
+                           MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
+                           priv->fw->ucode_capa.max_probe_length;
+       const u8 *ssid = NULL;
+       u8 ssid_len = 0;
+
+       if (WARN_ON_ONCE(priv->scan_request &&
+                        priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
+               return -EINVAL;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (vif)
+               ctx = iwl_rxon_ctx_from_vif(vif);
+
+       if (!priv->scan_cmd) {
+               priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
+               if (!priv->scan_cmd) {
+                       IWL_DEBUG_SCAN(priv,
+                                      "fail to allocate memory for scan\n");
+                       return -ENOMEM;
+               }
+       }
+       scan = priv->scan_cmd;
+       memset(scan, 0, scan_cmd_size);
+
+       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+       if (priv->scan_type != IWL_SCAN_ROC &&
+           iwl_is_any_associated(priv)) {
+               u16 interval = 0;
+               u32 extra;
+               u32 suspend_time = 100;
+               u32 scan_suspend_time = 100;
+
+               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
+               switch (priv->scan_type) {
+               case IWL_SCAN_ROC:
+                       WARN_ON(1);
+                       break;
+               case IWL_SCAN_RADIO_RESET:
+                       interval = 0;
+                       break;
+               case IWL_SCAN_NORMAL:
+                       interval = vif->bss_conf.beacon_int;
+                       break;
+               }
+
+               scan->suspend_time = 0;
+               scan->max_out_time = cpu_to_le32(200 * 1024);
+               if (!interval)
+                       interval = suspend_time;
+
+               extra = (suspend_time / interval) << 22;
+               scan_suspend_time = (extra |
+                   ((suspend_time % interval) * 1024));
+               scan->suspend_time = cpu_to_le32(scan_suspend_time);
+               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
+                              scan_suspend_time, interval);
+       } else if (priv->scan_type == IWL_SCAN_ROC) {
+               scan->suspend_time = 0;
+               scan->max_out_time = 0;
+               scan->quiet_time = 0;
+               scan->quiet_plcp_th = 0;
+       }
+
+       switch (priv->scan_type) {
+       case IWL_SCAN_RADIO_RESET:
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+               /*
+                * Override quiet time as firmware checks that active
+                * dwell is >= quiet; since we use passive scan it'll
+                * not actually be used.
+                */
+               scan->quiet_time = cpu_to_le16(IWL_RADIO_RESET_DWELL_TIME);
+               break;
+       case IWL_SCAN_NORMAL:
+               if (priv->scan_request->n_ssids) {
+                       int i, p = 0;
+                       IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+                       /*
+                        * The highest priority SSID is inserted to the
+                        * probe request template.
+                        */
+                       ssid_len = priv->scan_request->ssids[0].ssid_len;
+                       ssid = priv->scan_request->ssids[0].ssid;
+
+                       /*
+                        * Invert the order of ssids, the firmware will invert
+                        * it back.
+                        */
+                       for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
+                               scan->direct_scan[p].id = WLAN_EID_SSID;
+                               scan->direct_scan[p].len =
+                                       priv->scan_request->ssids[i].ssid_len;
+                               memcpy(scan->direct_scan[p].ssid,
+                                      priv->scan_request->ssids[i].ssid,
+                                      priv->scan_request->ssids[i].ssid_len);
+                               n_probes++;
+                               p++;
+                       }
+                       is_active = true;
+               } else
+                       IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
+               break;
+       case IWL_SCAN_ROC:
+               IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
+               break;
+       }
+
+       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
+       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+       switch (priv->scan_band) {
+       case IEEE80211_BAND_2GHZ:
+               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+               chan_mod = le32_to_cpu(
+                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_CHANNEL_MODE_MSK)
+                                      >> RXON_FLG_CHANNEL_MODE_POS;
+               if ((priv->scan_request && priv->scan_request->no_cck) ||
+                   chan_mod == CHANNEL_MODE_PURE_40) {
+                       rate = IWL_RATE_6M_PLCP;
+               } else {
+                       rate = IWL_RATE_1M_PLCP;
+                       rate_flags = RATE_MCS_CCK_MSK;
+               }
+               /*
+                * Internal scans are passive, so we can indiscriminately set
+                * the BT ignore flag on 2.4 GHz since it applies to TX only.
+                */
+               if (priv->cfg->bt_params &&
+                   priv->cfg->bt_params->advanced_bt_coexist)
+                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               rate = IWL_RATE_6M_PLCP;
+               break;
+       default:
+               IWL_WARN(priv, "Invalid scan band\n");
+               return -EIO;
+       }
+
+       /*
+        * If active scanning is requested but a certain channel is
+        * marked passive, we can do active scanning if we detect
+        * transmissions.
+        *
+        * There is an issue with some firmware versions that triggers
+        * a sysassert on a "good CRC threshold" of zero (== disabled),
+        * on a radar channel even though this means that we should NOT
+        * send probes.
+        *
+        * The "good CRC threshold" is the number of frames that we
+        * need to receive during our dwell time on a channel before
+        * sending out probes -- setting this to a huge value will
+        * mean we never reach it, but at the same time work around
+        * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+        * here instead of IWL_GOOD_CRC_TH_DISABLED.
+        *
+        * This was fixed in later versions along with some other
+        * scan changes, and the threshold behaves as a flag in those
+        * versions.
+        */
+       if (priv->new_scan_threshold_behaviour)
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_DISABLED;
+       else
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_NEVER;
+
+       band = priv->scan_band;
+
+       if (band == IEEE80211_BAND_2GHZ &&
+           priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               /* transmit 2.4 GHz probes only on first antenna */
+               scan_tx_antennas = first_antenna(scan_tx_antennas);
+       }
+
+       priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv,
+                                                   priv->scan_tx_ant[band],
+                                                   scan_tx_antennas);
+       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
+       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+       /*
+        * In power save mode while associated use one chain,
+        * otherwise use all chains
+        */
+       if (test_bit(STATUS_POWER_PMI, &priv->status) &&
+           !(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
+               /* rx_ant has been set to all valid chains previously */
+               active_chains = rx_ant &
+                               ((u8)(priv->chain_noise_data.active_chains));
+               if (!active_chains)
+                       active_chains = rx_ant;
+
+               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
+                               priv->chain_noise_data.active_chains);
+
+               rx_ant = first_antenna(active_chains);
+       }
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               rx_ant = first_antenna(rx_ant);
+       }
+
+       /* MIMO is not used here, but value is required */
+       rx_chain |=
+               priv->eeprom_data->valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+       scan->rx_chain = cpu_to_le16(rx_chain);
+       switch (priv->scan_type) {
+       case IWL_SCAN_NORMAL:
+               cmd_len = iwl_fill_probe_req(
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       vif->addr,
+                                       priv->scan_request->ie,
+                                       priv->scan_request->ie_len,
+                                       ssid, ssid_len,
+                                       scan_cmd_size - sizeof(*scan));
+               break;
+       case IWL_SCAN_RADIO_RESET:
+       case IWL_SCAN_ROC:
+               /* use bcast addr, will not be transmitted but must be valid */
+               cmd_len = iwl_fill_probe_req(
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       iwl_bcast_addr, NULL, 0,
+                                       NULL, 0,
+                                       scan_cmd_size - sizeof(*scan));
+               break;
+       default:
+               BUG();
+       }
+       scan->tx_cmd.len = cpu_to_le16(cmd_len);
+
+       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+                              RXON_FILTER_BCON_AWARE_MSK);
+
+       switch (priv->scan_type) {
+       case IWL_SCAN_RADIO_RESET:
+               scan->channel_count =
+                       iwl_get_channel_for_reset_scan(priv, vif, band,
+                               (void *)&scan->data[cmd_len]);
+               break;
+       case IWL_SCAN_NORMAL:
+               scan->channel_count =
+                       iwl_get_channels_for_scan(priv, vif, band,
+                               is_active, n_probes,
+                               (void *)&scan->data[cmd_len]);
+               break;
+       case IWL_SCAN_ROC: {
+               struct iwl_scan_channel *scan_ch;
+               int n_chan, i;
+               u16 dwell;
+
+               dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
+               n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
+
+               scan->channel_count = n_chan;
+
+               scan_ch = (void *)&scan->data[cmd_len];
+
+               for (i = 0; i < n_chan; i++) {
+                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+                       scan_ch->channel =
+                               cpu_to_le16(priv->hw_roc_channel->hw_value);
+
+                       if (i == n_chan - 1)
+                               dwell = priv->hw_roc_duration - i * dwell;
+
+                       scan_ch->active_dwell =
+                       scan_ch->passive_dwell = cpu_to_le16(dwell);
+
+                       /* Set txpower levels to defaults */
+                       scan_ch->dsp_atten = 110;
+
+                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                        * power level:
+                        * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                        */
+                       if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
+                               scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+                       else
+                               scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+                       scan_ch++;
+               }
+               }
+
+               break;
+       }
+
+       if (scan->channel_count == 0) {
+               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
+               return -EIO;
+       }
+
+       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
+           scan->channel_count * sizeof(struct iwl_scan_channel);
+       cmd.data[0] = scan;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       scan->len = cpu_to_le16(cmd.len[0]);
+
+       /* set scan bit here for PAN params */
+       set_bit(STATUS_SCAN_HW, &priv->status);
+
+       ret = iwlagn_set_pan_params(priv);
+       if (ret) {
+               clear_bit(STATUS_SCAN_HW, &priv->status);
+               return ret;
+       }
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+       if (ret) {
+               clear_bit(STATUS_SCAN_HW, &priv->status);
+               iwlagn_set_pan_params(priv);
+       }
+
+       return ret;
+}
+
+void iwl_init_scan_params(struct iwl_priv *priv)
+{
+       u8 ant_idx = fls(priv->eeprom_data->valid_tx_ant) - 1;
+       if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
+               priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
+       if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
+               priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
+}
+
+int __must_check iwl_scan_initiate(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  enum iwl_scan_type scan_type,
+                                  enum ieee80211_band band)
+{
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       cancel_delayed_work(&priv->scan_check);
+
+       if (!iwl_is_ready_rf(priv)) {
+               IWL_WARN(priv, "Request scan called when driver not ready.\n");
+               return -EIO;
+       }
+
+       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+               IWL_DEBUG_SCAN(priv,
+                       "Multiple concurrent scan requests in parallel.\n");
+               return -EBUSY;
+       }
+
+       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
+               return -EBUSY;
+       }
+
+       IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
+                       scan_type == IWL_SCAN_NORMAL ? "" :
+                       scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
+                       "internal short ");
+
+       set_bit(STATUS_SCANNING, &priv->status);
+       priv->scan_type = scan_type;
+       priv->scan_start = jiffies;
+       priv->scan_band = band;
+
+       ret = iwlagn_request_scan(priv, vif);
+       if (ret) {
+               clear_bit(STATUS_SCANNING, &priv->status);
+               priv->scan_type = IWL_SCAN_NORMAL;
+               return ret;
+       }
+
+       queue_delayed_work(priv->workqueue, &priv->scan_check,
+                          IWL_SCAN_CHECK_WATCHDOG);
+
+       return 0;
+}
+
+
+/*
+ * internal short scan, this function should only been called while associated.
+ * It will reset and tune the radio to prevent possible RF related problem
+ */
+void iwl_internal_short_hw_scan(struct iwl_priv *priv)
+{
+       queue_work(priv->workqueue, &priv->start_internal_scan);
+}
+
+static void iwl_bg_start_internal_scan(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, start_internal_scan);
+
+       IWL_DEBUG_SCAN(priv, "Start internal scan\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
+               IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
+               goto unlock;
+       }
+
+       if (test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+               goto unlock;
+       }
+
+       if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
+               IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
+ unlock:
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+       struct iwl_priv *priv =
+           container_of(data, struct iwl_priv, scan_check.work);
+
+       IWL_DEBUG_SCAN(priv, "Scan check work\n");
+
+       /* Since we are here firmware does not finish scan and
+        * most likely is in bad shape, so we don't bother to
+        * send abort command, just force scan complete to mac80211 */
+       mutex_lock(&priv->mutex);
+       iwl_force_scan_end(priv);
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
+
+       IWL_DEBUG_SCAN(priv, "Abort scan work\n");
+
+       /* We keep scan_check work queued in case when firmware will not
+        * report back scan completed notification */
+       mutex_lock(&priv->mutex);
+       iwl_scan_cancel_timeout(priv, 200);
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, scan_completed);
+
+       mutex_lock(&priv->mutex);
+       iwl_process_scan_complete(priv);
+       mutex_unlock(&priv->mutex);
+}
+
+void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
+{
+       INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+       INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
+       INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+}
+
+void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
+{
+       cancel_work_sync(&priv->start_internal_scan);
+       cancel_work_sync(&priv->abort_scan);
+       cancel_work_sync(&priv->scan_completed);
+
+       if (cancel_delayed_work_sync(&priv->scan_check)) {
+               mutex_lock(&priv->mutex);
+               iwl_force_scan_end(priv);
+               mutex_unlock(&priv->mutex);
+       }
+}
+
+void iwl_scan_roc_expired(struct iwl_priv *priv)
+{
+       /*
+        * The status bit should be set here, to prevent a race
+        * where the atomic_read returns 1, but before the execution continues
+        * iwl_scan_offchannel_skb_status() checks if the status bit is set
+        */
+       set_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
+
+       if (atomic_read(&priv->num_aux_in_flight) == 0) {
+               ieee80211_remain_on_channel_expired(priv->hw);
+               priv->hw_roc_channel = NULL;
+               schedule_delayed_work(&priv->hw_roc_disable_work,
+                                     10 * HZ);
+
+               clear_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status);
+       } else {
+               IWL_DEBUG_SCAN(priv, "ROC done with %d frames in aux\n",
+                              atomic_read(&priv->num_aux_in_flight));
+       }
+}
+
+void iwl_scan_offchannel_skb(struct iwl_priv *priv)
+{
+       WARN_ON(!priv->hw_roc_start_notified);
+       atomic_inc(&priv->num_aux_in_flight);
+}
+
+void iwl_scan_offchannel_skb_status(struct iwl_priv *priv)
+{
+       if (atomic_dec_return(&priv->num_aux_in_flight) == 0 &&
+           test_bit(STATUS_SCAN_ROC_EXPIRED, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "0 aux frames. Calling ROC expired\n");
+               iwl_scan_roc_expired(priv);
+       }
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
new file mode 100644 (file)
index 0000000..b29b798
--- /dev/null
@@ -0,0 +1,1485 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-trans.h"
+#include "dev.h"
+#include "agn.h"
+
+const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
+{
+       lockdep_assert_held(&priv->sta_lock);
+
+       if (sta_id >= IWLAGN_STATION_COUNT) {
+               IWL_ERR(priv, "invalid sta_id %u", sta_id);
+               return -EINVAL;
+       }
+       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
+               IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u "
+                       "addr %pM\n",
+                       sta_id, priv->stations[sta_id].sta.sta.addr);
+
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
+               IWL_DEBUG_ASSOC(priv,
+                               "STA id %u addr %pM already present in uCode "
+                               "(according to driver)\n",
+                               sta_id, priv->stations[sta_id].sta.sta.addr);
+       } else {
+               priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
+               IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
+                               sta_id, priv->stations[sta_id].sta.sta.addr);
+       }
+       return 0;
+}
+
+static int iwl_process_add_sta_resp(struct iwl_priv *priv,
+                                   struct iwl_addsta_cmd *addsta,
+                                   struct iwl_rx_packet *pkt)
+{
+       struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data;
+       u8 sta_id = addsta->sta.sta_id;
+       int ret = -EIO;
+
+       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
+                       pkt->hdr.flags);
+               return ret;
+       }
+
+       IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
+                      sta_id);
+
+       spin_lock(&priv->sta_lock);
+
+       switch (add_sta_resp->status) {
+       case ADD_STA_SUCCESS_MSK:
+               IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
+               ret = iwl_sta_ucode_activate(priv, sta_id);
+               break;
+       case ADD_STA_NO_ROOM_IN_TABLE:
+               IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
+                       sta_id);
+               break;
+       case ADD_STA_NO_BLOCK_ACK_RESOURCE:
+               IWL_ERR(priv, "Adding station %d failed, no block ack "
+                       "resource.\n", sta_id);
+               break;
+       case ADD_STA_MODIFY_NON_EXIST_STA:
+               IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
+                       sta_id);
+               break;
+       default:
+               IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
+                               add_sta_resp->status);
+               break;
+       }
+
+       IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
+                      priv->stations[sta_id].sta.mode ==
+                      STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added",
+                      sta_id, priv->stations[sta_id].sta.sta.addr);
+
+       /*
+        * XXX: The MAC address in the command buffer is often changed from
+        * the original sent to the device. That is, the MAC address
+        * written to the command buffer often is not the same MAC address
+        * read from the command buffer when the command returns. This
+        * issue has not yet been resolved and this debugging is left to
+        * observe the problem.
+        */
+       IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
+                      priv->stations[sta_id].sta.mode ==
+                      STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+                      addsta->sta.addr);
+       spin_unlock(&priv->sta_lock);
+
+       return ret;
+}
+
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_addsta_cmd *addsta =
+               (struct iwl_addsta_cmd *) cmd->payload;
+
+       return iwl_process_add_sta_resp(priv, addsta, pkt);
+}
+
+int iwl_send_add_sta(struct iwl_priv *priv,
+                    struct iwl_addsta_cmd *sta, u8 flags)
+{
+       int ret = 0;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_ADD_STA,
+               .flags = flags,
+               .data = { sta, },
+               .len = { sizeof(*sta), },
+       };
+       u8 sta_id __maybe_unused = sta->sta.sta_id;
+
+       IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
+                      sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
+
+       if (!(flags & CMD_ASYNC)) {
+               cmd.flags |= CMD_WANT_SKB;
+               might_sleep();
+       }
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+
+       if (ret || (flags & CMD_ASYNC))
+               return ret;
+       /*else the command was successfully sent in SYNC mode, need to free
+        * the reply page */
+
+       iwl_free_resp(&cmd);
+
+       if (cmd.handler_status)
+               IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
+                       cmd.handler_status);
+
+       return cmd.handler_status;
+}
+
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap)
+{
+       if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
+               return false;
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (priv->disable_ht40)
+               return false;
+#endif
+
+       /*
+        * Remainder of this function checks ht_cap, but if it's
+        * NULL then we can do HT40 (special case for RXON)
+        */
+       if (!ht_cap)
+               return true;
+
+       if (!ht_cap->ht_supported)
+               return false;
+
+       if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+               return false;
+
+       return true;
+}
+
+static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
+                                 struct ieee80211_sta *sta,
+                                 struct iwl_rxon_context *ctx,
+                                 __le32 *flags, __le32 *mask)
+{
+       struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
+       u8 mimo_ps_mode;
+
+       *mask = STA_FLG_RTS_MIMO_PROT_MSK |
+               STA_FLG_MIMO_DIS_MSK |
+               STA_FLG_HT40_EN_MSK |
+               STA_FLG_MAX_AGG_SIZE_MSK |
+               STA_FLG_AGG_MPDU_DENSITY_MSK;
+       *flags = 0;
+
+       if (!sta || !sta_ht_inf->ht_supported)
+               return;
+
+       mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
+
+       IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
+                       sta->addr,
+                       (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
+                       "static" :
+                       (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
+                       "dynamic" : "disabled");
+
+       switch (mimo_ps_mode) {
+       case WLAN_HT_CAP_SM_PS_STATIC:
+               *flags |= STA_FLG_MIMO_DIS_MSK;
+               break;
+       case WLAN_HT_CAP_SM_PS_DYNAMIC:
+               *flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+               break;
+       case WLAN_HT_CAP_SM_PS_DISABLED:
+               break;
+       default:
+               IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
+               break;
+       }
+
+       *flags |= cpu_to_le32(
+               (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+       *flags |= cpu_to_le32(
+               (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
+               *flags |= STA_FLG_HT40_EN_MSK;
+}
+
+int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                     struct ieee80211_sta *sta)
+{
+       u8 sta_id = iwl_sta_id(sta);
+       __le32 flags, mask;
+       struct iwl_addsta_cmd cmd;
+
+       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
+
+       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].sta.station_flags &= ~mask;
+       priv->stations[sta_id].sta.station_flags |= flags;
+       spin_unlock_bh(&priv->sta_lock);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.mode = STA_CONTROL_MODIFY_MSK;
+       cmd.station_flags_msk = mask;
+       cmd.station_flags = flags;
+       cmd.sta.sta_id = sta_id;
+
+       return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
+}
+
+static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+                                  struct ieee80211_sta *sta,
+                                  struct iwl_rxon_context *ctx)
+{
+       __le32 flags, mask;
+
+       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
+
+       lockdep_assert_held(&priv->sta_lock);
+       priv->stations[index].sta.station_flags &= ~mask;
+       priv->stations[index].sta.station_flags |= flags;
+}
+
+/**
+ * iwl_prep_station - Prepare station information for addition
+ *
+ * should be called with sta_lock held
+ */
+u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                   const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
+{
+       struct iwl_station_entry *station;
+       int i;
+       u8 sta_id = IWL_INVALID_STATION;
+
+       if (is_ap)
+               sta_id = ctx->ap_sta_id;
+       else if (is_broadcast_ether_addr(addr))
+               sta_id = ctx->bcast_sta_id;
+       else
+               for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) {
+                       if (ether_addr_equal(priv->stations[i].sta.sta.addr,
+                                            addr)) {
+                               sta_id = i;
+                               break;
+                       }
+
+                       if (!priv->stations[i].used &&
+                           sta_id == IWL_INVALID_STATION)
+                               sta_id = i;
+               }
+
+       /*
+        * These two conditions have the same outcome, but keep them
+        * separate
+        */
+       if (unlikely(sta_id == IWL_INVALID_STATION))
+               return sta_id;
+
+       /*
+        * uCode is not able to deal with multiple requests to add a
+        * station. Keep track if one is in progress so that we do not send
+        * another.
+        */
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+               IWL_DEBUG_INFO(priv, "STA %d already in process of being "
+                              "added.\n", sta_id);
+               return sta_id;
+       }
+
+       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
+           ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) {
+               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
+                               "adding again.\n", sta_id, addr);
+               return sta_id;
+       }
+
+       station = &priv->stations[sta_id];
+       station->used = IWL_STA_DRIVER_ACTIVE;
+       IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
+                       sta_id, addr);
+       priv->num_stations++;
+
+       /* Set up the REPLY_ADD_STA command to send to device */
+       memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+       memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+       station->sta.mode = 0;
+       station->sta.sta.sta_id = sta_id;
+       station->sta.station_flags = ctx->station_flags;
+       station->ctxid = ctx->ctxid;
+
+       if (sta) {
+               struct iwl_station_priv *sta_priv;
+
+               sta_priv = (void *)sta->drv_priv;
+               sta_priv->ctx = ctx;
+       }
+
+       /*
+        * OK to call unconditionally, since local stations (IBSS BSSID
+        * STA and broadcast STA) pass in a NULL sta, and mac80211
+        * doesn't allow HT IBSS.
+        */
+       iwl_set_ht_add_station(priv, sta_id, sta, ctx);
+
+       return sta_id;
+
+}
+
+#define STA_WAIT_TIMEOUT (HZ/2)
+
+/**
+ * iwl_add_station_common -
+ */
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r)
+{
+       int ret = 0;
+       u8 sta_id;
+       struct iwl_addsta_cmd sta_cmd;
+
+       *sta_id_r = 0;
+       spin_lock_bh(&priv->sta_lock);
+       sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
+                       addr);
+               spin_unlock_bh(&priv->sta_lock);
+               return -EINVAL;
+       }
+
+       /*
+        * uCode is not able to deal with multiple requests to add a
+        * station. Keep track if one is in progress so that we do not send
+        * another.
+        */
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+               IWL_DEBUG_INFO(priv, "STA %d already in process of being "
+                              "added.\n", sta_id);
+               spin_unlock_bh(&priv->sta_lock);
+               return -EEXIST;
+       }
+
+       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
+                               "adding again.\n", sta_id, addr);
+               spin_unlock_bh(&priv->sta_lock);
+               return -EEXIST;
+       }
+
+       priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta,
+              sizeof(struct iwl_addsta_cmd));
+       spin_unlock_bh(&priv->sta_lock);
+
+       /* Add station to device's station table */
+       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+       if (ret) {
+               spin_lock_bh(&priv->sta_lock);
+               IWL_ERR(priv, "Adding station %pM failed.\n",
+                       priv->stations[sta_id].sta.sta.addr);
+               priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+               priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_bh(&priv->sta_lock);
+       }
+       *sta_id_r = sta_id;
+       return ret;
+}
+
+/**
+ * iwl_sta_ucode_deactivate - deactivate ucode status for a station
+ */
+static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
+{
+       lockdep_assert_held(&priv->sta_lock);
+
+       /* Ucode must be active and driver must be non active */
+       if ((priv->stations[sta_id].used &
+            (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
+             IWL_STA_UCODE_ACTIVE)
+               IWL_ERR(priv, "removed non active STA %u\n", sta_id);
+
+       priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+
+       memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
+       IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
+}
+
+static int iwl_send_remove_station(struct iwl_priv *priv,
+                                  const u8 *addr, int sta_id,
+                                  bool temporary)
+{
+       struct iwl_rx_packet *pkt;
+       int ret;
+       struct iwl_rem_sta_cmd rm_sta_cmd;
+
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_REMOVE_STA,
+               .len = { sizeof(struct iwl_rem_sta_cmd), },
+               .flags = CMD_SYNC,
+               .data = { &rm_sta_cmd, },
+       };
+
+       memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
+       rm_sta_cmd.num_sta = 1;
+       memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
+
+       cmd.flags |= CMD_WANT_SKB;
+
+       ret = iwl_dvm_send_cmd(priv, &cmd);
+
+       if (ret)
+               return ret;
+
+       pkt = cmd.resp_pkt;
+       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+                         pkt->hdr.flags);
+               ret = -EIO;
+       }
+
+       if (!ret) {
+               struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data;
+               switch (rem_sta_resp->status) {
+               case REM_STA_SUCCESS_MSK:
+                       if (!temporary) {
+                               spin_lock_bh(&priv->sta_lock);
+                               iwl_sta_ucode_deactivate(priv, sta_id);
+                               spin_unlock_bh(&priv->sta_lock);
+                       }
+                       IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
+                       break;
+               default:
+                       ret = -EIO;
+                       IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
+                       break;
+               }
+       }
+       iwl_free_resp(&cmd);
+
+       return ret;
+}
+
+/**
+ * iwl_remove_station - Remove driver's knowledge of station.
+ */
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr)
+{
+       u8 tid;
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv,
+                       "Unable to remove station %pM, device not ready.\n",
+                       addr);
+               /*
+                * It is typical for stations to be removed when we are
+                * going down. Return success since device will be down
+                * soon anyway
+                */
+               return 0;
+       }
+
+       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
+                       sta_id, addr);
+
+       if (WARN_ON(sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
+
+       spin_lock_bh(&priv->sta_lock);
+
+       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+               IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
+                               addr);
+               goto out_err;
+       }
+
+       if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+               IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
+                               addr);
+               goto out_err;
+       }
+
+       if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
+               kfree(priv->stations[sta_id].lq);
+               priv->stations[sta_id].lq = NULL;
+       }
+
+       for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+               memset(&priv->tid_data[sta_id][tid], 0,
+                       sizeof(priv->tid_data[sta_id][tid]));
+
+       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+       priv->num_stations--;
+
+       if (WARN_ON(priv->num_stations < 0))
+               priv->num_stations = 0;
+
+       spin_unlock_bh(&priv->sta_lock);
+
+       return iwl_send_remove_station(priv, addr, sta_id, false);
+out_err:
+       spin_unlock_bh(&priv->sta_lock);
+       return -EINVAL;
+}
+
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+                           const u8 *addr)
+{
+       u8 tid;
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv,
+                       "Unable to remove station %pM, device not ready.\n",
+                       addr);
+               return;
+       }
+
+       IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
+
+       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+               return;
+
+       spin_lock_bh(&priv->sta_lock);
+
+       WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
+
+       for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+               memset(&priv->tid_data[sta_id][tid], 0,
+                       sizeof(priv->tid_data[sta_id][tid]));
+
+       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+       priv->num_stations--;
+
+       if (WARN_ON_ONCE(priv->num_stations < 0))
+               priv->num_stations = 0;
+
+       spin_unlock_bh(&priv->sta_lock);
+}
+
+static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
+{
+       int i, r;
+       u32 rate_flags = 0;
+       __le32 rate_n_flags;
+
+       lockdep_assert_held(&priv->mutex);
+
+       memset(link_cmd, 0, sizeof(*link_cmd));
+
+       /* Set up the rate scaling to start at selected rate, fall back
+        * all the way down to 1M in IEEE order, and then spin on 1M */
+       if (priv->band == IEEE80211_BAND_5GHZ)
+               r = IWL_RATE_6M_INDEX;
+       else if (ctx && ctx->vif && ctx->vif->p2p)
+               r = IWL_RATE_6M_INDEX;
+       else
+               r = IWL_RATE_1M_INDEX;
+
+       if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+       rate_flags |= first_antenna(priv->eeprom_data->valid_tx_ant) <<
+                               RATE_MCS_ANT_POS;
+       rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+               link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
+
+       link_cmd->general_params.single_stream_ant_msk =
+                       first_antenna(priv->eeprom_data->valid_tx_ant);
+
+       link_cmd->general_params.dual_stream_ant_msk =
+               priv->eeprom_data->valid_tx_ant &
+               ~first_antenna(priv->eeprom_data->valid_tx_ant);
+       if (!link_cmd->general_params.dual_stream_ant_msk) {
+               link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
+       } else if (num_of_ant(priv->eeprom_data->valid_tx_ant) == 2) {
+               link_cmd->general_params.dual_stream_ant_msk =
+                       priv->eeprom_data->valid_tx_ant;
+       }
+
+       link_cmd->agg_params.agg_dis_start_th =
+               LINK_QUAL_AGG_DISABLE_START_DEF;
+       link_cmd->agg_params.agg_time_limit =
+               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+
+       link_cmd->sta_id = sta_id;
+}
+
+/**
+ * iwl_clear_ucode_stations - clear ucode station table bits
+ *
+ * This function clears all the bits in the driver indicating
+ * which stations are active in the ucode. Call when something
+ * other than explicit station management would cause this in
+ * the ucode, e.g. unassociated RXON.
+ */
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx)
+{
+       int i;
+       bool cleared = false;
+
+       IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
+
+       spin_lock_bh(&priv->sta_lock);
+       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+               if (ctx && ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
+
+               if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
+                       IWL_DEBUG_INFO(priv,
+                               "Clearing ucode active for station %d\n", i);
+                       priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+                       cleared = true;
+               }
+       }
+       spin_unlock_bh(&priv->sta_lock);
+
+       if (!cleared)
+               IWL_DEBUG_INFO(priv,
+                              "No active stations found to be cleared\n");
+}
+
+/**
+ * iwl_restore_stations() - Restore driver known stations to device
+ *
+ * All stations considered active by driver, but not present in ucode, is
+ * restored.
+ *
+ * Function sleeps.
+ */
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       struct iwl_addsta_cmd sta_cmd;
+       struct iwl_link_quality_cmd lq;
+       int i;
+       bool found = false;
+       int ret;
+       bool send_lq;
+
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv,
+                              "Not ready yet, not restoring any stations.\n");
+               return;
+       }
+
+       IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
+       spin_lock_bh(&priv->sta_lock);
+       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+               if (ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
+               if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
+                           !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
+                       IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
+                                       priv->stations[i].sta.sta.addr);
+                       priv->stations[i].sta.mode = 0;
+                       priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
+                       found = true;
+               }
+       }
+
+       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+               if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+                       memcpy(&sta_cmd, &priv->stations[i].sta,
+                              sizeof(struct iwl_addsta_cmd));
+                       send_lq = false;
+                       if (priv->stations[i].lq) {
+                               if (priv->wowlan)
+                                       iwl_sta_fill_lq(priv, ctx, i, &lq);
+                               else
+                                       memcpy(&lq, priv->stations[i].lq,
+                                              sizeof(struct iwl_link_quality_cmd));
+                               send_lq = true;
+                       }
+                       spin_unlock_bh(&priv->sta_lock);
+                       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+                       if (ret) {
+                               spin_lock_bh(&priv->sta_lock);
+                               IWL_ERR(priv, "Adding station %pM failed.\n",
+                                       priv->stations[i].sta.sta.addr);
+                               priv->stations[i].used &=
+                                               ~IWL_STA_DRIVER_ACTIVE;
+                               priv->stations[i].used &=
+                                               ~IWL_STA_UCODE_INPROGRESS;
+                               continue;
+                       }
+                       /*
+                        * Rate scaling has already been initialized, send
+                        * current LQ command
+                        */
+                       if (send_lq)
+                               iwl_send_lq_cmd(priv, ctx, &lq,
+                                               CMD_SYNC, true);
+                       spin_lock_bh(&priv->sta_lock);
+                       priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
+               }
+       }
+
+       spin_unlock_bh(&priv->sta_lock);
+       if (!found)
+               IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+                       "no stations to be restored.\n");
+       else
+               IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
+                       "complete.\n");
+}
+
+int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < priv->sta_key_max_num; i++)
+               if (!test_and_set_bit(i, &priv->ucode_key_table))
+                       return i;
+
+       return WEP_INVALID_OFFSET;
+}
+
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
+{
+       int i;
+
+       spin_lock_bh(&priv->sta_lock);
+       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
+               if (!(priv->stations[i].used & IWL_STA_BCAST))
+                       continue;
+
+               priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+               priv->num_stations--;
+               if (WARN_ON(priv->num_stations < 0))
+                       priv->num_stations = 0;
+               kfree(priv->stations[i].lq);
+               priv->stations[i].lq = NULL;
+       }
+       spin_unlock_bh(&priv->sta_lock);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_dump_lq_cmd(struct iwl_priv *priv,
+                          struct iwl_link_quality_cmd *lq)
+{
+       int i;
+       IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
+       IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
+                      lq->general_params.single_stream_ant_msk,
+                      lq->general_params.dual_stream_ant_msk);
+
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+               IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
+                              i, lq->rs_table[i].rate_n_flags);
+}
+#else
+static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
+                                  struct iwl_link_quality_cmd *lq)
+{
+}
+#endif
+
+/**
+ * is_lq_table_valid() - Test one aspect of LQ cmd for validity
+ *
+ * It sometimes happens when a HT rate has been in use and we
+ * loose connectivity with AP then mac80211 will first tell us that the
+ * current channel is not HT anymore before removing the station. In such a
+ * scenario the RXON flags will be updated to indicate we are not
+ * communicating HT anymore, but the LQ command may still contain HT rates.
+ * Test for this to prevent driver from sending LQ command between the time
+ * RXON flags are updated and when LQ command is updated.
+ */
+static bool is_lq_table_valid(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_link_quality_cmd *lq)
+{
+       int i;
+
+       if (ctx->ht.enabled)
+               return true;
+
+       IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
+                      ctx->active.channel);
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+               if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
+                   RATE_MCS_HT_MSK) {
+                       IWL_DEBUG_INFO(priv,
+                                      "index %d of LQ expects HT channel\n",
+                                      i);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
+ * iwl_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ *        after station has been added.
+ *
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
+ */
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                   struct iwl_link_quality_cmd *lq, u8 flags, bool init)
+{
+       int ret = 0;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_TX_LINK_QUALITY_CMD,
+               .len = { sizeof(struct iwl_link_quality_cmd), },
+               .flags = flags,
+               .data = { lq, },
+       };
+
+       if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
+
+
+       spin_lock_bh(&priv->sta_lock);
+       if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+               spin_unlock_bh(&priv->sta_lock);
+               return -EINVAL;
+       }
+       spin_unlock_bh(&priv->sta_lock);
+
+       iwl_dump_lq_cmd(priv, lq);
+       if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+               return -EINVAL;
+
+       if (is_lq_table_valid(priv, ctx, lq))
+               ret = iwl_dvm_send_cmd(priv, &cmd);
+       else
+               ret = -EINVAL;
+
+       if (cmd.flags & CMD_ASYNC)
+               return ret;
+
+       if (init) {
+               IWL_DEBUG_INFO(priv, "init LQ command complete, "
+                              "clearing sta addition status for sta %d\n",
+                              lq->sta_id);
+               spin_lock_bh(&priv->sta_lock);
+               priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_bh(&priv->sta_lock);
+       }
+       return ret;
+}
+
+
+static struct iwl_link_quality_cmd *
+iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                u8 sta_id)
+{
+       struct iwl_link_quality_cmd *link_cmd;
+
+       link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
+       if (!link_cmd) {
+               IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
+               return NULL;
+       }
+
+       iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd);
+
+       return link_cmd;
+}
+
+/*
+ * iwlagn_add_bssid_station - Add the special IBSS BSSID station
+ *
+ * Function sleeps.
+ */
+int iwlagn_add_bssid_station(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx,
+                            const u8 *addr, u8 *sta_id_r)
+{
+       int ret;
+       u8 sta_id;
+       struct iwl_link_quality_cmd *link_cmd;
+
+       if (sta_id_r)
+               *sta_id_r = IWL_INVALID_STATION;
+
+       ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM\n", addr);
+               return ret;
+       }
+
+       if (sta_id_r)
+               *sta_id_r = sta_id;
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].used |= IWL_STA_LOCAL;
+       spin_unlock_bh(&priv->sta_lock);
+
+       /* Set up default rate scaling table in device's station table */
+       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+       if (!link_cmd) {
+               IWL_ERR(priv,
+                       "Unable to initialize rate scaling for station %pM.\n",
+                       addr);
+               return -ENOMEM;
+       }
+
+       ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
+       if (ret)
+               IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].lq = link_cmd;
+       spin_unlock_bh(&priv->sta_lock);
+
+       return 0;
+}
+
+/*
+ * static WEP keys
+ *
+ * For each context, the device has a table of 4 static WEP keys
+ * (one for each key index) that is updated with the following
+ * commands.
+ */
+
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx,
+                                     bool send_if_empty)
+{
+       int i, not_empty = 0;
+       u8 buff[sizeof(struct iwl_wep_cmd) +
+               sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
+       struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
+       size_t cmd_size  = sizeof(struct iwl_wep_cmd);
+       struct iwl_host_cmd cmd = {
+               .id = ctx->wep_key_cmd,
+               .data = { wep_cmd, },
+               .flags = CMD_SYNC,
+       };
+
+       might_sleep();
+
+       memset(wep_cmd, 0, cmd_size +
+                       (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
+
+       for (i = 0; i < WEP_KEYS_MAX ; i++) {
+               wep_cmd->key[i].key_index = i;
+               if (ctx->wep_keys[i].key_size) {
+                       wep_cmd->key[i].key_offset = i;
+                       not_empty = 1;
+               } else {
+                       wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
+               }
+
+               wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
+               memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
+                               ctx->wep_keys[i].key_size);
+       }
+
+       wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
+       wep_cmd->num_keys = WEP_KEYS_MAX;
+
+       cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
+
+       cmd.len[0] = cmd_size;
+
+       if (not_empty || send_if_empty)
+               return iwl_dvm_send_cmd(priv, &cmd);
+       else
+               return 0;
+}
+
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx)
+{
+       lockdep_assert_held(&priv->mutex);
+
+       return iwl_send_static_wepkey_cmd(priv, ctx, false);
+}
+
+int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
+                              struct ieee80211_key_conf *keyconf)
+{
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+                     keyconf->keyidx);
+
+       memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_WEP(priv,
+                       "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+               /* but keys in device are clear anyway so return success */
+               return 0;
+       }
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
+       IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
+                     keyconf->keyidx, ret);
+
+       return ret;
+}
+
+int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_key_conf *keyconf)
+{
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       if (keyconf->keylen != WEP_KEY_LEN_128 &&
+           keyconf->keylen != WEP_KEY_LEN_64) {
+               IWL_DEBUG_WEP(priv,
+                             "Bad WEP key length %d\n", keyconf->keylen);
+               return -EINVAL;
+       }
+
+       keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT;
+
+       ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+       memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
+                                                       keyconf->keylen);
+
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
+       IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
+               keyconf->keylen, keyconf->keyidx, ret);
+
+       return ret;
+}
+
+/*
+ * dynamic (per-station) keys
+ *
+ * The dynamic keys are a little more complicated. The device has
+ * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys.
+ * These are linked to stations by a table that contains an index
+ * into the key table for each station/key index/{mcast,unicast},
+ * i.e. it's basically an array of pointers like this:
+ *     key_offset_t key_mapping[NUM_STATIONS][4][2];
+ * (it really works differently, but you can think of it as such)
+ *
+ * The key uploading and linking happens in the same command, the
+ * add station command with STA_MODIFY_KEY_MASK.
+ */
+
+static u8 iwlagn_key_sta_id(struct iwl_priv *priv,
+                           struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       if (sta)
+               return iwl_sta_id(sta);
+
+       /*
+        * The device expects GTKs for station interfaces to be
+        * installed as GTKs for the AP station. If we have no
+        * station ID, then use the ap_sta_id in that case.
+        */
+       if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx)
+               return vif_priv->ctx->ap_sta_id;
+
+       return IWL_INVALID_STATION;
+}
+
+static int iwlagn_send_sta_key(struct iwl_priv *priv,
+                              struct ieee80211_key_conf *keyconf,
+                              u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
+                              u32 cmd_flags)
+{
+       __le16 key_flags;
+       struct iwl_addsta_cmd sta_cmd;
+       int i;
+
+       spin_lock_bh(&priv->sta_lock);
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+       spin_unlock_bh(&priv->sta_lock);
+
+       key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+       key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
+
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
+               key_flags |= STA_KEY_FLG_CCMP;
+               memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               key_flags |= STA_KEY_FLG_TKIP;
+               sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
+               for (i = 0; i < 5; i++)
+                       sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
+               memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_WEP40:
+               key_flags |= STA_KEY_FLG_WEP;
+               memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen);
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+               key_flags |= STA_KEY_MULTICAST_MSK;
+
+       /* key pointer (offset) */
+       sta_cmd.key.key_offset = keyconf->hw_key_idx;
+
+       sta_cmd.key.key_flags = key_flags;
+       sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
+       sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
+
+       return iwl_send_add_sta(priv, &sta_cmd, cmd_flags);
+}
+
+void iwl_update_tkip_key(struct iwl_priv *priv,
+                        struct ieee80211_vif *vif,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
+{
+       u8 sta_id = iwlagn_key_sta_id(priv, vif, sta);
+
+       if (sta_id == IWL_INVALID_STATION)
+               return;
+
+       if (iwl_scan_cancel(priv)) {
+               /* cancel scan failed, just live w/ bad key and rely
+                  briefly on SW decryption */
+               return;
+       }
+
+       iwlagn_send_sta_key(priv, keyconf, sta_id,
+                           iv32, phase1key, CMD_ASYNC);
+}
+
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx,
+                          struct ieee80211_key_conf *keyconf,
+                          struct ieee80211_sta *sta)
+{
+       struct iwl_addsta_cmd sta_cmd;
+       u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
+       __le16 key_flags;
+
+       /* if station isn't there, neither is the key */
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENOENT;
+
+       spin_lock_bh(&priv->sta_lock);
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+       if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE))
+               sta_id = IWL_INVALID_STATION;
+       spin_unlock_bh(&priv->sta_lock);
+
+       if (sta_id == IWL_INVALID_STATION)
+               return 0;
+
+       lockdep_assert_held(&priv->mutex);
+
+       ctx->key_mapping_keys--;
+
+       IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
+                     keyconf->keyidx, sta_id);
+
+       if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table))
+               IWL_ERR(priv, "offset %d not used in uCode key table.\n",
+                       keyconf->hw_key_idx);
+
+       key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+       key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC |
+                    STA_KEY_FLG_INVALID;
+
+       if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+               key_flags |= STA_KEY_MULTICAST_MSK;
+
+       sta_cmd.key.key_flags = key_flags;
+       sta_cmd.key.key_offset = keyconf->hw_key_idx;
+       sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
+       sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_set_dynamic_key(struct iwl_priv *priv,
+                       struct iwl_rxon_context *ctx,
+                       struct ieee80211_key_conf *keyconf,
+                       struct ieee80211_sta *sta)
+{
+       struct ieee80211_key_seq seq;
+       u16 p1k[5];
+       int ret;
+       u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
+       const u8 *addr;
+
+       if (sta_id == IWL_INVALID_STATION)
+               return -EINVAL;
+
+       lockdep_assert_held(&priv->mutex);
+
+       keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
+       if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
+               return -ENOSPC;
+
+       ctx->key_mapping_keys++;
+
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (sta)
+                       addr = sta->addr;
+               else /* station mode case only */
+                       addr = ctx->active.bssid_addr;
+
+               /* pre-fill phase 1 key into device cache */
+               ieee80211_get_key_rx_seq(keyconf, 0, &seq);
+               ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
+               ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
+                                         seq.tkip.iv32, p1k, CMD_SYNC);
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
+                                         0, NULL, CMD_SYNC);
+               break;
+       default:
+               IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher);
+               ret = -EINVAL;
+       }
+
+       if (ret) {
+               ctx->key_mapping_keys--;
+               clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table);
+       }
+
+       IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
+                     keyconf->cipher, keyconf->keylen, keyconf->keyidx,
+                     sta ? sta->addr : NULL, ret);
+
+       return ret;
+}
+
+/**
+ * iwlagn_alloc_bcast_station - add broadcast station into driver's station table.
+ *
+ * This adds the broadcast station into the driver's station table
+ * and marks it driver active, so that it will be restored to the
+ * device at the next best time.
+ */
+int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       struct iwl_link_quality_cmd *link_cmd;
+       u8 sta_id;
+
+       spin_lock_bh(&priv->sta_lock);
+       sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Unable to prepare broadcast station\n");
+               spin_unlock_bh(&priv->sta_lock);
+
+               return -EINVAL;
+       }
+
+       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+       priv->stations[sta_id].used |= IWL_STA_BCAST;
+       spin_unlock_bh(&priv->sta_lock);
+
+       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+       if (!link_cmd) {
+               IWL_ERR(priv,
+                       "Unable to initialize rate scaling for bcast station.\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].lq = link_cmd;
+       spin_unlock_bh(&priv->sta_lock);
+
+       return 0;
+}
+
+/**
+ * iwl_update_bcast_station - update broadcast station's LQ command
+ *
+ * Only used by iwlagn. Placed here to have all bcast station management
+ * code together.
+ */
+int iwl_update_bcast_station(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx)
+{
+       struct iwl_link_quality_cmd *link_cmd;
+       u8 sta_id = ctx->bcast_sta_id;
+
+       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
+       if (!link_cmd) {
+               IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_bh(&priv->sta_lock);
+       if (priv->stations[sta_id].lq)
+               kfree(priv->stations[sta_id].lq);
+       else
+               IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
+       priv->stations[sta_id].lq = link_cmd;
+       spin_unlock_bh(&priv->sta_lock);
+
+       return 0;
+}
+
+int iwl_update_bcast_stations(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret = 0;
+
+       for_each_context(priv, ctx) {
+               ret = iwl_update_bcast_station(priv, ctx);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/**
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
+ */
+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
+{
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /* Remove "disable" flag, to enable Tx for this TID */
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+       priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+       spin_unlock_bh(&priv->sta_lock);
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn)
+{
+       int sta_id;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
+
+       sta_id = iwl_sta_id(sta);
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENXIO;
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].sta.station_flags_msk = 0;
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+       priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+       priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+       spin_unlock_bh(&priv->sta_lock);
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid)
+{
+       int sta_id;
+       struct iwl_addsta_cmd sta_cmd;
+
+       lockdep_assert_held(&priv->mutex);
+
+       sta_id = iwl_sta_id(sta);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+               return -ENXIO;
+       }
+
+       spin_lock_bh(&priv->sta_lock);
+       priv->stations[sta_id].sta.station_flags_msk = 0;
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+       priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
+       spin_unlock_bh(&priv->sta_lock);
+
+       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+}
+
+
+
+void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
+{
+       struct iwl_addsta_cmd cmd = {
+               .mode = STA_CONTROL_MODIFY_MSK,
+               .station_flags = STA_FLG_PWR_SAVE_MSK,
+               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
+               .sta.sta_id = sta_id,
+               .sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK,
+               .sleep_tx_count = cpu_to_le16(cnt),
+       };
+
+       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c
new file mode 100644 (file)
index 0000000..57b918c
--- /dev/null
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <net/net_namespace.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+#include "iwl-debug.h"
+#include "iwl-trans.h"
+#include "dev.h"
+#include "agn.h"
+#include "iwl-test.h"
+#include "iwl-testmode.h"
+
+static int iwl_testmode_send_cmd(struct iwl_op_mode *op_mode,
+                                struct iwl_host_cmd *cmd)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       return iwl_dvm_send_cmd(priv, cmd);
+}
+
+static bool iwl_testmode_valid_hw_addr(u32 addr)
+{
+       if (iwlagn_hw_valid_rtc_data_addr(addr))
+               return true;
+
+       if (IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
+           addr < IWLAGN_RTC_INST_UPPER_BOUND)
+               return true;
+
+       return false;
+}
+
+static u32 iwl_testmode_get_fw_ver(struct iwl_op_mode *op_mode)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       return priv->fw->ucode_ver;
+}
+
+static struct sk_buff*
+iwl_testmode_alloc_reply(struct iwl_op_mode *op_mode, int len)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       return cfg80211_testmode_alloc_reply_skb(priv->hw->wiphy, len);
+}
+
+static int iwl_testmode_reply(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+       return cfg80211_testmode_reply(skb);
+}
+
+static struct sk_buff *iwl_testmode_alloc_event(struct iwl_op_mode *op_mode,
+                                               int len)
+{
+       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
+       return cfg80211_testmode_alloc_event_skb(priv->hw->wiphy, len,
+                                                GFP_ATOMIC);
+}
+
+static void iwl_testmode_event(struct iwl_op_mode *op_mode, struct sk_buff *skb)
+{
+       return cfg80211_testmode_event(skb, GFP_ATOMIC);
+}
+
+static struct iwl_test_ops tst_ops = {
+       .send_cmd = iwl_testmode_send_cmd,
+       .valid_hw_addr = iwl_testmode_valid_hw_addr,
+       .get_fw_ver = iwl_testmode_get_fw_ver,
+       .alloc_reply = iwl_testmode_alloc_reply,
+       .reply = iwl_testmode_reply,
+       .alloc_event = iwl_testmode_alloc_event,
+       .event = iwl_testmode_event,
+};
+
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+       iwl_test_init(&priv->tst, priv->trans, &tst_ops);
+}
+
+void iwl_testmode_free(struct iwl_priv *priv)
+{
+       iwl_test_free(&priv->tst);
+}
+
+static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
+{
+       struct iwl_notification_wait calib_wait;
+       static const u8 calib_complete[] = {
+               CALIBRATION_COMPLETE_NOTIFICATION
+       };
+       int ret;
+
+       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
+                                  calib_complete, ARRAY_SIZE(calib_complete),
+                                  NULL, NULL);
+       ret = iwl_init_alive_start(priv);
+       if (ret) {
+               IWL_ERR(priv, "Fail init calibration: %d\n", ret);
+               goto cfg_init_calib_error;
+       }
+
+       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
+       if (ret)
+               IWL_ERR(priv, "Error detecting"
+                       " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
+       return ret;
+
+cfg_init_calib_error:
+       iwl_remove_notification(&priv->notif_wait, &calib_wait);
+       return ret;
+}
+
+/*
+ * This function handles the user application commands for driver.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
+ * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
+ * IWL_TM_CMD_DEV2APP_SYNC_RSP.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       struct iwl_trans *trans = priv->trans;
+       struct sk_buff *skb;
+       unsigned char *rsp_data_ptr = NULL;
+       int status = 0, rsp_data_len = 0;
+       u32 inst_size = 0, data_size = 0;
+       const struct fw_img *img;
+
+       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+       case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+               rsp_data_ptr = (unsigned char *)priv->cfg->name;
+               rsp_data_len = strlen(priv->cfg->name);
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                                                       rsp_data_len + 20);
+               if (!skb) {
+                       IWL_ERR(priv, "Memory allocation fail\n");
+                       return -ENOMEM;
+               }
+               if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+                               IWL_TM_CMD_DEV2APP_SYNC_RSP) ||
+                   nla_put(skb, IWL_TM_ATTR_SYNC_RSP,
+                           rsp_data_len, rsp_data_ptr))
+                       goto nla_put_failure;
+               status = cfg80211_testmode_reply(skb);
+               if (status < 0)
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
+               if (status)
+                       IWL_ERR(priv, "Error loading init ucode: %d\n", status);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+               iwl_testmode_cfg_init_calib(priv);
+               priv->ucode_loaded = false;
+               iwl_trans_stop_device(trans);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+               if (status) {
+                       IWL_ERR(priv,
+                               "Error loading runtime ucode: %d\n", status);
+                       break;
+               }
+               status = iwl_alive_start(priv);
+               if (status)
+                       IWL_ERR(priv,
+                               "Error starting the device: %d\n", status);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
+               iwl_scan_cancel_timeout(priv, 200);
+               priv->ucode_loaded = false;
+               iwl_trans_stop_device(trans);
+               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+               if (status) {
+                       IWL_ERR(priv,
+                               "Error loading WOWLAN ucode: %d\n", status);
+                       break;
+               }
+               status = iwl_alive_start(priv);
+               if (status)
+                       IWL_ERR(priv,
+                               "Error starting the device: %d\n", status);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+               if (priv->eeprom_blob) {
+                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                               priv->eeprom_blob_size + 20);
+                       if (!skb) {
+                               IWL_ERR(priv, "Memory allocation fail\n");
+                               return -ENOMEM;
+                       }
+                       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+                                       IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
+                           nla_put(skb, IWL_TM_ATTR_EEPROM,
+                                   priv->eeprom_blob_size,
+                                   priv->eeprom_blob))
+                               goto nla_put_failure;
+                       status = cfg80211_testmode_reply(skb);
+                       if (status < 0)
+                               IWL_ERR(priv, "Error sending msg : %d\n",
+                                       status);
+               } else
+                       return -ENODATA;
+               break;
+
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+               if (!tb[IWL_TM_ATTR_FIXRATE]) {
+                       IWL_ERR(priv, "Missing fixrate setting\n");
+                       return -ENOMSG;
+               }
+               priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
+               if (!skb) {
+                       IWL_ERR(priv, "Memory allocation fail\n");
+                       return -ENOMEM;
+               }
+               if (!priv->ucode_loaded) {
+                       IWL_ERR(priv, "No uCode has not been loaded\n");
+                       return -EINVAL;
+               } else {
+                       img = &priv->fw->img[priv->cur_ucode];
+                       inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
+                       data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
+               }
+               if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) ||
+                   nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) ||
+                   nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size))
+                       goto nla_put_failure;
+               status = cfg80211_testmode_reply(skb);
+               if (status < 0)
+                       IWL_ERR(priv, "Error sending msg : %d\n", status);
+               break;
+
+       default:
+               IWL_ERR(priv, "Unknown testmode driver command ID\n");
+               return -ENOSYS;
+       }
+       return status;
+
+nla_put_failure:
+       kfree_skb(skb);
+       return -EMSGSIZE;
+}
+
+/*
+ * This function handles the user application switch ucode ownership.
+ *
+ * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
+ * decide who the current owner of the uCode
+ *
+ * If the current owner is OWNERSHIP_TM, then the only host command
+ * can deliver to uCode is from testmode, all the other host commands
+ * will dropped.
+ *
+ * default driver is the owner of uCode in normal operational mode
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       u8 owner;
+
+       if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
+               IWL_ERR(priv, "Missing ucode owner\n");
+               return -ENOMSG;
+       }
+
+       owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
+       if (owner == IWL_OWNERSHIP_DRIVER) {
+               priv->ucode_owner = owner;
+               iwl_test_enable_notifications(&priv->tst, false);
+       } else if (owner == IWL_OWNERSHIP_TM) {
+               priv->ucode_owner = owner;
+               iwl_test_enable_notifications(&priv->tst, true);
+       } else {
+               IWL_ERR(priv, "Invalid owner\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* The testmode gnl message handler that takes the gnl message from the
+ * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
+ * invoke the corresponding handlers.
+ *
+ * This function is invoked when there is user space application sending
+ * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
+ * by nl80211.
+ *
+ * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
+ * dispatching it to the corresponding handler.
+ *
+ * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
+ * -ENOSYS is replied to the user application if the command is unknown;
+ * Otherwise, the command is dispatched to the respective handler.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @data: pointer to user space message
+ * @len: length in byte of @data
+ */
+int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+       struct nlattr *tb[IWL_TM_ATTR_MAX];
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       int result;
+
+       result = iwl_test_parse(&priv->tst, tb, data, len);
+       if (result)
+               return result;
+
+       /* in case multiple accesses to the device happens */
+       mutex_lock(&priv->mutex);
+       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+       case IWL_TM_CMD_APP2DEV_UCODE:
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+       case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+       case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
+       case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+               result = iwl_test_handle_cmd(&priv->tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+       case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+       case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+       case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+       case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
+       case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
+               IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
+               result = iwl_testmode_driver(hw, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_OWNERSHIP:
+               IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
+               result = iwl_testmode_ownership(hw, tb);
+               break;
+
+       default:
+               IWL_ERR(priv, "Unknown testmode command\n");
+               result = -ENOSYS;
+               break;
+       }
+       mutex_unlock(&priv->mutex);
+
+       if (result)
+               IWL_ERR(priv, "Test cmd failed result=%d\n", result);
+       return result;
+}
+
+int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+                     struct netlink_callback *cb,
+                     void *data, int len)
+{
+       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
+       int result;
+       u32 cmd;
+
+       if (cb->args[3]) {
+               /* offset by 1 since commands start at 0 */
+               cmd = cb->args[3] - 1;
+       } else {
+               struct nlattr *tb[IWL_TM_ATTR_MAX];
+
+               result = iwl_test_parse(&priv->tst, tb, data, len);
+               if (result)
+                       return result;
+
+               cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+               cb->args[3] = cmd + 1;
+       }
+
+       /* in case multiple accesses to the device happens */
+       mutex_lock(&priv->mutex);
+       result = iwl_test_dump(&priv->tst, cmd, skb, cb);
+       mutex_unlock(&priv->mutex);
+       return result;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
new file mode 100644 (file)
index 0000000..eb86443
--- /dev/null
@@ -0,0 +1,693 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/slab.h>
+#include <linux/init.h>
+#include <net/mac80211.h>
+#include "iwl-io.h"
+#include "iwl-modparams.h"
+#include "iwl-debug.h"
+#include "agn.h"
+#include "dev.h"
+#include "commands.h"
+#include "tt.h"
+
+/* default Thermal Throttling transaction table
+ * Current state   |         Throttling Down               |  Throttling Up
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     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 - 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 - 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, 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},
+       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+       {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
+       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
+       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
+       {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
+};
+
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (tt->state >= IWL_TI_1)
+               return true;
+       return false;
+}
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       return tt->tt_power_mode;
+}
+
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return true;
+       restriction = tt->restriction + tt->state;
+       return restriction->is_ht;
+}
+
+static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+       bool within_margin = false;
+
+       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;
+}
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv)
+{
+       bool is_ct_kill = false;
+
+       if (iwl_within_ct_kill_margin(priv)) {
+               iwl_tt_enter_ct_kill(priv);
+               is_ct_kill = true;
+       }
+       return is_ct_kill;
+}
+
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return IWL_ANT_OK_MULTI;
+       restriction = tt->restriction + tt->state;
+       return restriction->tx_stream;
+}
+
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return IWL_ANT_OK_MULTI;
+       restriction = tt->restriction + tt->state;
+       return restriction->rx_stream;
+}
+
+#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
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       unsigned long flags;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (tt->state == IWL_TI_CT_KILL) {
+               if (priv->thermal_throttle.ct_kill_toggle) {
+                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
+                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+                       priv->thermal_throttle.ct_kill_toggle = false;
+               } else {
+                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
+                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+                       priv->thermal_throttle.ct_kill_toggle = true;
+               }
+               iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
+               spin_lock_irqsave(&priv->trans->reg_lock, flags);
+               if (likely(iwl_grab_nic_access(priv->trans)))
+                       iwl_release_nic_access(priv->trans);
+               spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
+
+               /* Reschedule the ct_kill timer to occur in
+                * CT_KILL_EXIT_DURATION seconds to ensure we get a
+                * thermal update */
+               IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
+               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+                         jiffies + CT_KILL_EXIT_DURATION * HZ);
+       }
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+                          bool stop)
+{
+       if (stop) {
+               IWL_DEBUG_TEMP(priv, "Stop all queues\n");
+               if (priv->mac80211_registered)
+                       ieee80211_stop_queues(priv->hw);
+               IWL_DEBUG_TEMP(priv,
+                               "Schedule 5 seconds CT_KILL Timer\n");
+               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+                         jiffies + CT_KILL_EXIT_DURATION * HZ);
+       } else {
+               IWL_DEBUG_TEMP(priv, "Wake all queues\n");
+               if (priv->mac80211_registered)
+                       ieee80211_wake_queues(priv->hw);
+       }
+}
+
+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_TEMP(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_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+       /* make request to retrieve statistics information */
+       iwl_send_statistics_request(priv, CMD_SYNC, false);
+       /* 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)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *     Chip will identify dangerously high temperatures that can
+ *     harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *     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, bool force)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       enum iwl_tt_state old_state;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if ((tt->tt_previous_temp) &&
+           (temp > tt->tt_previous_temp) &&
+           ((temp - tt->tt_previous_temp) >
+           IWL_TT_INCREASE_MARGIN)) {
+               IWL_DEBUG_TEMP(priv,
+                       "Temperature increase %d degree Celsius\n",
+                       (temp - tt->tt_previous_temp));
+       }
+#endif
+       old_state = tt->state;
+       /* in Celsius */
+       if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+               tt->state = IWL_TI_CT_KILL;
+       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+               tt->state = IWL_TI_2;
+       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+               tt->state = IWL_TI_1;
+       else
+               tt->state = IWL_TI_0;
+
+#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:
+                       /*
+                        * When the system is ready to go back to IWL_TI_0
+                        * we only have to call iwl_power_update_mode() to
+                        * do so.
+                        */
+                       break;
+               case IWL_TI_1:
+                       tt->tt_power_mode = IWL_POWER_INDEX_3;
+                       break;
+               case IWL_TI_2:
+                       tt->tt_power_mode = IWL_POWER_INDEX_4;
+                       break;
+               default:
+                       tt->tt_power_mode = IWL_POWER_INDEX_5;
+                       break;
+               }
+               mutex_lock(&priv->mutex);
+               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) {
+                               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_TEMP(priv, "Temperature state changed %u\n",
+                                       tt->state);
+                       IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
+                                       tt->tt_power_mode);
+               }
+               mutex_unlock(&priv->mutex);
+       }
+}
+
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *     Chip will identify dangerously high temperatures that can
+ *     harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *     Throttle early enough to lower the power consumption before
+ *     drastic steps are needed
+ *     Actions include relaxing the power down sleep thresholds and
+ *     decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     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, bool force)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       int i;
+       bool changed = false;
+       enum iwl_tt_state old_state;
+       struct iwl_tt_trans *transaction;
+
+       old_state = tt->state;
+       for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+               /* based on the current TT state,
+                * find the curresponding transaction table
+                * each table has (IWL_TI_STATE_MAX - 1) entries
+                * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+                * will advance to the correct table.
+                * then based on the current temperature
+                * find the next state need to transaction to
+                * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+                * in the current table to see if transaction is needed
+                */
+               transaction = tt->transaction +
+                       ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+               if (temp >= transaction->tt_low &&
+                   temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+                       if ((tt->tt_previous_temp) &&
+                           (temp > tt->tt_previous_temp) &&
+                           ((temp - tt->tt_previous_temp) >
+                           IWL_TT_INCREASE_MARGIN)) {
+                               IWL_DEBUG_TEMP(priv,
+                                       "Temperature increase %d "
+                                       "degree Celsius\n",
+                                       (temp - tt->tt_previous_temp));
+                       }
+                       tt->tt_previous_temp = temp;
+#endif
+                       if (old_state !=
+                           transaction->next_state) {
+                               changed = true;
+                               tt->state =
+                                       transaction->next_state;
+                       }
+                       break;
+               }
+       }
+       /* stop ct_kill_waiting_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+       if (changed) {
+               if (tt->state >= IWL_TI_1) {
+                       /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+                       tt->tt_power_mode = IWL_POWER_INDEX_5;
+
+                       if (!iwl_ht_enabled(priv)) {
+                               struct iwl_rxon_context *ctx;
+
+                               for_each_context(priv, ctx) {
+                                       struct iwl_rxon_cmd *rxon;
+
+                                       rxon = &ctx->staging;
+
+                                       /* disable HT */
+                                       rxon->flags &= ~(
+                                               RXON_FLG_CHANNEL_MODE_MSK |
+                                               RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+                                               RXON_FLG_HT40_PROT_MSK |
+                                               RXON_FLG_HT_PROT_MSK);
+                               }
+                       } else {
+                               /* check HT capability and set
+                                * according to the system HT capability
+                                * in case get disabled before */
+                               iwl_set_rxon_ht(priv, &priv->current_ht_config);
+                       }
+
+               } else {
+                       /*
+                        * restore system power setting -- it will be
+                        * recalculated automatically.
+                        */
+
+                       /* check HT capability and set
+                        * according to the system HT capability
+                        * in case get disabled before */
+                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
+               }
+               mutex_lock(&priv->mutex);
+               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_TEMP(priv,
+                                       "Thermal Throttling to new state: %u\n",
+                                       tt->state);
+                       if (old_state != IWL_TI_CT_KILL &&
+                           tt->state == IWL_TI_CT_KILL) {
+                               if (force) {
+                                       IWL_DEBUG_TEMP(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_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
+                               iwl_perform_ct_kill_task(priv, false);
+                       }
+               }
+               mutex_unlock(&priv->mutex);
+       }
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+static void iwl_bg_ct_enter(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!iwl_is_ready(priv))
+               return;
+
+       if (tt->state != IWL_TI_CT_KILL) {
+               IWL_ERR(priv, "Device reached critical temperature "
+                             "- ucode going to sleep!\n");
+               if (!priv->thermal_throttle.advanced_tt)
+                       iwl_legacy_tt_handler(priv,
+                                             IWL_MINIMAL_POWER_THRESHOLD,
+                                             true);
+               else
+                       iwl_advance_tt_handler(priv,
+                                              CT_KILL_THRESHOLD + 1, true);
+       }
+}
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+static void iwl_bg_ct_exit(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!iwl_is_ready(priv))
+               return;
+
+       /* stop ct_kill_exit_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+
+       if (tt->state == IWL_TI_CT_KILL) {
+               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,
+                                     true);
+               else
+                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+                                              true);
+       }
+}
+
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
+       queue_work(priv->workqueue, &priv->ct_enter);
+}
+
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
+       queue_work(priv->workqueue, &priv->ct_exit);
+}
+
+static void iwl_bg_tt_work(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               iwl_legacy_tt_handler(priv, temp, false);
+       else
+               iwl_advance_tt_handler(priv, temp, false);
+}
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
+       queue_work(priv->workqueue, &priv->tt_work);
+}
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ *     Initialize Thermal Index and temperature threshold table
+ *     Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+       struct iwl_tt_trans *transaction;
+
+       IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
+
+       memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+       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;
+       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);
+
+       if (priv->cfg->base_params->adv_thermal_throttle) {
+               IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
+               tt->restriction = kcalloc(IWL_TI_STATE_MAX,
+                                         sizeof(struct iwl_tt_restriction),
+                                         GFP_KERNEL);
+               tt->transaction = kcalloc(IWL_TI_STATE_MAX *
+                                         (IWL_TI_STATE_MAX - 1),
+                                         sizeof(struct iwl_tt_trans),
+                                         GFP_KERNEL);
+               if (!tt->restriction || !tt->transaction) {
+                       IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+                       priv->thermal_throttle.advanced_tt = false;
+                       kfree(tt->restriction);
+                       tt->restriction = NULL;
+                       kfree(tt->transaction);
+                       tt->transaction = NULL;
+               } else {
+                       transaction = tt->transaction +
+                               (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_0[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_1[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_2[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_3[0], size);
+                       size = sizeof(struct iwl_tt_restriction) *
+                               IWL_TI_STATE_MAX;
+                       memcpy(tt->restriction,
+                               &restriction_range[0], size);
+                       priv->thermal_throttle.advanced_tt = true;
+               }
+       } else {
+               IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
+               priv->thermal_throttle.advanced_tt = false;
+       }
+}
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       /* 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);
+
+       if (priv->thermal_throttle.advanced_tt) {
+               /* free advance thermal throttling memory */
+               kfree(tt->restriction);
+               tt->restriction = NULL;
+               kfree(tt->transaction);
+               tt->transaction = NULL;
+       }
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h
new file mode 100644 (file)
index 0000000..44c7c8f
--- /dev/null
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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_tt_setting_h__
+#define __iwl_tt_setting_h__
+
+#include "commands.h"
+
+#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,
+       IWL_ANT_OK_SINGLE,
+       IWL_ANT_OK_MULTI,
+};
+
+/* Thermal Throttling State Machine states */
+enum  iwl_tt_state {
+       IWL_TI_0,       /* normal temperature, system power state */
+       IWL_TI_1,       /* high temperature detect, low power state */
+       IWL_TI_2,       /* higher temperature detected, lower power state */
+       IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+       IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ *
+ * This table is used by advance thermal throttling management
+ * based on the current thermal throttling state, and determines
+ * the number of tx/rx streams and the status of HT operation.
+ */
+struct iwl_tt_restriction {
+       enum iwl_antenna_ok tx_stream;
+       enum iwl_antenna_ok rx_stream;
+       bool is_ht;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table
+ * @next_state:  next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ *
+ * This is used by the advanced thermal throttling algorithm
+ * to determine the next thermal state to go based on the
+ * current temperature.
+ */
+struct iwl_tt_trans {
+       enum iwl_tt_state next_state;
+       u32 tt_low;
+       u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @advanced_tt:    advanced thermal throttle required
+ * @state:          current Thermal Throttling state
+ * @tt_power_mode:  Thermal Throttling power mode index
+ *                 being used to set power level when
+ *                 when thermal throttling state != IWL_TI_0
+ *                 the tt_power_mode should set to different
+ *                 power mode based on the current tt state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ *                 thermal throttling to determine how many tx/rx streams
+ *                 should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ *                 state transaction
+ * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
+ * @ct_kill_exit_tm: timer to exit thermal kill
+ */
+struct iwl_tt_mgmt {
+       enum iwl_tt_state state;
+       bool advanced_tt;
+       u8 tt_power_mode;
+       bool ct_kill_toggle;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       s32 tt_previous_temp;
+#endif
+       struct iwl_tt_restriction *restriction;
+       struct iwl_tt_trans *transaction;
+       struct timer_list ct_kill_exit_tm;
+       struct timer_list ct_kill_waiting_tm;
+};
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
+bool iwl_ht_enabled(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);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
+
+#endif  /* __iwl_tt_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
new file mode 100644 (file)
index 0000000..5971a23
--- /dev/null
@@ -0,0 +1,1388 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * 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/sched.h>
+#include <linux/ieee80211.h>
+#include "iwl-io.h"
+#include "iwl-trans.h"
+#include "iwl-agn-hw.h"
+#include "dev.h"
+#include "agn.h"
+
+static const u8 tid_to_ac[] = {
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_VO,
+};
+
+static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
+                                    struct ieee80211_tx_info *info,
+                                    __le16 fc, __le32 *tx_flags)
+{
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
+           info->flags & IEEE80211_TX_CTL_AMPDU)
+               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
+                                     struct sk_buff *skb,
+                                     struct iwl_tx_cmd *tx_cmd,
+                                     struct ieee80211_tx_info *info,
+                                     struct ieee80211_hdr *hdr, u8 sta_id)
+{
+       __le16 fc = hdr->frame_control;
+       __le32 tx_flags = tx_cmd->tx_flags;
+
+       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;
+       else
+               tx_flags &= ~TX_CMD_FLG_ACK_MSK;
+
+       if (ieee80211_is_probe_resp(fc))
+               tx_flags |= TX_CMD_FLG_TSF_MSK;
+       else if (ieee80211_is_back_req(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+       else if (info->band == IEEE80211_BAND_2GHZ &&
+                priv->cfg->bt_params &&
+                priv->cfg->bt_params->advanced_bt_coexist &&
+                (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
+                ieee80211_is_reassoc_req(fc) ||
+                skb->protocol == cpu_to_be16(ETH_P_PAE)))
+               tx_flags |= TX_CMD_FLG_IGNORE_BT;
+
+
+       tx_cmd->sta_id = sta_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_cmd->tid_tspec = qc[0] & 0xf;
+               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+       } else {
+               tx_cmd->tid_tspec = IWL_TID_NON_QOS;
+               if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+               else
+                       tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
+
+       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_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+               else
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+       } else {
+               tx_cmd->timeout.pm_frame_timeout = 0;
+       }
+
+       tx_cmd->driver_txop = 0;
+       tx_cmd->tx_flags = tx_flags;
+       tx_cmd->next_frame_len = 0;
+}
+
+static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
+                                    struct iwl_tx_cmd *tx_cmd,
+                                    struct ieee80211_tx_info *info,
+                                    __le16 fc)
+{
+       u32 rate_flags;
+       int rate_idx;
+       u8 rts_retry_limit;
+       u8 data_retry_limit;
+       u8 rate_plcp;
+
+       if (priv->wowlan) {
+               rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+               data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
+       } else {
+               /* Set retry limit on RTS packets */
+               rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT;
+
+               /* Set retry limit on DATA packets and Probe Responses*/
+               if (ieee80211_is_probe_resp(fc)) {
+                       data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT;
+                       rts_retry_limit =
+                               min(data_retry_limit, rts_retry_limit);
+               } else if (ieee80211_is_back_req(fc))
+                       data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT;
+               else
+                       data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
+       }
+
+       tx_cmd->data_retry_limit = data_retry_limit;
+       tx_cmd->rts_retry_limit = rts_retry_limit;
+
+       /* DATA packets will use the uCode station table for rate/antenna
+        * selection */
+       if (ieee80211_is_data(fc)) {
+               tx_cmd->initial_rate_index = 0;
+               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
+               if (priv->tm_fixed_rate) {
+                       /*
+                        * rate overwrite by testmode
+                        * we not only send lq command to change rate
+                        * we also re-enforce per data pkt base.
+                        */
+                       tx_cmd->tx_flags &= ~TX_CMD_FLG_STA_RATE_MSK;
+                       memcpy(&tx_cmd->rate_n_flags, &priv->tm_fixed_rate,
+                              sizeof(tx_cmd->rate_n_flags));
+               }
+#endif
+               return;
+       } else if (ieee80211_is_back_req(fc))
+               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+
+       /**
+        * If the current TX rate stored in mac80211 has the MCS bit set, it's
+        * not really a TX rate.  Thus, we use the lowest supported rate for
+        * this band.  Also use the lowest supported rate if the stored rate
+        * index is invalid.
+        */
+       rate_idx = info->control.rates[0].idx;
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
+                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
+               rate_idx = rate_lowest_index(
+                               &priv->eeprom_data->bands[info->band],
+                               info->control.sta);
+       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate_idx += IWL_FIRST_OFDM_RATE;
+       /* Get PLCP rate for tx_cmd->rate_n_flags */
+       rate_plcp = iwl_rates[rate_idx].plcp;
+       /* Zero out flags for this packet */
+       rate_flags = 0;
+
+       /* Set CCK flag as needed */
+       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+       /* Set up antennas */
+        if (priv->cfg->bt_params &&
+            priv->cfg->bt_params->advanced_bt_coexist &&
+            priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+                               first_antenna(priv->eeprom_data->valid_tx_ant));
+       } else
+               priv->mgmt_tx_ant = iwl_toggle_tx_ant(
+                                       priv, priv->mgmt_tx_ant,
+                                       priv->eeprom_data->valid_tx_ant);
+       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+       /* Set the rate in the TX cmd */
+       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+                                        struct ieee80211_tx_info *info,
+                                        struct iwl_tx_cmd *tx_cmd,
+                                        struct sk_buff *skb_frag)
+{
+       struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
+               break;
+
+       case WLAN_CIPHER_SUITE_TKIP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+               ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
+               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
+               break;
+
+       case WLAN_CIPHER_SUITE_WEP104:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_WEP40:
+               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
+                            "with key %d\n", keyconf->keyidx);
+               break;
+
+       default:
+               IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
+               break;
+       }
+}
+
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @context: the current context
+ * @sta: mac80211 station
+ *
+ * In certain circumstances mac80211 passes a station pointer
+ * that may be %NULL, for example during TX or key setup. In
+ * that case, we need to use the broadcast station, so this
+ * inline wraps that pattern.
+ */
+static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
+                                  struct ieee80211_sta *sta)
+{
+       int sta_id;
+
+       if (!sta)
+               return context->bcast_sta_id;
+
+       sta_id = iwl_sta_id(sta);
+
+       /*
+        * mac80211 should not be passing a partially
+        * initialised station!
+        */
+       WARN_ON(sta_id == IWL_INVALID_STATION);
+
+       return sta_id;
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwlagn_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 iwl_station_priv *sta_priv = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_device_cmd *dev_cmd;
+       struct iwl_tx_cmd *tx_cmd;
+       __le16 fc;
+       u8 hdr_len;
+       u16 len, seq_number = 0;
+       u8 sta_id, tid = IWL_MAX_TID_COUNT;
+       bool is_agg = false;
+       int txq_id;
+
+       if (info->control.vif)
+               ctx = iwl_rxon_ctx_from_vif(info->control.vif);
+
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
+               goto drop_unlock_priv;
+       }
+
+       fc = hdr->frame_control;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (ieee80211_is_auth(fc))
+               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
+       else if (ieee80211_is_assoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
+       else if (ieee80211_is_reassoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
+#endif
+
+       if (unlikely(ieee80211_is_probe_resp(fc))) {
+               struct iwl_wipan_noa_data *noa_data =
+                       rcu_dereference(priv->noa_data);
+
+               if (noa_data &&
+                   pskb_expand_head(skb, 0, noa_data->length,
+                                    GFP_ATOMIC) == 0) {
+                       memcpy(skb_put(skb, noa_data->length),
+                              noa_data->data, noa_data->length);
+                       hdr = (struct ieee80211_hdr *)skb->data;
+               }
+       }
+
+       hdr_len = ieee80211_hdrlen(fc);
+
+       /* For management frames use broadcast id to do not break aggregation */
+       if (!ieee80211_is_data(fc))
+               sta_id = ctx->bcast_sta_id;
+       else {
+               /* Find index into station table for destination station */
+               sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+                                      hdr->addr1);
+                       goto drop_unlock_priv;
+               }
+       }
+
+       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
+
+       if (info->control.sta)
+               sta_priv = (void *)info->control.sta->drv_priv;
+
+       if (sta_priv && sta_priv->asleep &&
+           (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
+               /*
+                * This sends an asynchronous command to the device,
+                * but we can rely on it being processed before the
+                * next frame is processed -- and the next frame to
+                * this station is the one that will consume this
+                * counter.
+                * For now set the counter to just 1 since we do not
+                * support uAPSD yet.
+                *
+                * FIXME: If we get two non-bufferable frames one
+                * after the other, we might only send out one of
+                * them because this is racy.
+                */
+               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+       }
+
+       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               is_agg = true;
+
+       dev_cmd = iwl_trans_alloc_tx_cmd(priv->trans);
+
+       if (unlikely(!dev_cmd))
+               goto drop_unlock_priv;
+
+       memset(dev_cmd, 0, sizeof(*dev_cmd));
+       tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+
+       /* Total # bytes to be transmitted */
+       len = (u16)skb->len;
+       tx_cmd->len = cpu_to_le16(len);
+
+       if (info->control.hw_key)
+               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb);
+
+       /* TODO need this for burst mode later on */
+       iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
+
+       iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
+
+       memset(&info->status, 0, sizeof(info->status));
+
+       info->driver_data[0] = ctx;
+       info->driver_data[1] = dev_cmd;
+       /* From now on, we cannot access info->control */
+
+       spin_lock(&priv->sta_lock);
+
+       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
+               u8 *qc = NULL;
+               struct iwl_tid_data *tid_data;
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+                       goto drop_unlock_sta;
+               tid_data = &priv->tid_data[sta_id][tid];
+
+               /* aggregation is on for this <sta,tid> */
+               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+                   tid_data->agg.state != IWL_AGG_ON) {
+                       IWL_ERR(priv, "TX_CTL_AMPDU while not in AGG:"
+                               " Tx flags = 0x%08x, agg.state = %d",
+                               info->flags, tid_data->agg.state);
+                       IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
+                               sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
+                       goto drop_unlock_sta;
+               }
+
+               /* We can receive packets from the stack in IWL_AGG_{ON,OFF}
+                * only. Check this here.
+                */
+               if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON &&
+                   tid_data->agg.state != IWL_AGG_OFF,
+                   "Tx while agg.state = %d", tid_data->agg.state))
+                       goto drop_unlock_sta;
+
+               seq_number = tid_data->seq_number;
+               seq_number &= IEEE80211_SCTL_SEQ;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(seq_number);
+               seq_number += 0x10;
+       }
+
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+       if (is_agg)
+               txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+       else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+               /*
+                * Send this frame after DTIM -- there's a special queue
+                * reserved for this for contexts that support AP mode.
+                */
+               txq_id = ctx->mcast_queue;
+
+               /*
+                * The microcode will clear the more data
+                * bit in the last frame it transmits.
+                */
+               hdr->frame_control |=
+                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+               txq_id = IWL_AUX_QUEUE;
+       else
+               txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
+
+       WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
+       WARN_ON_ONCE(is_agg &&
+                    priv->queue_to_mac80211[txq_id] != info->hw_queue);
+
+       if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
+               goto drop_unlock_sta;
+
+       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
+           !ieee80211_has_morefrags(fc))
+               priv->tid_data[sta_id][tid].seq_number = seq_number;
+
+       spin_unlock(&priv->sta_lock);
+
+       /*
+        * Avoid atomic ops if it isn't an associated client.
+        * Also, if this is a packet for aggregation, don't
+        * increase the counter because the ucode will stop
+        * aggregation queues when their respective station
+        * goes to sleep.
+        */
+       if (sta_priv && sta_priv->client && !is_agg)
+               atomic_inc(&sta_priv->pending_frames);
+
+       if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+               iwl_scan_offchannel_skb(priv);
+
+       return 0;
+
+drop_unlock_sta:
+       if (dev_cmd)
+               iwl_trans_free_tx_cmd(priv->trans, dev_cmd);
+       spin_unlock(&priv->sta_lock);
+drop_unlock_priv:
+       return -1;
+}
+
+static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int mq)
+{
+       int q;
+
+       for (q = IWLAGN_FIRST_AMPDU_QUEUE;
+            q < priv->cfg->base_params->num_of_queues; q++) {
+               if (!test_and_set_bit(q, priv->agg_q_alloc)) {
+                       priv->queue_to_mac80211[q] = mq;
+                       return q;
+               }
+       }
+
+       return -ENOSPC;
+}
+
+static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q)
+{
+       clear_bit(q, priv->agg_q_alloc);
+       priv->queue_to_mac80211[q] = IWL_INVALID_MAC80211_QUEUE;
+}
+
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid)
+{
+       struct iwl_tid_data *tid_data;
+       int sta_id, txq_id;
+       enum iwl_agg_state agg_state;
+
+       sta_id = iwl_sta_id(sta);
+
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+               return -ENXIO;
+       }
+
+       spin_lock_bh(&priv->sta_lock);
+
+       tid_data = &priv->tid_data[sta_id][tid];
+       txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
+
+       switch (priv->tid_data[sta_id][tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /*
+               * This can happen if the peer stops aggregation
+               * again before we've had a chance to drain the
+               * queue we selected previously, i.e. before the
+               * session was really started completely.
+               */
+               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+               goto turn_off;
+       case IWL_AGG_STARTING:
+               /*
+                * This can happen when the session is stopped before
+                * we receive ADDBA response
+                */
+               IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n");
+               goto turn_off;
+       case IWL_AGG_ON:
+               break;
+       default:
+               IWL_WARN(priv, "Stopping AGG while state not ON "
+                        "or starting for %d on %d (%d)\n", sta_id, tid,
+                        priv->tid_data[sta_id][tid].agg.state);
+               spin_unlock_bh(&priv->sta_lock);
+               return 0;
+       }
+
+       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+
+       /* There are still packets for this RA / TID in the HW */
+       if (!test_bit(txq_id, priv->agg_q_alloc)) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "stopping AGG on STA/TID %d/%d but hwq %d not used\n",
+                       sta_id, tid, txq_id);
+       } else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
+               IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
+                                   "next_recl = %d\n",
+                                   tid_data->agg.ssn,
+                                   tid_data->next_reclaimed);
+               priv->tid_data[sta_id][tid].agg.state =
+                       IWL_EMPTYING_HW_QUEUE_DELBA;
+               spin_unlock_bh(&priv->sta_lock);
+               return 0;
+       }
+
+       IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
+                           tid_data->agg.ssn);
+turn_off:
+       agg_state = priv->tid_data[sta_id][tid].agg.state;
+       priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
+
+       spin_unlock_bh(&priv->sta_lock);
+
+       if (test_bit(txq_id, priv->agg_q_alloc)) {
+               /*
+                * If the transport didn't know that we wanted to start
+                * agreggation, don't tell it that we want to stop them.
+                * This can happen when we don't get the addBA response on
+                * time, or we hadn't time to drain the AC queues.
+                */
+               if (agg_state == IWL_AGG_ON)
+                       iwl_trans_txq_disable(priv->trans, txq_id);
+               else
+                       IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
+                                           agg_state);
+               iwlagn_dealloc_agg_txq(priv, txq_id);
+       }
+
+       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+
+       return 0;
+}
+
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       struct iwl_tid_data *tid_data;
+       int sta_id, txq_id, ret;
+
+       IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
+                    sta->addr, tid);
+
+       sta_id = iwl_sta_id(sta);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Start AGG on invalid station\n");
+               return -ENXIO;
+       }
+       if (unlikely(tid >= IWL_MAX_TID_COUNT))
+               return -EINVAL;
+
+       if (priv->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) {
+               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
+               return -ENXIO;
+       }
+
+       txq_id = iwlagn_alloc_agg_txq(priv, ctx->ac_to_queue[tid_to_ac[tid]]);
+       if (txq_id < 0) {
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "No free aggregation queue for %pM/%d\n",
+                       sta->addr, tid);
+               return txq_id;
+       }
+
+       ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+       if (ret)
+               return ret;
+
+       spin_lock_bh(&priv->sta_lock);
+       tid_data = &priv->tid_data[sta_id][tid];
+       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.txq_id = txq_id;
+
+       *ssn = tid_data->agg.ssn;
+
+       if (*ssn == tid_data->next_reclaimed) {
+               IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
+                                   tid_data->agg.ssn);
+               tid_data->agg.state = IWL_AGG_STARTING;
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+       } else {
+               IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
+                                   "next_reclaimed = %d\n",
+                                   tid_data->agg.ssn,
+                                   tid_data->next_reclaimed);
+               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+       }
+       spin_unlock_bh(&priv->sta_lock);
+
+       return ret;
+}
+
+int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u8 buf_size)
+{
+       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       int q, fifo;
+       u16 ssn;
+
+       buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+       spin_lock_bh(&priv->sta_lock);
+       ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
+       q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id;
+       priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON;
+       spin_unlock_bh(&priv->sta_lock);
+
+       fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
+
+       iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid,
+                            buf_size, ssn);
+
+       /*
+        * If the limit is 0, then it wasn't initialised yet,
+        * use the default. We can do that since we take the
+        * minimum below, and we don't want to go above our
+        * default due to hardware restrictions.
+        */
+       if (sta_priv->max_agg_bufsize == 0)
+               sta_priv->max_agg_bufsize =
+                       LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+       /*
+        * Even though in theory the peer could have different
+        * aggregation reorder buffer sizes for different sessions,
+        * our ucode doesn't allow for that and has a global limit
+        * for each station. Therefore, use the minimum of all the
+        * aggregation sessions and our default value.
+        */
+       sta_priv->max_agg_bufsize =
+               min(sta_priv->max_agg_bufsize, buf_size);
+
+       if (priv->hw_params.use_rts_for_aggregation) {
+               /*
+                * switch to RTS/CTS if it is the prefer protection
+                * method for HT traffic
+                */
+
+               sta_priv->lq_sta.lq.general_params.flags |=
+                       LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+       }
+       priv->agg_tids_count++;
+       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                    priv->agg_tids_count);
+
+       sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
+               sta_priv->max_agg_bufsize;
+
+       IWL_DEBUG_HT(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+                sta->addr, tid);
+
+       return iwl_send_lq_cmd(priv, ctx,
+                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+}
+
+static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
+{
+       struct iwl_tid_data *tid_data = &priv->tid_data[sta_id][tid];
+       enum iwl_rxon_context_id ctx;
+       struct ieee80211_vif *vif;
+       u8 *addr;
+
+       lockdep_assert_held(&priv->sta_lock);
+
+       addr = priv->stations[sta_id].sta.sta.addr;
+       ctx = priv->stations[sta_id].ctxid;
+       vif = priv->contexts[ctx].vif;
+
+       switch (priv->tid_data[sta_id][tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_DELBA:
+               /* There are no packets for this RA / TID in the HW any more */
+               if (tid_data->agg.ssn == tid_data->next_reclaimed) {
+                       IWL_DEBUG_TX_QUEUES(priv,
+                               "Can continue DELBA flow ssn = next_recl ="
+                               " %d", tid_data->next_reclaimed);
+                       iwl_trans_txq_disable(priv->trans,
+                                             tid_data->agg.txq_id);
+                       iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
+                       tid_data->agg.state = IWL_AGG_OFF;
+                       ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+               }
+               break;
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /* There are no packets for this RA / TID in the HW any more */
+               if (tid_data->agg.ssn == tid_data->next_reclaimed) {
+                       IWL_DEBUG_TX_QUEUES(priv,
+                               "Can continue ADDBA flow ssn = next_recl ="
+                               " %d", tid_data->next_reclaimed);
+                       tid_data->agg.state = IWL_AGG_STARTING;
+                       ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
+                                    struct iwl_rxon_context *ctx,
+                                    const u8 *addr1)
+{
+       struct ieee80211_sta *sta;
+       struct iwl_station_priv *sta_priv;
+
+       rcu_read_lock();
+       sta = ieee80211_find_sta(ctx->vif, addr1);
+       if (sta) {
+               sta_priv = (void *)sta->drv_priv;
+               /* avoid atomic ops if this isn't a client */
+               if (sta_priv->client &&
+                   atomic_dec_return(&sta_priv->pending_frames) == 0)
+                       ieee80211_sta_block_awake(priv->hw, sta, false);
+       }
+       rcu_read_unlock();
+}
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+                                 struct ieee80211_tx_info *info)
+{
+       struct ieee80211_tx_rate *r = &info->status.rates[0];
+
+       info->status.antenna =
+               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               r->flags |= IEEE80211_TX_RC_MCS;
+       if (rate_n_flags & RATE_MCS_GF_MSK)
+               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+       if (rate_n_flags & RATE_MCS_DUP_MSK)
+               r->flags |= IEEE80211_TX_RC_DUP_DATA;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               r->flags |= IEEE80211_TX_RC_SHORT_GI;
+       r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
+
+       switch (status & TX_STATUS_MSK) {
+       case TX_STATUS_SUCCESS:
+               return "SUCCESS";
+       TX_STATUS_POSTPONE(DELAY);
+       TX_STATUS_POSTPONE(FEW_BYTES);
+       TX_STATUS_POSTPONE(BT_PRIO);
+       TX_STATUS_POSTPONE(QUIET_PERIOD);
+       TX_STATUS_POSTPONE(CALC_TTAK);
+       TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+       TX_STATUS_FAIL(SHORT_LIMIT);
+       TX_STATUS_FAIL(LONG_LIMIT);
+       TX_STATUS_FAIL(FIFO_UNDERRUN);
+       TX_STATUS_FAIL(DRAIN_FLOW);
+       TX_STATUS_FAIL(RFKILL_FLUSH);
+       TX_STATUS_FAIL(LIFE_EXPIRE);
+       TX_STATUS_FAIL(DEST_PS);
+       TX_STATUS_FAIL(HOST_ABORTED);
+       TX_STATUS_FAIL(BT_RETRY);
+       TX_STATUS_FAIL(STA_INVALID);
+       TX_STATUS_FAIL(FRAG_DROPPED);
+       TX_STATUS_FAIL(TID_DISABLE);
+       TX_STATUS_FAIL(FIFO_FLUSHED);
+       TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
+       TX_STATUS_FAIL(PASSIVE_NO_RX);
+       TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
+       }
+
+       return "UNKNOWN";
+
+#undef TX_STATUS_FAIL
+#undef TX_STATUS_POSTPONE
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
+{
+       status &= AGG_TX_STATUS_MSK;
+
+       switch (status) {
+       case AGG_TX_STATE_UNDERRUN_MSK:
+               priv->reply_agg_tx_stats.underrun++;
+               break;
+       case AGG_TX_STATE_BT_PRIO_MSK:
+               priv->reply_agg_tx_stats.bt_prio++;
+               break;
+       case AGG_TX_STATE_FEW_BYTES_MSK:
+               priv->reply_agg_tx_stats.few_bytes++;
+               break;
+       case AGG_TX_STATE_ABORT_MSK:
+               priv->reply_agg_tx_stats.abort++;
+               break;
+       case AGG_TX_STATE_LAST_SENT_TTL_MSK:
+               priv->reply_agg_tx_stats.last_sent_ttl++;
+               break;
+       case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
+               priv->reply_agg_tx_stats.last_sent_try++;
+               break;
+       case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
+               priv->reply_agg_tx_stats.last_sent_bt_kill++;
+               break;
+       case AGG_TX_STATE_SCD_QUERY_MSK:
+               priv->reply_agg_tx_stats.scd_query++;
+               break;
+       case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
+               priv->reply_agg_tx_stats.bad_crc32++;
+               break;
+       case AGG_TX_STATE_RESPONSE_MSK:
+               priv->reply_agg_tx_stats.response++;
+               break;
+       case AGG_TX_STATE_DUMP_TX_MSK:
+               priv->reply_agg_tx_stats.dump_tx++;
+               break;
+       case AGG_TX_STATE_DELAY_TX_MSK:
+               priv->reply_agg_tx_stats.delay_tx++;
+               break;
+       default:
+               priv->reply_agg_tx_stats.unknown++;
+               break;
+       }
+}
+
+static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
+                               struct iwlagn_tx_resp *tx_resp)
+{
+       struct agg_tx_status *frame_status = &tx_resp->status;
+       int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+               IWLAGN_TX_RES_TID_POS;
+       int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+               IWLAGN_TX_RES_RA_POS;
+       struct iwl_ht_agg *agg = &priv->tid_data[sta_id][tid].agg;
+       u32 status = le16_to_cpu(tx_resp->status.status);
+       int i;
+
+       WARN_ON(tid == IWL_TID_NON_QOS);
+
+       if (agg->wait_for_ba)
+               IWL_DEBUG_TX_REPLY(priv,
+                       "got tx response w/o block-ack\n");
+
+       agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       agg->wait_for_ba = (tx_resp->frame_count > 1);
+
+       /*
+        * If the BT kill count is non-zero, we'll get this
+        * notification again.
+        */
+       if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
+           priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
+       }
+
+       if (tx_resp->frame_count == 1)
+               return;
+
+       /* Construct bit-map of pending frames within Tx window */
+       for (i = 0; i < tx_resp->frame_count; i++) {
+               u16 fstatus = le16_to_cpu(frame_status[i].status);
+
+               if (status & AGG_TX_STATUS_MSK)
+                       iwlagn_count_agg_tx_err_status(priv, fstatus);
+
+               if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+                             AGG_TX_STATE_ABORT_MSK))
+                       continue;
+
+               IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
+                                  "try-count (0x%08x)\n",
+                                  iwl_get_agg_tx_fail_reason(fstatus),
+                                  fstatus & AGG_TX_STATUS_MSK,
+                                  fstatus & AGG_TX_TRY_MSK);
+       }
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
+
+const char *iwl_get_agg_tx_fail_reason(u16 status)
+{
+       status &= AGG_TX_STATUS_MSK;
+       switch (status) {
+       case AGG_TX_STATE_TRANSMITTED:
+               return "SUCCESS";
+               AGG_TX_STATE_FAIL(UNDERRUN_MSK);
+               AGG_TX_STATE_FAIL(BT_PRIO_MSK);
+               AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
+               AGG_TX_STATE_FAIL(ABORT_MSK);
+               AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
+               AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
+               AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
+               AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
+               AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
+               AGG_TX_STATE_FAIL(RESPONSE_MSK);
+               AGG_TX_STATE_FAIL(DUMP_TX_MSK);
+               AGG_TX_STATE_FAIL(DELAY_TX_MSK);
+       }
+
+       return "UNKNOWN";
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
+{
+       return le32_to_cpup((__le32 *)&tx_resp->status +
+                           tx_resp->frame_count) & MAX_SN;
+}
+
+static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_POSTPONE_DELAY:
+               priv->reply_tx_stats.pp_delay++;
+               break;
+       case TX_STATUS_POSTPONE_FEW_BYTES:
+               priv->reply_tx_stats.pp_few_bytes++;
+               break;
+       case TX_STATUS_POSTPONE_BT_PRIO:
+               priv->reply_tx_stats.pp_bt_prio++;
+               break;
+       case TX_STATUS_POSTPONE_QUIET_PERIOD:
+               priv->reply_tx_stats.pp_quiet_period++;
+               break;
+       case TX_STATUS_POSTPONE_CALC_TTAK:
+               priv->reply_tx_stats.pp_calc_ttak++;
+               break;
+       case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
+               priv->reply_tx_stats.int_crossed_retry++;
+               break;
+       case TX_STATUS_FAIL_SHORT_LIMIT:
+               priv->reply_tx_stats.short_limit++;
+               break;
+       case TX_STATUS_FAIL_LONG_LIMIT:
+               priv->reply_tx_stats.long_limit++;
+               break;
+       case TX_STATUS_FAIL_FIFO_UNDERRUN:
+               priv->reply_tx_stats.fifo_underrun++;
+               break;
+       case TX_STATUS_FAIL_DRAIN_FLOW:
+               priv->reply_tx_stats.drain_flow++;
+               break;
+       case TX_STATUS_FAIL_RFKILL_FLUSH:
+               priv->reply_tx_stats.rfkill_flush++;
+               break;
+       case TX_STATUS_FAIL_LIFE_EXPIRE:
+               priv->reply_tx_stats.life_expire++;
+               break;
+       case TX_STATUS_FAIL_DEST_PS:
+               priv->reply_tx_stats.dest_ps++;
+               break;
+       case TX_STATUS_FAIL_HOST_ABORTED:
+               priv->reply_tx_stats.host_abort++;
+               break;
+       case TX_STATUS_FAIL_BT_RETRY:
+               priv->reply_tx_stats.bt_retry++;
+               break;
+       case TX_STATUS_FAIL_STA_INVALID:
+               priv->reply_tx_stats.sta_invalid++;
+               break;
+       case TX_STATUS_FAIL_FRAG_DROPPED:
+               priv->reply_tx_stats.frag_drop++;
+               break;
+       case TX_STATUS_FAIL_TID_DISABLE:
+               priv->reply_tx_stats.tid_disable++;
+               break;
+       case TX_STATUS_FAIL_FIFO_FLUSHED:
+               priv->reply_tx_stats.fifo_flush++;
+               break;
+       case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
+               priv->reply_tx_stats.insuff_cf_poll++;
+               break;
+       case TX_STATUS_FAIL_PASSIVE_NO_RX:
+               priv->reply_tx_stats.fail_hw_drop++;
+               break;
+       case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
+               priv->reply_tx_stats.sta_color_mismatch++;
+               break;
+       default:
+               priv->reply_tx_stats.unknown++;
+               break;
+       }
+}
+
+static void iwlagn_set_tx_status(struct iwl_priv *priv,
+                                struct ieee80211_tx_info *info,
+                                struct iwlagn_tx_resp *tx_resp,
+                                bool is_agg)
+{
+       u16  status = le16_to_cpu(tx_resp->status.status);
+
+       info->status.rates[0].count = tx_resp->failure_frame + 1;
+       if (is_agg)
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+       info->flags |= iwl_tx_status_to_mac80211(status);
+       iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+                                   info);
+       if (!iwl_is_tx_success(status))
+               iwlagn_count_tx_err_status(priv, status);
+}
+
+static void iwl_check_abort_status(struct iwl_priv *priv,
+                           u8 frame_count, u32 status)
+{
+       if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
+               IWL_ERR(priv, "Tx flush command to flush out all frames\n");
+               if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       queue_work(priv->workqueue, &priv->tx_flush);
+       }
+}
+
+static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid,
+                      int txq_id, int ssn, struct sk_buff_head *skbs)
+{
+       if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
+                    tid != IWL_TID_NON_QOS &&
+                    txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) {
+               /*
+                * FIXME: this is a uCode bug which need to be addressed,
+                * log the information and return for now.
+                * Since it is can possibly happen very often and in order
+                * not to fill the syslog, don't use IWL_ERR or IWL_WARN
+                */
+               IWL_DEBUG_TX_QUEUES(priv,
+                       "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
+                       txq_id, sta_id, tid,
+                       priv->tid_data[sta_id][tid].agg.txq_id);
+               return 1;
+       }
+
+       iwl_trans_reclaim(priv->trans, txq_id, ssn, skbs);
+       return 0;
+}
+
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence);
+       struct iwlagn_tx_resp *tx_resp = (void *)pkt->data;
+       struct ieee80211_hdr *hdr;
+       u32 status = le16_to_cpu(tx_resp->status.status);
+       u16 ssn = iwlagn_get_scd_ssn(tx_resp);
+       int tid;
+       int sta_id;
+       int freed;
+       struct ieee80211_tx_info *info;
+       struct sk_buff_head skbs;
+       struct sk_buff *skb;
+       struct iwl_rxon_context *ctx;
+       bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
+       bool is_offchannel_skb;
+
+       tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
+               IWLAGN_TX_RES_TID_POS;
+       sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
+               IWLAGN_TX_RES_RA_POS;
+
+       spin_lock(&priv->sta_lock);
+
+       if (is_agg)
+               iwl_rx_reply_tx_agg(priv, tx_resp);
+
+       __skb_queue_head_init(&skbs);
+
+       is_offchannel_skb = false;
+
+       if (tx_resp->frame_count == 1) {
+               u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
+               next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
+
+               if (is_agg) {
+                       /* If this is an aggregation queue, we can rely on the
+                        * ssn since the wifi sequence number corresponds to
+                        * the index in the TFD ring (%256).
+                        * The seq_ctl is the sequence control of the packet
+                        * to which this Tx response relates. But if there is a
+                        * hole in the bitmap of the BA we received, this Tx
+                        * response may allow to reclaim the hole and all the
+                        * subsequent packets that were already acked.
+                        * In that case, seq_ctl != ssn, and the next packet
+                        * to be reclaimed will be ssn and not seq_ctl.
+                        */
+                       next_reclaimed = ssn;
+               }
+
+               if (tid != IWL_TID_NON_QOS) {
+                       priv->tid_data[sta_id][tid].next_reclaimed =
+                               next_reclaimed;
+                       IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
+                                                 next_reclaimed);
+               }
+
+               /*we can free until ssn % q.n_bd not inclusive */
+               WARN_ON_ONCE(iwl_reclaim(priv, sta_id, tid,
+                                        txq_id, ssn, &skbs));
+               iwlagn_check_ratid_empty(priv, sta_id, tid);
+               freed = 0;
+
+               /* process frames */
+               skb_queue_walk(&skbs, skb) {
+                       hdr = (struct ieee80211_hdr *)skb->data;
+
+                       if (!ieee80211_is_data_qos(hdr->frame_control))
+                               priv->last_seq_ctl = tx_resp->seq_ctl;
+
+                       info = IEEE80211_SKB_CB(skb);
+                       ctx = info->driver_data[0];
+                       iwl_trans_free_tx_cmd(priv->trans,
+                                             info->driver_data[1]);
+
+                       memset(&info->status, 0, sizeof(info->status));
+
+                       if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
+                           iwl_is_associated_ctx(ctx) && ctx->vif &&
+                           ctx->vif->type == NL80211_IFTYPE_STATION) {
+                               /* block and stop all queues */
+                               priv->passive_no_rx = true;
+                               IWL_DEBUG_TX_QUEUES(priv, "stop all queues: "
+                                                   "passive channel");
+                               ieee80211_stop_queues(priv->hw);
+
+                               IWL_DEBUG_TX_REPLY(priv,
+                                          "TXQ %d status %s (0x%08x) "
+                                          "rate_n_flags 0x%x retries %d\n",
+                                          txq_id,
+                                          iwl_get_tx_fail_reason(status),
+                                          status,
+                                          le32_to_cpu(tx_resp->rate_n_flags),
+                                          tx_resp->failure_frame);
+
+                               IWL_DEBUG_TX_REPLY(priv,
+                                          "FrameCnt = %d, idx=%d\n",
+                                          tx_resp->frame_count, cmd_index);
+                       }
+
+                       /* check if BAR is needed */
+                       if (is_agg && !iwl_is_tx_success(status))
+                               info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+                       iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
+                                    tx_resp, is_agg);
+                       if (!is_agg)
+                               iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
+
+                       is_offchannel_skb =
+                               (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN);
+                       freed++;
+               }
+
+               WARN_ON(!is_agg && freed != 1);
+
+               /*
+                * An offchannel frame can be send only on the AUX queue, where
+                * there is no aggregation (and reordering) so it only is single
+                * skb is expected to be processed.
+                */
+               WARN_ON(is_offchannel_skb && freed != 1);
+       }
+
+       iwl_check_abort_status(priv, tx_resp->frame_count, status);
+       spin_unlock(&priv->sta_lock);
+
+       while (!skb_queue_empty(&skbs)) {
+               skb = __skb_dequeue(&skbs);
+               ieee80211_tx_status(priv->hw, skb);
+       }
+
+       if (is_offchannel_skb)
+               iwl_scan_offchannel_skb_status(priv);
+
+       return 0;
+}
+
+/**
+ * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                  struct iwl_rx_cmd_buffer *rxb,
+                                  struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
+       struct iwl_ht_agg *agg;
+       struct sk_buff_head reclaimed_skbs;
+       struct ieee80211_tx_info *info;
+       struct ieee80211_hdr *hdr;
+       struct sk_buff *skb;
+       int sta_id;
+       int tid;
+       int freed;
+
+       /* "flow" corresponds to Tx queue */
+       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+       /* "ssn" is start of block-ack Tx window, corresponds to index
+        * (in Tx queue's circular buffer) of first TFD/frame in window */
+       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+       if (scd_flow >= priv->cfg->base_params->num_of_queues) {
+               IWL_ERR(priv,
+                       "BUG_ON scd_flow is bigger than number of queues\n");
+               return 0;
+       }
+
+       sta_id = ba_resp->sta_id;
+       tid = ba_resp->tid;
+       agg = &priv->tid_data[sta_id][tid].agg;
+
+       spin_lock(&priv->sta_lock);
+
+       if (unlikely(!agg->wait_for_ba)) {
+               if (unlikely(ba_resp->bitmap))
+                       IWL_ERR(priv, "Received BA when not expected\n");
+               spin_unlock(&priv->sta_lock);
+               return 0;
+       }
+
+       __skb_queue_head_init(&reclaimed_skbs);
+
+       /* Release all TFDs before the SSN, i.e. all TFDs in front of
+        * block-ack window (we assume that they've been successfully
+        * transmitted ... if not, it's too late anyway). */
+       if (iwl_reclaim(priv, sta_id, tid, scd_flow,
+                       ba_resp_scd_ssn, &reclaimed_skbs)) {
+               spin_unlock(&priv->sta_lock);
+               return 0;
+       }
+
+       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
+                          "sta_id = %d\n",
+                          agg->wait_for_ba,
+                          (u8 *) &ba_resp->sta_addr_lo32,
+                          ba_resp->sta_id);
+       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
+                          "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
+                          ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
+                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
+                          scd_flow, ba_resp_scd_ssn, ba_resp->txed,
+                          ba_resp->txed_2_done);
+
+       /* Mark that the expected block-ack response arrived */
+       agg->wait_for_ba = false;
+
+       /* Sanity check values reported by uCode */
+       if (ba_resp->txed_2_done > ba_resp->txed) {
+               IWL_DEBUG_TX_REPLY(priv,
+                       "bogus sent(%d) and ack(%d) count\n",
+                       ba_resp->txed, ba_resp->txed_2_done);
+               /*
+                * set txed_2_done = txed,
+                * so it won't impact rate scale
+                */
+               ba_resp->txed = ba_resp->txed_2_done;
+       }
+
+       priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
+
+       iwlagn_check_ratid_empty(priv, sta_id, tid);
+       freed = 0;
+
+       skb_queue_walk(&reclaimed_skbs, skb) {
+               hdr = (struct ieee80211_hdr *)skb->data;
+
+               if (ieee80211_is_data_qos(hdr->frame_control))
+                       freed++;
+               else
+                       WARN_ON_ONCE(1);
+
+               info = IEEE80211_SKB_CB(skb);
+               iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
+
+               if (freed == 1) {
+                       /* this is the first skb we deliver in this batch */
+                       /* put the rate scaling data there */
+                       info = IEEE80211_SKB_CB(skb);
+                       memset(&info->status, 0, sizeof(info->status));
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+                       info->flags |= IEEE80211_TX_STAT_AMPDU;
+                       info->status.ampdu_ack_len = ba_resp->txed_2_done;
+                       info->status.ampdu_len = ba_resp->txed;
+                       iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
+                                                   info);
+               }
+       }
+
+       spin_unlock(&priv->sta_lock);
+
+       while (!skb_queue_empty(&reclaimed_skbs)) {
+               skb = __skb_dequeue(&reclaimed_skbs);
+               ieee80211_tx_status(priv->hw, skb);
+       }
+
+       return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
new file mode 100644 (file)
index 0000000..b3a314b
--- /dev/null
@@ -0,0 +1,520 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * 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/init.h>
+
+#include "iwl-io.h"
+#include "iwl-agn-hw.h"
+#include "iwl-trans.h"
+#include "iwl-fh.h"
+#include "iwl-op-mode.h"
+
+#include "dev.h"
+#include "agn.h"
+#include "calib.h"
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static inline const struct fw_img *
+iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
+{
+       if (ucode_type >= IWL_UCODE_TYPE_MAX)
+               return NULL;
+
+       return &priv->fw->img[ucode_type];
+}
+
+/*
+ *  Calibration
+ */
+static int iwl_set_Xtal_calib(struct iwl_priv *priv)
+{
+       struct iwl_calib_xtal_freq_cmd cmd;
+       __le16 *xtal_calib = priv->eeprom_data->xtal_calib;
+
+       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
+       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
+       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
+{
+       struct iwl_calib_temperature_offset_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
+       cmd.radio_sensor_offset = priv->eeprom_data->raw_temperature;
+       if (!(cmd.radio_sensor_offset))
+               cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
+
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
+                       le16_to_cpu(cmd.radio_sensor_offset));
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
+{
+       struct iwl_calib_temperature_offset_v2_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
+       cmd.radio_sensor_offset_high = priv->eeprom_data->kelvin_temperature;
+       cmd.radio_sensor_offset_low = priv->eeprom_data->raw_temperature;
+       if (!cmd.radio_sensor_offset_low) {
+               IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
+               cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
+               cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
+       }
+       cmd.burntVoltageRef = priv->eeprom_data->calib_voltage;
+
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
+                       le16_to_cpu(cmd.radio_sensor_offset_high));
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
+                       le16_to_cpu(cmd.radio_sensor_offset_low));
+       IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
+                       le16_to_cpu(cmd.burntVoltageRef));
+
+       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
+}
+
+static int iwl_send_calib_cfg(struct iwl_priv *priv)
+{
+       struct iwl_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.flags =
+               IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
+
+       return iwl_dvm_send_cmd(priv, &cmd);
+}
+
+int iwl_init_alive_start(struct iwl_priv *priv)
+{
+       int ret;
+
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               /*
+                * Tell uCode we are ready to perform calibration
+                * need to perform this before any calibration
+                * no need to close the envlope since we are going
+                * to load the runtime uCode later.
+                */
+               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+                       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+               if (ret)
+                       return ret;
+
+       }
+
+       ret = iwl_send_calib_cfg(priv);
+       if (ret)
+               return ret;
+
+       /**
+        * temperature offset calibration is only needed for runtime ucode,
+        * so prepare the value now.
+        */
+       if (priv->cfg->need_temp_offset_calib) {
+               if (priv->cfg->temp_offset_v2)
+                       return iwl_set_temperature_offset_calib_v2(priv);
+               else
+                       return iwl_set_temperature_offset_calib(priv);
+       }
+
+       return 0;
+}
+
+static int iwl_send_wimax_coex(struct iwl_priv *priv)
+{
+       struct iwl_wimax_coex_cmd coex_cmd;
+
+       /* coexistence is disabled */
+       memset(&coex_cmd, 0, sizeof(coex_cmd));
+
+       return iwl_dvm_send_cmd_pdu(priv,
+                               COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
+                               sizeof(coex_cmd), &coex_cmd);
+}
+
+static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       0, 0, 0, 0, 0, 0, 0
+};
+
+void iwl_send_prio_tbl(struct iwl_priv *priv)
+{
+       struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
+
+       memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
+               sizeof(iwl_bt_prio_tbl));
+       if (iwl_dvm_send_cmd_pdu(priv,
+                               REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
+                               sizeof(prio_tbl_cmd), &prio_tbl_cmd))
+               IWL_ERR(priv, "failed to send BT prio tbl command\n");
+}
+
+int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+{
+       struct iwl_bt_coex_prot_env_cmd env_cmd;
+       int ret;
+
+       env_cmd.action = action;
+       env_cmd.type = type;
+       ret = iwl_dvm_send_cmd_pdu(priv,
+                              REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
+                              sizeof(env_cmd), &env_cmd);
+       if (ret)
+               IWL_ERR(priv, "failed to send BT env command\n");
+       return ret;
+}
+
+
+static int iwl_alive_notify(struct iwl_priv *priv)
+{
+       int ret;
+
+       iwl_trans_fw_alive(priv->trans);
+
+       priv->passive_no_rx = false;
+       priv->transport_queue_stop = 0;
+
+       ret = iwl_send_wimax_coex(priv);
+       if (ret)
+               return ret;
+
+       if (!priv->cfg->no_xtal_calib) {
+               ret = iwl_set_Xtal_calib(priv);
+               if (ret)
+                       return ret;
+       }
+
+       return iwl_send_calib_results(priv);
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_sec_sparse(struct iwl_priv *priv,
+                                 const struct fw_desc *fw_desc)
+{
+       __le32 *image = (__le32 *)fw_desc->v_addr;
+       u32 len = fw_desc->len;
+       u32 val;
+       u32 i;
+
+       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+
+       for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+               /* read data comes through single port, auto-incr addr */
+               /* NOTE: Use the debugless read so we don't flood kernel log
+                * if IWL_DL_IO is set */
+               iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
+                       i + fw_desc->offset);
+               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+               if (val != le32_to_cpu(*image))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static void iwl_print_mismatch_sec(struct iwl_priv *priv,
+                                   const struct fw_desc *fw_desc)
+{
+       __le32 *image = (__le32 *)fw_desc->v_addr;
+       u32 len = fw_desc->len;
+       u32 val;
+       u32 offs;
+       int errors = 0;
+
+       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+
+       iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
+                               fw_desc->offset);
+
+       for (offs = 0;
+            offs < len && errors < 20;
+            offs += sizeof(u32), image++) {
+               /* read data comes through single port, auto-incr addr */
+               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
+               if (val != le32_to_cpu(*image)) {
+                       IWL_ERR(priv, "uCode INST section at "
+                               "offset 0x%x, is 0x%x, s/b 0x%x\n",
+                               offs, val, le32_to_cpu(*image));
+                       errors++;
+               }
+       }
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv,
+                           enum iwl_ucode_type ucode_type)
+{
+       const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
+
+       if (!img) {
+               IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
+               return -EINVAL;
+       }
+
+       if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
+               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
+               return 0;
+       }
+
+       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+
+       iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
+       return -EIO;
+}
+
+struct iwl_alive_data {
+       bool valid;
+       u8 subtype;
+};
+
+static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
+                        struct iwl_rx_packet *pkt, void *data)
+{
+       struct iwl_priv *priv =
+               container_of(notif_wait, struct iwl_priv, notif_wait);
+       struct iwl_alive_data *alive_data = data;
+       struct iwl_alive_resp *palive;
+
+       palive = (void *)pkt->data;
+
+       IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
+                      "0x%01X 0x%01X\n",
+                      palive->is_valid, palive->ver_type,
+                      palive->ver_subtype);
+
+       priv->device_pointers.error_event_table =
+               le32_to_cpu(palive->error_event_table_ptr);
+       priv->device_pointers.log_event_table =
+               le32_to_cpu(palive->log_event_table_ptr);
+
+       alive_data->subtype = palive->ver_subtype;
+       alive_data->valid = palive->is_valid == UCODE_VALID_OK;
+
+       return true;
+}
+
+#define UCODE_ALIVE_TIMEOUT    HZ
+#define UCODE_CALIB_TIMEOUT    (2*HZ)
+
+int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
+                                enum iwl_ucode_type ucode_type)
+{
+       struct iwl_notification_wait alive_wait;
+       struct iwl_alive_data alive_data;
+       const struct fw_img *fw;
+       int ret;
+       enum iwl_ucode_type old_type;
+       static const u8 alive_cmd[] = { REPLY_ALIVE };
+
+       old_type = priv->cur_ucode;
+       priv->cur_ucode = ucode_type;
+       fw = iwl_get_ucode_image(priv, ucode_type);
+
+       priv->ucode_loaded = false;
+
+       if (!fw)
+               return -EINVAL;
+
+       iwl_init_notification_wait(&priv->notif_wait, &alive_wait,
+                                  alive_cmd, ARRAY_SIZE(alive_cmd),
+                                  iwl_alive_fn, &alive_data);
+
+       ret = iwl_trans_start_fw(priv->trans, fw);
+       if (ret) {
+               priv->cur_ucode = old_type;
+               iwl_remove_notification(&priv->notif_wait, &alive_wait);
+               return ret;
+       }
+
+       /*
+        * Some things may run in the background now, but we
+        * just wait for the ALIVE notification here.
+        */
+       ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
+                                       UCODE_ALIVE_TIMEOUT);
+       if (ret) {
+               priv->cur_ucode = old_type;
+               return ret;
+       }
+
+       if (!alive_data.valid) {
+               IWL_ERR(priv, "Loaded ucode is not valid!\n");
+               priv->cur_ucode = old_type;
+               return -EIO;
+       }
+
+       /*
+        * This step takes a long time (60-80ms!!) and
+        * WoWLAN image should be loaded quickly, so
+        * skip it for WoWLAN.
+        */
+       if (ucode_type != IWL_UCODE_WOWLAN) {
+               ret = iwl_verify_ucode(priv, ucode_type);
+               if (ret) {
+                       priv->cur_ucode = old_type;
+                       return ret;
+               }
+
+               /* delay a bit to give rfkill time to run */
+               msleep(5);
+       }
+
+       ret = iwl_alive_notify(priv);
+       if (ret) {
+               IWL_WARN(priv,
+                       "Could not complete ALIVE transition: %d\n", ret);
+               priv->cur_ucode = old_type;
+               return ret;
+       }
+
+       priv->ucode_loaded = true;
+
+       return 0;
+}
+
+static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
+                             struct iwl_rx_packet *pkt, void *data)
+{
+       struct iwl_priv *priv = data;
+       struct iwl_calib_hdr *hdr;
+       int len;
+
+       if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
+               WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
+               return true;
+       }
+
+       hdr = (struct iwl_calib_hdr *)pkt->data;
+       len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+       /* reduce the size by the length field itself */
+       len -= sizeof(__le32);
+
+       if (iwl_calib_set(priv, hdr, len))
+               IWL_ERR(priv, "Failed to record calibration data %d\n",
+                       hdr->op_code);
+
+       return false;
+}
+
+int iwl_run_init_ucode(struct iwl_priv *priv)
+{
+       struct iwl_notification_wait calib_wait;
+       static const u8 calib_complete[] = {
+               CALIBRATION_RES_NOTIFICATION,
+               CALIBRATION_COMPLETE_NOTIFICATION
+       };
+       int ret;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /* No init ucode required? Curious, but maybe ok */
+       if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
+               return 0;
+
+       if (priv->init_ucode_run)
+               return 0;
+
+       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
+                                  calib_complete, ARRAY_SIZE(calib_complete),
+                                  iwlagn_wait_calib, priv);
+
+       /* Will also start the device */
+       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
+       if (ret)
+               goto error;
+
+       ret = iwl_init_alive_start(priv);
+       if (ret)
+               goto error;
+
+       /*
+        * Some things may run in the background now, but we
+        * just wait for the calibration complete notification.
+        */
+       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
+                                       UCODE_CALIB_TIMEOUT);
+       if (!ret)
+               priv->init_ucode_run = true;
+
+       goto out;
+
+ error:
+       iwl_remove_notification(&priv->notif_wait, &calib_wait);
+ out:
+       /* Whatever happened, stop the device */
+       iwl_trans_stop_device(priv->trans);
+       priv->ucode_loaded = false;
+
+       return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
deleted file mode 100644 (file)
index 2629a66..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-csr.h"
-#include "iwl-agn-hw.h"
-
-/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 5
-#define IWL100_UCODE_API_MAX 5
-
-/* Oldest version we won't warn about */
-#define IWL1000_UCODE_API_OK 5
-#define IWL100_UCODE_API_OK 5
-
-/* Lowest firmware API version supported */
-#define IWL1000_UCODE_API_MIN 1
-#define IWL100_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_1000_TX_POWER_VERSION   (4)
-#define EEPROM_1000_EEPROM_VERSION     (0x15C)
-
-#define IWL1000_FW_PRE "iwlwifi-1000-"
-#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL100_FW_PRE "iwlwifi-100-"
-#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
-
-
-static const struct iwl_base_params iwl1000_base_params = {
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .max_ll_items = OTP_MAX_LL_ITEMS_1000,
-       .shadow_ram_support = false,
-       .led_compensation = 51,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_WATCHHDOG_DISABLED,
-       .max_event_log_size = 128,
-};
-
-static const struct iwl_ht_params iwl1000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-#define IWL_DEVICE_1000                                                \
-       .fw_name_pre = IWL1000_FW_PRE,                          \
-       .ucode_api_max = IWL1000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL1000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL1000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_1000,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
-       .base_params = &iwl1000_base_params,                    \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl1000_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
-       IWL_DEVICE_1000,
-       .ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl1000_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
-       IWL_DEVICE_1000,
-};
-
-#define IWL_DEVICE_100                                         \
-       .fw_name_pre = IWL100_FW_PRE,                           \
-       .ucode_api_max = IWL100_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL100_UCODE_API_OK,                    \
-       .ucode_api_min = IWL100_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_100,                 \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
-       .base_params = &iwl1000_base_params,                    \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl100_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
-       IWL_DEVICE_100,
-       .ht_params = &iwl1000_ht_params,
-};
-
-const struct iwl_cfg iwl100_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
-       IWL_DEVICE_100,
-};
-
-MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
deleted file mode 100644 (file)
index 8133105..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL2030_UCODE_API_MAX 6
-#define IWL2000_UCODE_API_MAX 6
-#define IWL105_UCODE_API_MAX 6
-#define IWL135_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL2030_UCODE_API_OK 6
-#define IWL2000_UCODE_API_OK 6
-#define IWL105_UCODE_API_OK 6
-#define IWL135_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL2030_UCODE_API_MIN 5
-#define IWL2000_UCODE_API_MIN 5
-#define IWL105_UCODE_API_MIN 5
-#define IWL135_UCODE_API_MIN 5
-
-/* EEPROM version */
-#define EEPROM_2000_TX_POWER_VERSION   (6)
-#define EEPROM_2000_EEPROM_VERSION     (0x805)
-
-
-#define IWL2030_FW_PRE "iwlwifi-2030-"
-#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
-
-#define IWL2000_FW_PRE "iwlwifi-2000-"
-#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL105_FW_PRE "iwlwifi-105-"
-#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
-
-#define IWL135_FW_PRE "iwlwifi-135-"
-#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl2000_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-       .hd_v2 = true,
-};
-
-
-static const struct iwl_base_params iwl2030_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
-       .shadow_ram_support = true,
-       .led_compensation = 57,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_LONG_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-       .hd_v2 = true,
-};
-
-static const struct iwl_ht_params iwl2000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-static const struct iwl_bt_params iwl2030_bt_params = {
-       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-       .advanced_bt_coexist = true,
-       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
-       .bt_sco_disable = true,
-       .bt_session_2 = true,
-};
-
-#define IWL_DEVICE_2000                                                \
-       .fw_name_pre = IWL2000_FW_PRE,                          \
-       .ucode_api_max = IWL2000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL2000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL2000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_2000,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
-       .base_params = &iwl2000_base_params,                    \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl2000_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
-       IWL_DEVICE_2000,
-       .ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl2000_2bgn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
-       IWL_DEVICE_2000,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_2030                                                \
-       .fw_name_pre = IWL2030_FW_PRE,                          \
-       .ucode_api_max = IWL2030_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL2030_UCODE_API_OK,                   \
-       .ucode_api_min = IWL2030_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_2030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
-       .base_params = &iwl2030_base_params,                    \
-       .bt_params = &iwl2030_bt_params,                        \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true
-
-const struct iwl_cfg iwl2030_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
-       IWL_DEVICE_2030,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_105                                         \
-       .fw_name_pre = IWL105_FW_PRE,                           \
-       .ucode_api_max = IWL105_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL105_UCODE_API_OK,                    \
-       .ucode_api_min = IWL105_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_105,                 \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
-       .base_params = &iwl2000_base_params,                    \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true,                                         \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl105_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
-       IWL_DEVICE_105,
-       .ht_params = &iwl2000_ht_params,
-};
-
-const struct iwl_cfg iwl105_bgn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
-       IWL_DEVICE_105,
-       .ht_params = &iwl2000_ht_params,
-};
-
-#define IWL_DEVICE_135                                         \
-       .fw_name_pre = IWL135_FW_PRE,                           \
-       .ucode_api_max = IWL135_UCODE_API_MAX,                  \
-       .ucode_api_ok = IWL135_UCODE_API_OK,                    \
-       .ucode_api_min = IWL135_UCODE_API_MIN,                  \
-       .device_family = IWL_DEVICE_FAMILY_135,                 \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
-       .base_params = &iwl2030_base_params,                    \
-       .bt_params = &iwl2030_bt_params,                        \
-       .need_temp_offset_calib = true,                         \
-       .temp_offset_v2 = true,                                 \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true,                                         \
-       .rx_with_siso_diversity = true
-
-const struct iwl_cfg iwl135_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
-       IWL_DEVICE_135,
-       .ht_params = &iwl2000_ht_params,
-};
-
-MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
-MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
-MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
deleted file mode 100644 (file)
index 8e26bc8..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 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/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-csr.h"
-
-/* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 5
-#define IWL5150_UCODE_API_MAX 2
-
-/* Oldest version we won't warn about */
-#define IWL5000_UCODE_API_OK 5
-#define IWL5150_UCODE_API_OK 2
-
-/* Lowest firmware API version supported */
-#define IWL5000_UCODE_API_MIN 1
-#define IWL5150_UCODE_API_MIN 1
-
-/* EEPROM versions */
-#define EEPROM_5000_TX_POWER_VERSION   (4)
-#define EEPROM_5000_EEPROM_VERSION     (0x11A)
-#define EEPROM_5050_TX_POWER_VERSION   (4)
-#define EEPROM_5050_EEPROM_VERSION     (0x21E)
-
-#define IWL5000_FW_PRE "iwlwifi-5000-"
-#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL5150_FW_PRE "iwlwifi-5150-"
-#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl5000_base_params = {
-       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
-       .led_compensation = 51,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_WATCHHDOG_DISABLED,
-       .max_event_log_size = 512,
-       .no_idle_support = true,
-};
-
-static const struct iwl_ht_params iwl5000_ht_params = {
-       .ht_greenfield_support = true,
-};
-
-#define IWL_DEVICE_5000                                                \
-       .fw_name_pre = IWL5000_FW_PRE,                          \
-       .ucode_api_max = IWL5000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL5000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL5000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_5000,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,       \
-       .base_params = &iwl5000_base_params,                    \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl5300_agn_cfg = {
-       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
-       IWL_DEVICE_5000,
-       /* at least EEPROM 0x11A has wrong info */
-       .valid_tx_ant = ANT_ABC,        /* .cfg overwrite */
-       .valid_rx_ant = ANT_ABC,        /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_bgn_cfg = {
-       .name = "Intel(R) WiFi Link 5100 BGN",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5100_abg_cfg = {
-       .name = "Intel(R) WiFi Link 5100 ABG",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-};
-
-const struct iwl_cfg iwl5100_agn_cfg = {
-       .name = "Intel(R) WiFi Link 5100 AGN",
-       IWL_DEVICE_5000,
-       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
-       .ht_params = &iwl5000_ht_params,
-};
-
-const struct iwl_cfg iwl5350_agn_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
-       .fw_name_pre = IWL5000_FW_PRE,
-       .ucode_api_max = IWL5000_UCODE_API_MAX,
-       .ucode_api_ok = IWL5000_UCODE_API_OK,
-       .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .device_family = IWL_DEVICE_FAMILY_5000,
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,
-       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .base_params = &iwl5000_base_params,
-       .ht_params = &iwl5000_ht_params,
-       .led_mode = IWL_LED_BLINK,
-       .internal_wimax_coex = true,
-};
-
-#define IWL_DEVICE_5150                                                \
-       .fw_name_pre = IWL5150_FW_PRE,                          \
-       .ucode_api_max = IWL5150_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL5150_UCODE_API_OK,                   \
-       .ucode_api_min = IWL5150_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_5150,                \
-       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
-       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
-       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,       \
-       .base_params = &iwl5000_base_params,                    \
-       .no_xtal_calib = true,                                  \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl5150_agn_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
-       IWL_DEVICE_5150,
-       .ht_params = &iwl5000_ht_params,
-
-};
-
-const struct iwl_cfg iwl5150_abg_cfg = {
-       .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
-       IWL_DEVICE_5150,
-};
-
-MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
deleted file mode 100644 (file)
index e5e8ada..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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/module.h>
-#include <linux/stringify.h>
-#include "iwl-config.h"
-#include "iwl-cfg.h"
-#include "iwl-agn-hw.h"
-#include "iwl-commands.h" /* needed for BT for now */
-
-/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 6
-#define IWL6050_UCODE_API_MAX 5
-#define IWL6000G2_UCODE_API_MAX 6
-#define IWL6035_UCODE_API_MAX 6
-
-/* Oldest version we won't warn about */
-#define IWL6000_UCODE_API_OK 4
-#define IWL6000G2_UCODE_API_OK 5
-#define IWL6050_UCODE_API_OK 5
-#define IWL6000G2B_UCODE_API_OK 6
-#define IWL6035_UCODE_API_OK 6
-
-/* Lowest firmware API version supported */
-#define IWL6000_UCODE_API_MIN 4
-#define IWL6050_UCODE_API_MIN 4
-#define IWL6000G2_UCODE_API_MIN 5
-#define IWL6035_UCODE_API_MIN 6
-
-/* EEPROM versions */
-#define EEPROM_6000_TX_POWER_VERSION   (4)
-#define EEPROM_6000_EEPROM_VERSION     (0x423)
-#define EEPROM_6050_TX_POWER_VERSION   (4)
-#define EEPROM_6050_EEPROM_VERSION     (0x532)
-#define EEPROM_6150_TX_POWER_VERSION   (6)
-#define EEPROM_6150_EEPROM_VERSION     (0x553)
-#define EEPROM_6005_TX_POWER_VERSION   (6)
-#define EEPROM_6005_EEPROM_VERSION     (0x709)
-#define EEPROM_6030_TX_POWER_VERSION   (6)
-#define EEPROM_6030_EEPROM_VERSION     (0x709)
-#define EEPROM_6035_TX_POWER_VERSION   (6)
-#define EEPROM_6035_EEPROM_VERSION     (0x753)
-
-#define IWL6000_FW_PRE "iwlwifi-6000-"
-#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6050_FW_PRE "iwlwifi-6050-"
-#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
-#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
-
-#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
-#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
-
-static const struct iwl_base_params iwl6000_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6050_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
-       .shadow_ram_support = true,
-       .led_compensation = 51,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1500,
-       .wd_timeout = IWL_DEF_WD_TIMEOUT,
-       .max_event_log_size = 1024,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_base_params iwl6000_g2_base_params = {
-       .eeprom_size = OTP_LOW_IMAGE_SIZE,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
-       .pll_cfg_val = 0,
-       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
-       .shadow_ram_support = true,
-       .led_compensation = 57,
-       .adv_thermal_throttle = true,
-       .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
-       .chain_noise_scale = 1000,
-       .wd_timeout = IWL_LONG_WD_TIMEOUT,
-       .max_event_log_size = 512,
-       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
-};
-
-static const struct iwl_ht_params iwl6000_ht_params = {
-       .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
-};
-
-static const struct iwl_bt_params iwl6000_bt_params = {
-       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
-       .advanced_bt_coexist = true,
-       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
-       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
-       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
-       .bt_sco_disable = true,
-};
-
-#define IWL_DEVICE_6005                                                \
-       .fw_name_pre = IWL6005_FW_PRE,                          \
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
-       .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
-       .device_family = IWL_DEVICE_FAMILY_6005,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_6005_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,       \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE
-
-const struct iwl_cfg iwl6005_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
-       IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
-       IWL_DEVICE_6005,
-};
-
-const struct iwl_cfg iwl6005_2agn_sff_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_d_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
-       IWL_DEVICE_6005,
-       .ht_params = &iwl6000_ht_params,
-};
-
-#define IWL_DEVICE_6030                                                \
-       .fw_name_pre = IWL6030_FW_PRE,                          \
-       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
-       .ucode_api_ok = IWL6000G2B_UCODE_API_OK,                \
-       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
-       .device_family = IWL_DEVICE_FAMILY_6030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_6030_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,       \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .bt_params = &iwl6000_bt_params,                        \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true                                          \
-
-const struct iwl_cfg iwl6030_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
-       IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl6030_2bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6030_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
-       IWL_DEVICE_6030,
-};
-
-#define IWL_DEVICE_6035                                                \
-       .fw_name_pre = IWL6030_FW_PRE,                          \
-       .ucode_api_max = IWL6035_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL6035_UCODE_API_OK,                   \
-       .ucode_api_min = IWL6035_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6030,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_6030_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,       \
-       .base_params = &iwl6000_g2_base_params,                 \
-       .bt_params = &iwl6000_bt_params,                        \
-       .need_temp_offset_calib = true,                         \
-       .led_mode = IWL_LED_RF_STATE,                           \
-       .adv_pm = true
-
-const struct iwl_cfg iwl6035_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
-       IWL_DEVICE_6035,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl1030_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
-       IWL_DEVICE_6030,
-};
-
-const struct iwl_cfg iwl130_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
-       IWL_DEVICE_6030,
-       .ht_params = &iwl6000_ht_params,
-       .rx_with_siso_diversity = true,
-};
-
-const struct iwl_cfg iwl130_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
-       IWL_DEVICE_6030,
-       .rx_with_siso_diversity = true,
-};
-
-/*
- * "i": Internal configuration, use internal Power Amplifier
- */
-#define IWL_DEVICE_6000i                                       \
-       .fw_name_pre = IWL6000_FW_PRE,                          \
-       .ucode_api_max = IWL6000_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL6000_UCODE_API_OK,                   \
-       .ucode_api_min = IWL6000_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6000i,               \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */    \
-       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */    \
-       .eeprom_ver = EEPROM_6000_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,       \
-       .base_params = &iwl6000_base_params,                    \
-       .led_mode = IWL_LED_BLINK
-
-const struct iwl_cfg iwl6000i_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
-       IWL_DEVICE_6000i,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6000i_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
-       IWL_DEVICE_6000i,
-};
-
-const struct iwl_cfg iwl6000i_2bg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
-       IWL_DEVICE_6000i,
-};
-
-#define IWL_DEVICE_6050                                                \
-       .fw_name_pre = IWL6050_FW_PRE,                          \
-       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
-       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6050,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
-       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
-       .eeprom_ver = EEPROM_6050_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,       \
-       .base_params = &iwl6050_base_params,                    \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl6050_2agn_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
-       IWL_DEVICE_6050,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6050_2abg_cfg = {
-       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
-       IWL_DEVICE_6050,
-};
-
-#define IWL_DEVICE_6150                                                \
-       .fw_name_pre = IWL6050_FW_PRE,                          \
-       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
-       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
-       .device_family = IWL_DEVICE_FAMILY_6150,                \
-       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
-       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
-       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,               \
-       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,       \
-       .base_params = &iwl6050_base_params,                    \
-       .led_mode = IWL_LED_BLINK,                              \
-       .internal_wimax_coex = true
-
-const struct iwl_cfg iwl6150_bgn_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
-       IWL_DEVICE_6150,
-       .ht_params = &iwl6000_ht_params,
-};
-
-const struct iwl_cfg iwl6150_bg_cfg = {
-       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
-       IWL_DEVICE_6150,
-};
-
-const struct iwl_cfg iwl6000_3agn_cfg = {
-       .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
-       .fw_name_pre = IWL6000_FW_PRE,
-       .ucode_api_max = IWL6000_UCODE_API_MAX,
-       .ucode_api_ok = IWL6000_UCODE_API_OK,
-       .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .device_family = IWL_DEVICE_FAMILY_6000,
-       .max_inst_size = IWL60_RTC_INST_SIZE,
-       .max_data_size = IWL60_RTC_DATA_SIZE,
-       .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
-       .base_params = &iwl6000_base_params,
-       .ht_params = &iwl6000_ht_params,
-       .led_mode = IWL_LED_BLINK,
-};
-
-MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
-MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
deleted file mode 100644 (file)
index 95f27f1..0000000
+++ /dev/null
@@ -1,1112 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#include <linux/slab.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-agn.h"
-
-/*****************************************************************************
- * INIT calibrations framework
- *****************************************************************************/
-
-/* Opaque calibration results */
-struct iwl_calib_result {
-       struct list_head list;
-       size_t cmd_len;
-       struct iwl_calib_hdr hdr;
-       /* data follows */
-};
-
-struct statistics_general_data {
-       u32 beacon_silence_rssi_a;
-       u32 beacon_silence_rssi_b;
-       u32 beacon_silence_rssi_c;
-       u32 beacon_energy_a;
-       u32 beacon_energy_b;
-       u32 beacon_energy_c;
-};
-
-int iwl_send_calib_results(struct iwl_priv *priv)
-{
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_PHY_CALIBRATION_CMD,
-               .flags = CMD_SYNC,
-       };
-       struct iwl_calib_result *res;
-
-       list_for_each_entry(res, &priv->calib_results, list) {
-               int ret;
-
-               hcmd.len[0] = res->cmd_len;
-               hcmd.data[0] = &res->hdr;
-               hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-               ret = iwl_dvm_send_cmd(priv, &hcmd);
-               if (ret) {
-                       IWL_ERR(priv, "Error %d on calib cmd %d\n",
-                               ret, res->hdr.op_code);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-int iwl_calib_set(struct iwl_priv *priv,
-                 const struct iwl_calib_hdr *cmd, int len)
-{
-       struct iwl_calib_result *res, *tmp;
-
-       res = kmalloc(sizeof(*res) + len - sizeof(struct iwl_calib_hdr),
-                     GFP_ATOMIC);
-       if (!res)
-               return -ENOMEM;
-       memcpy(&res->hdr, cmd, len);
-       res->cmd_len = len;
-
-       list_for_each_entry(tmp, &priv->calib_results, list) {
-               if (tmp->hdr.op_code == res->hdr.op_code) {
-                       list_replace(&tmp->list, &res->list);
-                       kfree(tmp);
-                       return 0;
-               }
-       }
-
-       /* wasn't in list already */
-       list_add_tail(&res->list, &priv->calib_results);
-
-       return 0;
-}
-
-void iwl_calib_free_results(struct iwl_priv *priv)
-{
-       struct iwl_calib_result *res, *tmp;
-
-       list_for_each_entry_safe(res, tmp, &priv->calib_results, list) {
-               list_del(&res->list);
-               kfree(res);
-       }
-}
-
-/*****************************************************************************
- * RUNTIME calibrations framework
- *****************************************************************************/
-
-/* "false alarms" are signals that our DSP tries to lock onto,
- *   but then determines that they are either noise, or transmissions
- *   from a distant wireless network (also "noise", really) that get
- *   "stepped on" by stronger transmissions within our own network.
- * This algorithm attempts to set a sensitivity level that is high
- *   enough to receive all of our own network traffic, but not so
- *   high that our DSP gets too busy trying to lock onto non-network
- *   activity/noise. */
-static int iwl_sens_energy_cck(struct iwl_priv *priv,
-                                  u32 norm_fa,
-                                  u32 rx_enable_time,
-                                  struct statistics_general_data *rx_info)
-{
-       u32 max_nrg_cck = 0;
-       int i = 0;
-       u8 max_silence_rssi = 0;
-       u32 silence_ref = 0;
-       u8 silence_rssi_a = 0;
-       u8 silence_rssi_b = 0;
-       u8 silence_rssi_c = 0;
-       u32 val;
-
-       /* "false_alarms" values below are cross-multiplications to assess the
-        *   numbers of false alarms within the measured period of actual Rx
-        *   (Rx is off when we're txing), vs the min/max expected false alarms
-        *   (some should be expected if rx is sensitive enough) in a
-        *   hypothetical listening period of 200 time units (TU), 204.8 msec:
-        *
-        * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
-        *
-        * */
-       u32 false_alarms = norm_fa * 200 * 1024;
-       u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
-       u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
-       struct iwl_sensitivity_data *data = NULL;
-       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-       data = &(priv->sensitivity_data);
-
-       data->nrg_auto_corr_silence_diff = 0;
-
-       /* Find max silence rssi among all 3 receivers.
-        * This is background noise, which may include transmissions from other
-        *    networks, measured during silence before our network's beacon */
-       silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
-                           ALL_BAND_FILTER) >> 8);
-       silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
-                           ALL_BAND_FILTER) >> 8);
-       silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
-                           ALL_BAND_FILTER) >> 8);
-
-       val = max(silence_rssi_b, silence_rssi_c);
-       max_silence_rssi = max(silence_rssi_a, (u8) val);
-
-       /* Store silence rssi in 20-beacon history table */
-       data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
-       data->nrg_silence_idx++;
-       if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
-               data->nrg_silence_idx = 0;
-
-       /* Find max silence rssi across 20 beacon history */
-       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
-               val = data->nrg_silence_rssi[i];
-               silence_ref = max(silence_ref, val);
-       }
-       IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
-                       silence_rssi_a, silence_rssi_b, silence_rssi_c,
-                       silence_ref);
-
-       /* Find max rx energy (min value!) among all 3 receivers,
-        *   measured during beacon frame.
-        * Save it in 10-beacon history table. */
-       i = data->nrg_energy_idx;
-       val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
-       data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
-
-       data->nrg_energy_idx++;
-       if (data->nrg_energy_idx >= 10)
-               data->nrg_energy_idx = 0;
-
-       /* Find min rx energy (max value) across 10 beacon history.
-        * This is the minimum signal level that we want to receive well.
-        * Add backoff (margin so we don't miss slightly lower energy frames).
-        * This establishes an upper bound (min value) for energy threshold. */
-       max_nrg_cck = data->nrg_value[0];
-       for (i = 1; i < 10; i++)
-               max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
-       max_nrg_cck += 6;
-
-       IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
-                       rx_info->beacon_energy_a, rx_info->beacon_energy_b,
-                       rx_info->beacon_energy_c, max_nrg_cck - 6);
-
-       /* Count number of consecutive beacons with fewer-than-desired
-        *   false alarms. */
-       if (false_alarms < min_false_alarms)
-               data->num_in_cck_no_fa++;
-       else
-               data->num_in_cck_no_fa = 0;
-       IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
-                       data->num_in_cck_no_fa);
-
-       /* If we got too many false alarms this time, reduce sensitivity */
-       if ((false_alarms > max_false_alarms) &&
-               (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
-               IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
-                    false_alarms, max_false_alarms);
-               IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
-               data->nrg_curr_state = IWL_FA_TOO_MANY;
-               /* Store for "fewer than desired" on later beacon */
-               data->nrg_silence_ref = silence_ref;
-
-               /* increase energy threshold (reduce nrg value)
-                *   to decrease sensitivity */
-               data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
-       /* Else if we got fewer than desired, increase sensitivity */
-       } else if (false_alarms < min_false_alarms) {
-               data->nrg_curr_state = IWL_FA_TOO_FEW;
-
-               /* Compare silence level with silence level for most recent
-                *   healthy number or too many false alarms */
-               data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
-                                                  (s32)silence_ref;
-
-               IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u, silence diff %d\n",
-                        false_alarms, min_false_alarms,
-                        data->nrg_auto_corr_silence_diff);
-
-               /* Increase value to increase sensitivity, but only if:
-                * 1a) previous beacon did *not* have *too many* false alarms
-                * 1b) AND there's a significant difference in Rx levels
-                *      from a previous beacon with too many, or healthy # FAs
-                * OR 2) We've seen a lot of beacons (100) with too few
-                *       false alarms */
-               if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
-                       ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
-                       (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
-
-                       IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n");
-                       /* Increase nrg value to increase sensitivity */
-                       val = data->nrg_th_cck + NRG_STEP_CCK;
-                       data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
-               } else {
-                       IWL_DEBUG_CALIB(priv, "... but not changing sensitivity\n");
-               }
-
-       /* Else we got a healthy number of false alarms, keep status quo */
-       } else {
-               IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
-               data->nrg_curr_state = IWL_FA_GOOD_RANGE;
-
-               /* Store for use in "fewer than desired" with later beacon */
-               data->nrg_silence_ref = silence_ref;
-
-               /* If previous beacon had too many false alarms,
-                *   give it some extra margin by reducing sensitivity again
-                *   (but don't go below measured energy of desired Rx) */
-               if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
-                       IWL_DEBUG_CALIB(priv, "... increasing margin\n");
-                       if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
-                               data->nrg_th_cck -= NRG_MARGIN;
-                       else
-                               data->nrg_th_cck = max_nrg_cck;
-               }
-       }
-
-       /* Make sure the energy threshold does not go above the measured
-        * energy of the desired Rx signals (reduced by backoff margin),
-        * or else we might start missing Rx frames.
-        * Lower value is higher energy, so we use max()!
-        */
-       data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
-       IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
-
-       data->nrg_prev_state = data->nrg_curr_state;
-
-       /* Auto-correlation CCK algorithm */
-       if (false_alarms > min_false_alarms) {
-
-               /* increase auto_corr values to decrease sensitivity
-                * so the DSP won't be disturbed by the noise
-                */
-               if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
-                       data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
-               else {
-                       val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
-                       data->auto_corr_cck =
-                               min((u32)ranges->auto_corr_max_cck, val);
-               }
-               val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
-               data->auto_corr_cck_mrc =
-                       min((u32)ranges->auto_corr_max_cck_mrc, val);
-       } else if ((false_alarms < min_false_alarms) &&
-          ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
-          (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
-
-               /* Decrease auto_corr values to increase sensitivity */
-               val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
-               data->auto_corr_cck =
-                       max((u32)ranges->auto_corr_min_cck, val);
-               val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
-               data->auto_corr_cck_mrc =
-                       max((u32)ranges->auto_corr_min_cck_mrc, val);
-       }
-
-       return 0;
-}
-
-
-static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
-                                      u32 norm_fa,
-                                      u32 rx_enable_time)
-{
-       u32 val;
-       u32 false_alarms = norm_fa * 200 * 1024;
-       u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
-       u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
-       struct iwl_sensitivity_data *data = NULL;
-       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-       data = &(priv->sensitivity_data);
-
-       /* If we got too many false alarms this time, reduce sensitivity */
-       if (false_alarms > max_false_alarms) {
-
-               IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u)\n",
-                            false_alarms, max_false_alarms);
-
-               val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm =
-                       min((u32)ranges->auto_corr_max_ofdm, val);
-
-               val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc =
-                       min((u32)ranges->auto_corr_max_ofdm_mrc, val);
-
-               val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_x1 =
-                       min((u32)ranges->auto_corr_max_ofdm_x1, val);
-
-               val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc_x1 =
-                       min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
-       }
-
-       /* Else if we got fewer than desired, increase sensitivity */
-       else if (false_alarms < min_false_alarms) {
-
-               IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u\n",
-                            false_alarms, min_false_alarms);
-
-               val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm =
-                       max((u32)ranges->auto_corr_min_ofdm, val);
-
-               val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc =
-                       max((u32)ranges->auto_corr_min_ofdm_mrc, val);
-
-               val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_x1 =
-                       max((u32)ranges->auto_corr_min_ofdm_x1, val);
-
-               val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc_x1 =
-                       max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
-       } else {
-               IWL_DEBUG_CALIB(priv, "min FA %u < norm FA %u < max FA %u OK\n",
-                        min_false_alarms, false_alarms, max_false_alarms);
-       }
-       return 0;
-}
-
-static void iwl_prepare_legacy_sensitivity_tbl(struct iwl_priv *priv,
-                               struct iwl_sensitivity_data *data,
-                               __le16 *tbl)
-{
-       tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm);
-       tbl[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
-       tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_x1);
-       tbl[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
-
-       tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_cck);
-       tbl[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_cck_mrc);
-
-       tbl[HD_MIN_ENERGY_CCK_DET_INDEX] =
-                               cpu_to_le16((u16)data->nrg_th_cck);
-       tbl[HD_MIN_ENERGY_OFDM_DET_INDEX] =
-                               cpu_to_le16((u16)data->nrg_th_ofdm);
-
-       tbl[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16(data->barker_corr_th_min);
-       tbl[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16(data->barker_corr_th_min_mrc);
-       tbl[HD_OFDM_ENERGY_TH_IN_INDEX] =
-                               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,
-                       data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
-                       data->nrg_th_ofdm);
-
-       IWL_DEBUG_CALIB(priv, "cck: ac %u mrc %u thresh %u\n",
-                       data->auto_corr_cck, data->auto_corr_cck_mrc,
-                       data->nrg_th_cck);
-}
-
-/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl_sensitivity_write(struct iwl_priv *priv)
-{
-       struct iwl_sensitivity_cmd cmd;
-       struct iwl_sensitivity_data *data = NULL;
-       struct iwl_host_cmd cmd_out = {
-               .id = SENSITIVITY_CMD,
-               .len = { sizeof(struct iwl_sensitivity_cmd), },
-               .flags = CMD_ASYNC,
-               .data = { &cmd, },
-       };
-
-       data = &(priv->sensitivity_data);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.table[0]);
-
-       /* Update uCode's "work" table, and copy it to DSP */
-       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
-
-       /* Don't send command to uCode if nothing has changed */
-       if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
-                   sizeof(u16)*HD_TABLE_SIZE)) {
-               IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
-               return 0;
-       }
-
-       /* Copy table for comparison next time */
-       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
-              sizeof(u16)*HD_TABLE_SIZE);
-
-       return iwl_dvm_send_cmd(priv, &cmd_out);
-}
-
-/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
-{
-       struct iwl_enhance_sensitivity_cmd cmd;
-       struct iwl_sensitivity_data *data = NULL;
-       struct iwl_host_cmd cmd_out = {
-               .id = SENSITIVITY_CMD,
-               .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
-               .flags = CMD_ASYNC,
-               .data = { &cmd, },
-       };
-
-       data = &(priv->sensitivity_data);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]);
-
-       if (priv->cfg->base_params->hd_v2) {
-               cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
-                       HD_INA_NON_SQUARE_DET_OFDM_DATA_V2;
-               cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
-                       HD_INA_NON_SQUARE_DET_CCK_DATA_V2;
-               cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
-                       HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2;
-       } else {
-               cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] =
-                       HD_INA_NON_SQUARE_DET_OFDM_DATA_V1;
-               cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] =
-                       HD_INA_NON_SQUARE_DET_CCK_DATA_V1;
-               cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] =
-                       HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1;
-               cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] =
-                       HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1;
-               cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] =
-                       HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1;
-       }
-
-       /* Update uCode's "work" table, and copy it to DSP */
-       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
-
-       /* Don't send command to uCode if nothing has changed */
-       if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]),
-                   sizeof(u16)*HD_TABLE_SIZE) &&
-           !memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
-                   &(priv->enhance_sensitivity_tbl[0]),
-                   sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
-               IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n");
-               return 0;
-       }
-
-       /* Copy table for comparison next time */
-       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]),
-              sizeof(u16)*HD_TABLE_SIZE);
-       memcpy(&(priv->enhance_sensitivity_tbl[0]),
-              &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
-              sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
-
-       return iwl_dvm_send_cmd(priv, &cmd_out);
-}
-
-void iwl_init_sensitivity(struct iwl_priv *priv)
-{
-       int ret = 0;
-       int i;
-       struct iwl_sensitivity_data *data = NULL;
-       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
-
-       if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
-               return;
-
-       IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n");
-
-       /* Clear driver's sensitivity algo data */
-       data = &(priv->sensitivity_data);
-
-       if (ranges == NULL)
-               return;
-
-       memset(data, 0, sizeof(struct iwl_sensitivity_data));
-
-       data->num_in_cck_no_fa = 0;
-       data->nrg_curr_state = IWL_FA_TOO_MANY;
-       data->nrg_prev_state = IWL_FA_TOO_MANY;
-       data->nrg_silence_ref = 0;
-       data->nrg_silence_idx = 0;
-       data->nrg_energy_idx = 0;
-
-       for (i = 0; i < 10; i++)
-               data->nrg_value[i] = 0;
-
-       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
-               data->nrg_silence_rssi[i] = 0;
-
-       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;
-       data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
-       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;
-       data->last_bad_plcp_cnt_cck = 0;
-       data->last_fa_cnt_cck = 0;
-
-       if (priv->fw->enhance_sensitivity_table)
-               ret |= iwl_enhance_sensitivity_write(priv);
-       else
-               ret |= iwl_sensitivity_write(priv);
-       IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
-}
-
-void iwl_sensitivity_calibration(struct iwl_priv *priv)
-{
-       u32 rx_enable_time;
-       u32 fa_cck;
-       u32 fa_ofdm;
-       u32 bad_plcp_cck;
-       u32 bad_plcp_ofdm;
-       u32 norm_fa_ofdm;
-       u32 norm_fa_cck;
-       struct iwl_sensitivity_data *data = NULL;
-       struct statistics_rx_non_phy *rx_info;
-       struct statistics_rx_phy *ofdm, *cck;
-       struct statistics_general_data statis;
-
-       if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED)
-               return;
-
-       data = &(priv->sensitivity_data);
-
-       if (!iwl_is_any_associated(priv)) {
-               IWL_DEBUG_CALIB(priv, "<< - not associated\n");
-               return;
-       }
-
-       spin_lock_bh(&priv->statistics.lock);
-       rx_info = &priv->statistics.rx_non_phy;
-       ofdm = &priv->statistics.rx_ofdm;
-       cck = &priv->statistics.rx_cck;
-       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-               IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
-               spin_unlock_bh(&priv->statistics.lock);
-               return;
-       }
-
-       /* Extract Statistics: */
-       rx_enable_time = le32_to_cpu(rx_info->channel_load);
-       fa_cck = le32_to_cpu(cck->false_alarm_cnt);
-       fa_ofdm = le32_to_cpu(ofdm->false_alarm_cnt);
-       bad_plcp_cck = le32_to_cpu(cck->plcp_err);
-       bad_plcp_ofdm = le32_to_cpu(ofdm->plcp_err);
-
-       statis.beacon_silence_rssi_a =
-                       le32_to_cpu(rx_info->beacon_silence_rssi_a);
-       statis.beacon_silence_rssi_b =
-                       le32_to_cpu(rx_info->beacon_silence_rssi_b);
-       statis.beacon_silence_rssi_c =
-                       le32_to_cpu(rx_info->beacon_silence_rssi_c);
-       statis.beacon_energy_a =
-                       le32_to_cpu(rx_info->beacon_energy_a);
-       statis.beacon_energy_b =
-                       le32_to_cpu(rx_info->beacon_energy_b);
-       statis.beacon_energy_c =
-                       le32_to_cpu(rx_info->beacon_energy_c);
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
-
-       if (!rx_enable_time) {
-               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
-               return;
-       }
-
-       /* These statistics increase monotonically, and do not reset
-        *   at each beacon.  Calculate difference from last value, or just
-        *   use the new statistics value if it has reset or wrapped around. */
-       if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
-               data->last_bad_plcp_cnt_cck = bad_plcp_cck;
-       else {
-               bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
-               data->last_bad_plcp_cnt_cck += bad_plcp_cck;
-       }
-
-       if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
-               data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
-       else {
-               bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
-               data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
-       }
-
-       if (data->last_fa_cnt_ofdm > fa_ofdm)
-               data->last_fa_cnt_ofdm = fa_ofdm;
-       else {
-               fa_ofdm -= data->last_fa_cnt_ofdm;
-               data->last_fa_cnt_ofdm += fa_ofdm;
-       }
-
-       if (data->last_fa_cnt_cck > fa_cck)
-               data->last_fa_cnt_cck = fa_cck;
-       else {
-               fa_cck -= data->last_fa_cnt_cck;
-               data->last_fa_cnt_cck += fa_cck;
-       }
-
-       /* Total aborted signal locks */
-       norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
-       norm_fa_cck = fa_cck + bad_plcp_cck;
-
-       IWL_DEBUG_CALIB(priv, "cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
-                       bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
-
-       iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
-       iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-       if (priv->fw->enhance_sensitivity_table)
-               iwl_enhance_sensitivity_write(priv);
-       else
-               iwl_sensitivity_write(priv);
-}
-
-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;
-}
-
-/**
- * Run disconnected antenna algorithm to find out which antennas are
- * disconnected.
- */
-static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
-                                    struct iwl_chain_noise_data *data)
-{
-       u32 active_chains = 0;
-       u32 max_average_sig;
-       u16 max_average_sig_antenna_i;
-       u8 num_tx_chains;
-       u8 first_chain;
-       u16 i = 0;
-
-       average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
-       average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
-       average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
-
-       if (average_sig[0] >= average_sig[1]) {
-               max_average_sig = average_sig[0];
-               max_average_sig_antenna_i = 0;
-               active_chains = (1 << max_average_sig_antenna_i);
-       } else {
-               max_average_sig = average_sig[1];
-               max_average_sig_antenna_i = 1;
-               active_chains = (1 << max_average_sig_antenna_i);
-       }
-
-       if (average_sig[2] >= max_average_sig) {
-               max_average_sig = average_sig[2];
-               max_average_sig_antenna_i = 2;
-               active_chains = (1 << max_average_sig_antenna_i);
-       }
-
-       IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
-                    average_sig[0], average_sig[1], average_sig[2]);
-       IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
-                    max_average_sig, max_average_sig_antenna_i);
-
-       /* Compare signal strengths for all 3 receivers. */
-       for (i = 0; i < NUM_RX_CHAINS; i++) {
-               if (i != max_average_sig_antenna_i) {
-                       s32 rssi_delta = (max_average_sig - average_sig[i]);
-
-                       /* If signal is very weak, compared with
-                        * strongest, mark it as disconnected. */
-                       if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
-                               data->disconn_array[i] = 1;
-                       else
-                               active_chains |= (1 << i);
-                       IWL_DEBUG_CALIB(priv, "i = %d  rssiDelta = %d  "
-                            "disconn_array[i] = %d\n",
-                            i, rssi_delta, data->disconn_array[i]);
-               }
-       }
-
-       /*
-        * The above algorithm sometimes fails when the ucode
-        * reports 0 for all chains. It's not clear why that
-        * happens to start with, but it is then causing trouble
-        * because this can make us enable more chains than the
-        * hardware really has.
-        *
-        * To be safe, simply mask out any chains that we know
-        * are not on the device.
-        */
-       active_chains &= priv->hw_params.valid_rx_ant;
-
-       num_tx_chains = 0;
-       for (i = 0; i < NUM_RX_CHAINS; i++) {
-               /* loops on all the bits of
-                * priv->hw_setting.valid_tx_ant */
-               u8 ant_msk = (1 << i);
-               if (!(priv->hw_params.valid_tx_ant & ant_msk))
-                       continue;
-
-               num_tx_chains++;
-               if (data->disconn_array[i] == 0)
-                       /* there is a Tx antenna connected */
-                       break;
-               if (num_tx_chains == priv->hw_params.tx_chains_num &&
-                   data->disconn_array[i]) {
-                       /*
-                        * If all chains are disconnected
-                        * connect the first valid tx chain
-                        */
-                       first_chain =
-                               find_first_chain(priv->hw_params.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;
-               }
-       }
-
-       if (active_chains != priv->hw_params.valid_rx_ant &&
-           active_chains != priv->chain_noise_data.active_chains)
-               IWL_DEBUG_CALIB(priv,
-                               "Detected that not all antennas are connected! "
-                               "Connected: %#x, valid: %#x.\n",
-                               active_chains,
-                               priv->hw_params.valid_rx_ant);
-
-       /* Save for use within RXON, TX, SCAN commands, etc. */
-       data->active_chains = active_chains;
-       IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
-                       active_chains);
-}
-
-static void iwlagn_gain_computation(struct iwl_priv *priv,
-                                   u32 average_noise[NUM_RX_CHAINS],
-                                   u8 default_chain)
-{
-       int i;
-       s32 delta_g;
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-
-       /*
-        * 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 = (priv->cfg->base_params->chain_noise_scale *
-                       ((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] =
-                       min(abs(delta_g),
-                       (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
-
-               if (delta_g < 0)
-                       /*
-                        * set negative sign ...
-                        * note to Intel developers:  This is uCode API format,
-                        *   not the format of any internal device registers.
-                        *   Do not change this format for e.g. 6050 or similar
-                        *   devices.  Change format only if more resolution
-                        *   (i.e. more than 2 bits magnitude) is needed.
-                        */
-                       data->delta_gain_code[i] |= (1 << 2);
-       }
-
-       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
-                       data->delta_gain_code[1], data->delta_gain_code[2]);
-
-       if (!data->radio_write) {
-               struct iwl_calib_chain_noise_gain_cmd cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               iwl_set_calib_hdr(&cmd.hdr,
-                       priv->phy_calib_chain_noise_gain_cmd);
-               cmd.delta_gain_1 = data->delta_gain_code[1];
-               cmd.delta_gain_2 = data->delta_gain_code[2];
-               iwl_dvm_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-                       CMD_ASYNC, sizeof(cmd), &cmd);
-
-               data->radio_write = 1;
-               data->state = IWL_CHAIN_NOISE_CALIBRATED;
-       }
-}
-
-/*
- * Accumulate 16 beacons of signal and noise statistics for each of
- *   3 receivers/antennas/rx-chains, then figure out:
- * 1)  Which antennas are connected.
- * 2)  Differential rx gain settings to balance the 3 receivers.
- */
-void iwl_chain_noise_calibration(struct iwl_priv *priv)
-{
-       struct iwl_chain_noise_data *data = NULL;
-
-       u32 chain_noise_a;
-       u32 chain_noise_b;
-       u32 chain_noise_c;
-       u32 chain_sig_a;
-       u32 chain_sig_b;
-       u32 chain_sig_c;
-       u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-       u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-       u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
-       u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
-       u16 i = 0;
-       u16 rxon_chnum = INITIALIZATION_VALUE;
-       u16 stat_chnum = INITIALIZATION_VALUE;
-       u8 rxon_band24;
-       u8 stat_band24;
-       struct statistics_rx_non_phy *rx_info;
-
-       /*
-        * MULTI-FIXME:
-        * When we support multiple interfaces on different channels,
-        * this must be modified/fixed.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-       if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
-               return;
-
-       data = &(priv->chain_noise_data);
-
-       /*
-        * 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");
-               return;
-       }
-
-       spin_lock_bh(&priv->statistics.lock);
-
-       rx_info = &priv->statistics.rx_non_phy;
-
-       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-               IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
-               spin_unlock_bh(&priv->statistics.lock);
-               return;
-       }
-
-       rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
-       rxon_chnum = le16_to_cpu(ctx->staging.channel);
-       stat_band24 =
-               !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
-       stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
-
-       /* Make sure we accumulate data for just the associated channel
-        *   (even if scanning). */
-       if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
-               IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
-                               rxon_chnum, rxon_band24);
-               spin_unlock_bh(&priv->statistics.lock);
-               return;
-       }
-
-       /*
-        *  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) &
-                               IN_BAND_FILTER;
-       chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
-                               IN_BAND_FILTER;
-
-       chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
-       chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
-       chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       data->beacon_count++;
-
-       data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
-       data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
-       data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
-
-       data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
-       data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
-       data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
-
-       IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
-                       rxon_chnum, rxon_band24, data->beacon_count);
-       IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
-                       chain_sig_a, chain_sig_b, chain_sig_c);
-       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 "chain_noise_num_beacons", determine:
-        * 1)  Disconnected antennas (using signal strengths)
-        * 2)  Differential gain (using silence noise) to balance receivers */
-       if (data->beacon_count != IWL_CAL_NUM_BEACONS)
-               return;
-
-       /* Analyze signal for disconnected antenna */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               /* Disable disconnected antenna algorithm for advanced
-                  bt coex, assuming valid antennas are connected */
-               data->active_chains = priv->hw_params.valid_rx_ant;
-               for (i = 0; i < NUM_RX_CHAINS; i++)
-                       if (!(data->active_chains & (1<<i)))
-                               data->disconn_array[i] = 1;
-       } else
-               iwl_find_disconn_antenna(priv, average_sig, data);
-
-       /* Analyze noise for rx balance */
-       average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
-       average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
-       average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
-
-       for (i = 0; i < NUM_RX_CHAINS; i++) {
-               if (!(data->disconn_array[i]) &&
-                  (average_noise[i] <= min_average_noise)) {
-                       /* This means that chain i is active and has
-                        * lower noise values so far: */
-                       min_average_noise = average_noise[i];
-                       min_average_noise_antenna_i = i;
-               }
-       }
-
-       IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
-                       average_noise[0], average_noise[1],
-                       average_noise[2]);
-
-       IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
-                       min_average_noise, min_average_noise_antenna_i);
-
-       iwlagn_gain_computation(priv, average_noise,
-                               find_first_chain(priv->hw_params.valid_rx_ant));
-
-       /* Some power changes may have been made during the calibration.
-        * Update and commit the RXON
-        */
-       iwl_update_chain_flags(priv);
-
-       data->state = IWL_CHAIN_NOISE_DONE;
-       iwl_power_update_mode(priv, false);
-}
-
-void iwl_reset_run_time_calib(struct iwl_priv *priv)
-{
-       int i;
-       memset(&(priv->sensitivity_data), 0,
-              sizeof(struct iwl_sensitivity_data));
-       memset(&(priv->chain_noise_data), 0,
-              sizeof(struct iwl_chain_noise_data));
-       for (i = 0; i < NUM_RX_CHAINS; i++)
-               priv->chain_noise_data.delta_gain_code[i] =
-                               CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-
-       /* Ask for statistics now, the uCode will send notification
-        * periodically after association */
-       iwl_send_statistics_request(priv, CMD_ASYNC, true);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
deleted file mode 100644 (file)
index dbe1378..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-#ifndef __iwl_calib_h__
-#define __iwl_calib_h__
-
-#include "iwl-dev.h"
-#include "iwl-commands.h"
-
-void iwl_chain_noise_calibration(struct iwl_priv *priv);
-void iwl_sensitivity_calibration(struct iwl_priv *priv);
-
-void iwl_init_sensitivity(struct iwl_priv *priv);
-void iwl_reset_run_time_calib(struct iwl_priv *priv);
-
-#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-devices.c b/drivers/net/wireless/iwlwifi/iwl-agn-devices.c
deleted file mode 100644 (file)
index 48533b3..0000000
+++ /dev/null
@@ -1,755 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2008 - 2012 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
- *
- *****************************************************************************/
-
-/*
- * DVM device-specific data & functions
- */
-#include "iwl-agn.h"
-#include "iwl-dev.h"
-#include "iwl-commands.h"
-#include "iwl-io.h"
-#include "iwl-prph.h"
-
-/*
- * 1000 series
- * ===========
- */
-
-/*
- * For 1000, use advance thermal throttling critical temperature threshold,
- * but legacy thermal management implementation for now.
- * This is for the reason of 1000 uCode using advance thermal throttling API
- * but not implement ct_kill_exit based on ct_kill exit temperature
- * so the thermal throttling will still based on legacy thermal throttling
- * management.
- * The code here need to be modified once 1000 uCode has the advanced thermal
- * throttling algorithm in place
- */
-static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
-{
-       /* want Celsius */
-       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
-       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 1000 series */
-static void iwl1000_nic_config(struct iwl_priv *priv)
-{
-       /* set CSR_HW_CONFIG_REG for uCode use */
-       iwl_set_bit(priv->trans, 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 */
-       iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG,
-                               APMG_SVR_DIGITAL_VOLTAGE_1_32,
-                               ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
-}
-
-/**
- * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
- * @priv -- pointer to iwl_priv data structure
- * @tsf_bits -- number of bits need to shift for masking)
- */
-static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
-                                          u16 tsf_bits)
-{
-       return (1 << tsf_bits) - 1;
-}
-
-/**
- * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
- * @priv -- pointer to iwl_priv data structure
- * @tsf_bits -- number of bits need to shift for masking)
- */
-static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
-                                           u16 tsf_bits)
-{
-       return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
-}
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in extended:internal format
- * the extended part is the beacon counts
- * the internal part is the time in usec within one beacon interval
- */
-static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec,
-                               u32 beacon_interval)
-{
-       u32 quot;
-       u32 rem;
-       u32 interval = beacon_interval * TIME_UNIT;
-
-       if (!interval || !usec)
-               return 0;
-
-       quot = (usec / interval) &
-               (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
-               IWLAGN_EXT_BEACON_TIME_POS);
-       rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
-                                  IWLAGN_EXT_BEACON_TIME_POS);
-
-       return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
-                          u32 addon, u32 beacon_interval)
-{
-       u32 base_low = base & iwl_beacon_time_mask_low(priv,
-                               IWLAGN_EXT_BEACON_TIME_POS);
-       u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
-                               IWLAGN_EXT_BEACON_TIME_POS);
-       u32 interval = beacon_interval * TIME_UNIT;
-       u32 res = (base & iwl_beacon_time_mask_high(priv,
-                               IWLAGN_EXT_BEACON_TIME_POS)) +
-                               (addon & iwl_beacon_time_mask_high(priv,
-                               IWLAGN_EXT_BEACON_TIME_POS));
-
-       if (base_low > addon_low)
-               res += base_low - addon_low;
-       else if (base_low < addon_low) {
-               res += interval + base_low - addon_low;
-               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
-       } else
-               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
-
-       return cpu_to_le32(res);
-}
-
-static const struct iwl_sensitivity_ranges iwl1000_sensitivity = {
-       .min_nrg_cck = 95,
-       .auto_corr_min_ofdm = 90,
-       .auto_corr_min_ofdm_mrc = 170,
-       .auto_corr_min_ofdm_x1 = 120,
-       .auto_corr_min_ofdm_mrc_x1 = 240,
-
-       .auto_corr_max_ofdm = 120,
-       .auto_corr_max_ofdm_mrc = 210,
-       .auto_corr_max_ofdm_x1 = 155,
-       .auto_corr_max_ofdm_mrc_x1 = 290,
-
-       .auto_corr_min_cck = 125,
-       .auto_corr_max_cck = 200,
-       .auto_corr_min_cck_mrc = 170,
-       .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 void iwl1000_hw_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
-
-       priv->hw_params.tx_chains_num =
-               num_of_ant(priv->hw_params.valid_tx_ant);
-       if (priv->cfg->rx_with_siso_diversity)
-               priv->hw_params.rx_chains_num = 1;
-       else
-               priv->hw_params.rx_chains_num =
-                       num_of_ant(priv->hw_params.valid_rx_ant);
-
-       iwl1000_set_ct_threshold(priv);
-
-       /* Set initial sensitivity parameters */
-       priv->hw_params.sens = &iwl1000_sensitivity;
-}
-
-struct iwl_lib_ops iwl1000_lib = {
-       .set_hw_params = iwl1000_hw_set_hw_params,
-       .nic_config = iwl1000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REGULATORY_BAND_NO_HT40,
-               },
-       },
-       .temperature = iwlagn_temperature,
-};
-
-
-/*
- * 2000 series
- * ===========
- */
-
-static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
-{
-       /* want Celsius */
-       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 2000 series */
-static void iwl2000_nic_config(struct iwl_priv *priv)
-{
-       iwl_rf_config(priv);
-
-       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-                   CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
-}
-
-static const struct iwl_sensitivity_ranges iwl2000_sensitivity = {
-       .min_nrg_cck = 97,
-       .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 = 110,
-       .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 void iwl2000_hw_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ);
-
-       priv->hw_params.tx_chains_num =
-               num_of_ant(priv->hw_params.valid_tx_ant);
-       if (priv->cfg->rx_with_siso_diversity)
-               priv->hw_params.rx_chains_num = 1;
-       else
-               priv->hw_params.rx_chains_num =
-                       num_of_ant(priv->hw_params.valid_rx_ant);
-
-       iwl2000_set_ct_threshold(priv);
-
-       /* Set initial sensitivity parameters */
-       priv->hw_params.sens = &iwl2000_sensitivity;
-}
-
-struct iwl_lib_ops iwl2000_lib = {
-       .set_hw_params = iwl2000_hw_set_hw_params,
-       .nic_config = iwl2000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REGULATORY_BAND_NO_HT40,
-               },
-               .enhanced_txpower = true,
-       },
-       .temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl2030_lib = {
-       .set_hw_params = iwl2000_hw_set_hw_params,
-       .nic_config = iwl2000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REGULATORY_BAND_NO_HT40,
-               },
-               .enhanced_txpower = true,
-       },
-       .temperature = iwlagn_temperature,
-};
-
-/*
- * 5000 series
- * ===========
- */
-
-/* NIC configuration for 5000 series */
-static void iwl5000_nic_config(struct iwl_priv *priv)
-{
-       iwl_rf_config(priv);
-
-       /* W/A : NIC is stuck in a reset state after Early PCIe power off
-        * (PCIe power is lost before PERST# is asserted),
-        * causing ME FW to lose ownership and not being able to obtain it back.
-        */
-       iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG,
-                               APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
-                               ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
-}
-
-static const struct iwl_sensitivity_ranges iwl5000_sensitivity = {
-       .min_nrg_cck = 100,
-       .auto_corr_min_ofdm = 90,
-       .auto_corr_min_ofdm_mrc = 170,
-       .auto_corr_min_ofdm_x1 = 105,
-       .auto_corr_min_ofdm_mrc_x1 = 220,
-
-       .auto_corr_max_ofdm = 120,
-       .auto_corr_max_ofdm_mrc = 210,
-       .auto_corr_max_ofdm_x1 = 120,
-       .auto_corr_max_ofdm_mrc_x1 = 240,
-
-       .auto_corr_min_cck = 125,
-       .auto_corr_max_cck = 200,
-       .auto_corr_min_cck_mrc = 200,
-       .auto_corr_max_cck_mrc = 400,
-       .nrg_th_cck = 100,
-       .nrg_th_ofdm = 100,
-
-       .barker_corr_th_min = 190,
-       .barker_corr_th_min_mrc = 390,
-       .nrg_th_cca = 62,
-};
-
-static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
-       .min_nrg_cck = 95,
-       .auto_corr_min_ofdm = 90,
-       .auto_corr_min_ofdm_mrc = 170,
-       .auto_corr_min_ofdm_x1 = 105,
-       .auto_corr_min_ofdm_mrc_x1 = 220,
-
-       .auto_corr_max_ofdm = 120,
-       .auto_corr_max_ofdm_mrc = 210,
-       /* max = min for performance bug in 5150 DSP */
-       .auto_corr_max_ofdm_x1 = 105,
-       .auto_corr_max_ofdm_mrc_x1 = 220,
-
-       .auto_corr_min_cck = 125,
-       .auto_corr_max_cck = 200,
-       .auto_corr_min_cck_mrc = 170,
-       .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,
-};
-
-#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF  (-5)
-
-static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
-{
-       u16 temperature, voltage;
-       __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
-                               EEPROM_KELVIN_TEMPERATURE);
-
-       temperature = le16_to_cpu(temp_calib[0]);
-       voltage = le16_to_cpu(temp_calib[1]);
-
-       /* offset = temp - volt / coeff */
-       return (s32)(temperature -
-                       voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
-}
-
-static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
-{
-       const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
-       s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) -
-                       iwl_temp_calib_to_offset(priv);
-
-       priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
-}
-
-static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
-{
-       /* want Celsius */
-       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
-}
-
-static void iwl5000_hw_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-                                       BIT(IEEE80211_BAND_5GHZ);
-
-       priv->hw_params.tx_chains_num =
-               num_of_ant(priv->hw_params.valid_tx_ant);
-       priv->hw_params.rx_chains_num =
-               num_of_ant(priv->hw_params.valid_rx_ant);
-
-       iwl5000_set_ct_threshold(priv);
-
-       /* Set initial sensitivity parameters */
-       priv->hw_params.sens = &iwl5000_sensitivity;
-}
-
-static void iwl5150_hw_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-                                       BIT(IEEE80211_BAND_5GHZ);
-
-       priv->hw_params.tx_chains_num =
-               num_of_ant(priv->hw_params.valid_tx_ant);
-       priv->hw_params.rx_chains_num =
-               num_of_ant(priv->hw_params.valid_rx_ant);
-
-       iwl5150_set_ct_threshold(priv);
-
-       /* Set initial sensitivity parameters */
-       priv->hw_params.sens = &iwl5150_sensitivity;
-}
-
-static void iwl5150_temperature(struct iwl_priv *priv)
-{
-       u32 vt = 0;
-       s32 offset =  iwl_temp_calib_to_offset(priv);
-
-       vt = le32_to_cpu(priv->statistics.common.temperature);
-       vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
-       /* now vt hold the temperature in Kelvin */
-       priv->temperature = KELVIN_TO_CELSIUS(vt);
-       iwl_tt_handler(priv);
-}
-
-static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
-                                    struct ieee80211_channel_switch *ch_switch)
-{
-       /*
-        * MULTI-FIXME
-        * See iwlagn_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl5000_channel_switch_cmd cmd;
-       const struct iwl_channel_info *ch_info;
-       u32 switch_time_in_usec, ucode_switch_time;
-       u16 ch;
-       u32 tsf_low;
-       u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
-       struct ieee80211_vif *vif = ctx->vif;
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_CHANNEL_SWITCH,
-               .len = { sizeof(cmd), },
-               .flags = CMD_SYNC,
-               .data = { &cmd, },
-       };
-
-       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ch_switch->channel->hw_value;
-       IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-                     ctx->active.channel, ch);
-       cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = ctx->staging.flags;
-       cmd.rxon_filter_flags = ctx->staging.filter_flags;
-       switch_count = ch_switch->count;
-       tsf_low = ch_switch->timestamp & 0x0ffffffff;
-       /*
-        * calculate the ucode channel switch time
-        * adding TSF as one of the factor for when to switch
-        */
-       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
-               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
-                   beacon_interval)) {
-                       switch_count -= (priv->ucode_beacon_time -
-                               tsf_low) / beacon_interval;
-               } else
-                       switch_count = 0;
-       }
-       if (switch_count <= 1)
-               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-       else {
-               switch_time_in_usec =
-                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
-               ucode_switch_time = iwl_usecs_to_beacons(priv,
-                                                        switch_time_in_usec,
-                                                        beacon_interval);
-               cmd.switch_time = iwl_add_beacon_time(priv,
-                                                     priv->ucode_beacon_time,
-                                                     ucode_switch_time,
-                                                     beacon_interval);
-       }
-       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
-                     cmd.switch_time);
-       ch_info = iwl_get_channel_info(priv, priv->band, ch);
-       if (ch_info)
-               cmd.expect_beacon = is_channel_radar(ch_info);
-       else {
-               IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       ctx->active.channel, ch);
-               return -EFAULT;
-       }
-
-       return iwl_dvm_send_cmd(priv, &hcmd);
-}
-
-struct iwl_lib_ops iwl5000_lib = {
-       .set_hw_params = iwl5000_hw_set_hw_params,
-       .set_channel_switch = iwl5000_hw_channel_switch,
-       .nic_config = iwl5000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REG_BAND_52_HT40_CHANNELS
-               },
-       },
-       .temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl5150_lib = {
-       .set_hw_params = iwl5150_hw_set_hw_params,
-       .set_channel_switch = iwl5000_hw_channel_switch,
-       .nic_config = iwl5000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REG_BAND_52_HT40_CHANNELS
-               },
-       },
-       .temperature = iwl5150_temperature,
-};
-
-
-
-/*
- * 6000 series
- * ===========
- */
-
-static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
-{
-       /* want Celsius */
-       priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
-       priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
-}
-
-/* NIC configuration for 6000 series */
-static void iwl6000_nic_config(struct iwl_priv *priv)
-{
-       iwl_rf_config(priv);
-
-       switch (priv->cfg->device_family) {
-       case IWL_DEVICE_FAMILY_6005:
-       case IWL_DEVICE_FAMILY_6030:
-       case IWL_DEVICE_FAMILY_6000:
-               break;
-       case IWL_DEVICE_FAMILY_6000i:
-               /* 2x2 IPA phy type */
-               iwl_write32(priv->trans, CSR_GP_DRIVER_REG,
-                            CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
-               break;
-       case IWL_DEVICE_FAMILY_6050:
-               /* Indicate calibration version to uCode. */
-               if (iwl_eeprom_calib_version(priv) >= 6)
-                       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-                                       CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
-               break;
-       case IWL_DEVICE_FAMILY_6150:
-               /* Indicate calibration version to uCode. */
-               if (iwl_eeprom_calib_version(priv) >= 6)
-                       iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-                                       CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
-               iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG,
-                           CSR_GP_DRIVER_REG_BIT_6050_1x2);
-               break;
-       default:
-               WARN_ON(1);
-       }
-}
-
-static const struct iwl_sensitivity_ranges iwl6000_sensitivity = {
-       .min_nrg_cck = 110,
-       .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 = 110,
-       .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 = 110,
-       .nrg_th_ofdm = 110,
-
-       .barker_corr_th_min = 190,
-       .barker_corr_th_min_mrc = 336,
-       .nrg_th_cca = 62,
-};
-
-static void iwl6000_hw_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
-                                       BIT(IEEE80211_BAND_5GHZ);
-
-       priv->hw_params.tx_chains_num =
-               num_of_ant(priv->hw_params.valid_tx_ant);
-       if (priv->cfg->rx_with_siso_diversity)
-               priv->hw_params.rx_chains_num = 1;
-       else
-               priv->hw_params.rx_chains_num =
-                       num_of_ant(priv->hw_params.valid_rx_ant);
-
-       iwl6000_set_ct_threshold(priv);
-
-       /* Set initial sensitivity parameters */
-       priv->hw_params.sens = &iwl6000_sensitivity;
-
-}
-
-static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
-                                    struct ieee80211_channel_switch *ch_switch)
-{
-       /*
-        * MULTI-FIXME
-        * See iwlagn_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl6000_channel_switch_cmd cmd;
-       const struct iwl_channel_info *ch_info;
-       u32 switch_time_in_usec, ucode_switch_time;
-       u16 ch;
-       u32 tsf_low;
-       u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
-       struct ieee80211_vif *vif = ctx->vif;
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_CHANNEL_SWITCH,
-               .len = { sizeof(cmd), },
-               .flags = CMD_SYNC,
-               .data = { &cmd, },
-       };
-
-       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ch_switch->channel->hw_value;
-       IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-                     ctx->active.channel, ch);
-       cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = ctx->staging.flags;
-       cmd.rxon_filter_flags = ctx->staging.filter_flags;
-       switch_count = ch_switch->count;
-       tsf_low = ch_switch->timestamp & 0x0ffffffff;
-       /*
-        * calculate the ucode channel switch time
-        * adding TSF as one of the factor for when to switch
-        */
-       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
-               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
-                   beacon_interval)) {
-                       switch_count -= (priv->ucode_beacon_time -
-                               tsf_low) / beacon_interval;
-               } else
-                       switch_count = 0;
-       }
-       if (switch_count <= 1)
-               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-       else {
-               switch_time_in_usec =
-                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
-               ucode_switch_time = iwl_usecs_to_beacons(priv,
-                                                        switch_time_in_usec,
-                                                        beacon_interval);
-               cmd.switch_time = iwl_add_beacon_time(priv,
-                                                     priv->ucode_beacon_time,
-                                                     ucode_switch_time,
-                                                     beacon_interval);
-       }
-       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
-                     cmd.switch_time);
-       ch_info = iwl_get_channel_info(priv, priv->band, ch);
-       if (ch_info)
-               cmd.expect_beacon = is_channel_radar(ch_info);
-       else {
-               IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       ctx->active.channel, ch);
-               return -EFAULT;
-       }
-
-       return iwl_dvm_send_cmd(priv, &hcmd);
-}
-
-struct iwl_lib_ops iwl6000_lib = {
-       .set_hw_params = iwl6000_hw_set_hw_params,
-       .set_channel_switch = iwl6000_hw_channel_switch,
-       .nic_config = iwl6000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REG_BAND_52_HT40_CHANNELS
-               },
-               .enhanced_txpower = true,
-       },
-       .temperature = iwlagn_temperature,
-};
-
-struct iwl_lib_ops iwl6030_lib = {
-       .set_hw_params = iwl6000_hw_set_hw_params,
-       .set_channel_switch = iwl6000_hw_channel_switch,
-       .nic_config = iwl6000_nic_config,
-       .eeprom_ops = {
-               .regulatory_bands = {
-                       EEPROM_REG_BAND_1_CHANNELS,
-                       EEPROM_REG_BAND_2_CHANNELS,
-                       EEPROM_REG_BAND_3_CHANNELS,
-                       EEPROM_REG_BAND_4_CHANNELS,
-                       EEPROM_REG_BAND_5_CHANNELS,
-                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_REG_BAND_52_HT40_CHANNELS
-               },
-               .enhanced_txpower = true,
-       },
-       .temperature = iwlagn_temperature,
-};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
deleted file mode 100644 (file)
index e55ec6c..0000000
+++ /dev/null
@@ -1,1285 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#include <linux/etherdevice.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-int iwlagn_hw_valid_rtc_data_addr(u32 addr)
-{
-       return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
-               (addr < IWLAGN_RTC_DATA_UPPER_BOUND);
-}
-
-int iwlagn_send_tx_power(struct iwl_priv *priv)
-{
-       struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
-       u8 tx_ant_cfg_cmd;
-
-       if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status),
-                     "TX Power requested while scanning!\n"))
-               return -EAGAIN;
-
-       /* half dBm need to multiply */
-       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
-
-       if (priv->tx_power_lmt_in_half_dbm &&
-           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
-               /*
-                * For the newer devices which using enhanced/extend tx power
-                * table in EEPROM, the format is in half dBm. driver need to
-                * convert to dBm format before report to mac80211.
-                * By doing so, there is a possibility of 1/2 dBm resolution
-                * lost. driver will perform "round-up" operation before
-                * reporting, but it will cause 1/2 dBm tx power over the
-                * regulatory limit. Perform the checking here, if the
-                * "tx_power_user_lmt" is higher than EEPROM value (in
-                * half-dBm format), lower the tx power based on EEPROM
-                */
-               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
-       }
-       tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
-       tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
-
-       if (IWL_UCODE_API(priv->fw->ucode_ver) == 1)
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
-       else
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
-
-       return iwl_dvm_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
-                       sizeof(tx_power_cmd), &tx_power_cmd);
-}
-
-void iwlagn_temperature(struct iwl_priv *priv)
-{
-       lockdep_assert_held(&priv->statistics.lock);
-
-       /* store temperature from correct statistics (in Celsius) */
-       priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
-       iwl_tt_handler(priv);
-}
-
-int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
-{
-       int idx = 0;
-       int band_offset = 0;
-
-       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
-       if (rate_n_flags & RATE_MCS_HT_MSK) {
-               idx = (rate_n_flags & 0xff);
-               return idx;
-       /* Legacy rate format, search for match in table */
-       } else {
-               if (band == IEEE80211_BAND_5GHZ)
-                       band_offset = IWL_FIRST_OFDM_RATE;
-               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
-                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
-                               return idx - band_offset;
-       }
-
-       return -1;
-}
-
-int iwlagn_manage_ibss_station(struct iwl_priv *priv,
-                              struct ieee80211_vif *vif, bool add)
-{
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-       if (add)
-               return iwlagn_add_bssid_station(priv, vif_priv->ctx,
-                                               vif->bss_conf.bssid,
-                                               &vif_priv->ibss_bssid_sta_id);
-       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
-                                 vif->bss_conf.bssid);
-}
-
-/**
- * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
- *
- * pre-requirements:
- *  1. acquire mutex before calling
- *  2. make sure rf is on and not in exit state
- */
-int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
-{
-       struct iwl_txfifo_flush_cmd flush_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_TXFIFO_FLUSH,
-               .len = { sizeof(struct iwl_txfifo_flush_cmd), },
-               .flags = CMD_SYNC,
-               .data = { &flush_cmd, },
-       };
-
-       might_sleep();
-
-       memset(&flush_cmd, 0, sizeof(flush_cmd));
-       if (flush_control & BIT(IWL_RXON_CTX_BSS))
-               flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
-                                IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
-                                IWL_SCD_MGMT_MSK;
-       if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
-           (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
-               flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
-                               IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
-                               IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
-                               IWL_PAN_SCD_MULTICAST_MSK;
-
-       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-               flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
-
-       IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
-                      flush_cmd.fifo_control);
-       flush_cmd.flush_control = cpu_to_le16(flush_control);
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
-{
-       mutex_lock(&priv->mutex);
-       ieee80211_stop_queues(priv->hw);
-       if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
-               IWL_ERR(priv, "flush request fail\n");
-               goto done;
-       }
-       IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans);
-done:
-       ieee80211_wake_queues(priv->hw);
-       mutex_unlock(&priv->mutex);
-}
-
-/*
- * BT coex
- */
-/* Notmal TDM */
-static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaeaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xcc00ff28),
-       cpu_to_le32(0x0000aaaa),
-       cpu_to_le32(0xcc00aaaa),
-       cpu_to_le32(0x0000aaaa),
-       cpu_to_le32(0xc0004000),
-       cpu_to_le32(0x00004000),
-       cpu_to_le32(0xf0005000),
-       cpu_to_le32(0xf0005000),
-};
-
-
-/* Loose Coex */
-static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaeaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xcc00ff28),
-       cpu_to_le32(0x0000aaaa),
-       cpu_to_le32(0xcc00aaaa),
-       cpu_to_le32(0x0000aaaa),
-       cpu_to_le32(0x00000000),
-       cpu_to_le32(0x00000000),
-       cpu_to_le32(0xf0005000),
-       cpu_to_le32(0xf0005000),
-};
-
-/* Full concurrency */
-static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0x00000000),
-       cpu_to_le32(0x00000000),
-       cpu_to_le32(0x00000000),
-       cpu_to_le32(0x00000000),
-};
-
-void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
-{
-       struct iwl_basic_bt_cmd basic = {
-               .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
-               .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
-               .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
-               .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
-       };
-       struct iwl_bt_cmd_v1 bt_cmd_v1;
-       struct iwl_bt_cmd_v2 bt_cmd_v2;
-       int ret;
-
-       BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
-                       sizeof(basic.bt3_lookup_table));
-
-       if (priv->cfg->bt_params) {
-               /*
-                * newer generation of devices (2000 series and newer)
-                * use the version 2 of the bt command
-                * we need to make sure sending the host command
-                * with correct data structure to avoid uCode assert
-                */
-               if (priv->cfg->bt_params->bt_session_2) {
-                       bt_cmd_v2.prio_boost = cpu_to_le32(
-                               priv->cfg->bt_params->bt_prio_boost);
-                       bt_cmd_v2.tx_prio_boost = 0;
-                       bt_cmd_v2.rx_prio_boost = 0;
-               } else {
-                       bt_cmd_v1.prio_boost =
-                               priv->cfg->bt_params->bt_prio_boost;
-                       bt_cmd_v1.tx_prio_boost = 0;
-                       bt_cmd_v1.rx_prio_boost = 0;
-               }
-       } else {
-               IWL_ERR(priv, "failed to construct BT Coex Config\n");
-               return;
-       }
-
-       /*
-        * Possible situations when BT needs to take over for receive,
-        * at the same time where STA needs to response to AP's frame(s),
-        * reduce the tx power of the required response frames, by that,
-        * allow the concurrent BT receive & WiFi transmit
-        * (BT - ANT A, WiFi -ANT B), without interference to one another
-        *
-        * Reduced tx power apply to control frames only (ACK/Back/CTS)
-        * when indicated by the BT config command
-        */
-       basic.kill_ack_mask = priv->kill_ack_mask;
-       basic.kill_cts_mask = priv->kill_cts_mask;
-       if (priv->reduced_txpower)
-               basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
-       basic.valid = priv->bt_valid;
-
-       /*
-        * Configure BT coex mode to "no coexistence" when the
-        * user disabled BT coexistence, we have no interface
-        * (might be in monitor mode), or the interface is in
-        * IBSS mode (no proper uCode support for coex then).
-        */
-       if (!iwlwifi_mod_params.bt_coex_active ||
-           priv->iw_mode == NL80211_IFTYPE_ADHOC) {
-               basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
-       } else {
-               basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
-                                       IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
-
-               if (!priv->bt_enable_pspoll)
-                       basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
-               else
-                       basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
-
-               if (priv->bt_ch_announce)
-                       basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
-               IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags);
-       }
-       priv->bt_enable_flag = basic.flags;
-       if (priv->bt_full_concurrent)
-               memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup,
-                       sizeof(iwlagn_concurrent_lookup));
-       else
-               memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup,
-                       sizeof(iwlagn_def_3w_lookup));
-
-       IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n",
-                      basic.flags ? "active" : "disabled",
-                      priv->bt_full_concurrent ?
-                      "full concurrency" : "3-wire");
-
-       if (priv->cfg->bt_params->bt_session_2) {
-               memcpy(&bt_cmd_v2.basic, &basic,
-                       sizeof(basic));
-               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                       CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2);
-       } else {
-               memcpy(&bt_cmd_v1.basic, &basic,
-                       sizeof(basic));
-               ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                       CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1);
-       }
-       if (ret)
-               IWL_ERR(priv, "failed to send BT Coex Config\n");
-
-}
-
-void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
-{
-       struct iwl_rxon_context *ctx, *found_ctx = NULL;
-       bool found_ap = false;
-
-       lockdep_assert_held(&priv->mutex);
-
-       /* Check whether AP or GO mode is active. */
-       if (rssi_ena) {
-               for_each_context(priv, ctx) {
-                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
-                           iwl_is_associated_ctx(ctx)) {
-                               found_ap = true;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * If disable was received or If GO/AP mode, disable RSSI
-        * measurements.
-        */
-       if (!rssi_ena || found_ap) {
-               if (priv->cur_rssi_ctx) {
-                       ctx = priv->cur_rssi_ctx;
-                       ieee80211_disable_rssi_reports(ctx->vif);
-                       priv->cur_rssi_ctx = NULL;
-               }
-               return;
-       }
-
-       /*
-        * If rssi measurements need to be enabled, consider all cases now.
-        * Figure out how many contexts are active.
-        */
-       for_each_context(priv, ctx) {
-               if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
-                   iwl_is_associated_ctx(ctx)) {
-                       found_ctx = ctx;
-                       break;
-               }
-       }
-
-       /*
-        * rssi monitor already enabled for the correct interface...nothing
-        * to do.
-        */
-       if (found_ctx == priv->cur_rssi_ctx)
-               return;
-
-       /*
-        * Figure out if rssi monitor is currently enabled, and needs
-        * to be changed. If rssi monitor is already enabled, disable
-        * it first else just enable rssi measurements on the
-        * interface found above.
-        */
-       if (priv->cur_rssi_ctx) {
-               ctx = priv->cur_rssi_ctx;
-               if (ctx->vif)
-                       ieee80211_disable_rssi_reports(ctx->vif);
-       }
-
-       priv->cur_rssi_ctx = found_ctx;
-
-       if (!found_ctx)
-               return;
-
-       ieee80211_enable_rssi_reports(found_ctx->vif,
-                       IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
-                       IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
-}
-
-static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
-{
-       return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
-                       BT_UART_MSG_FRAME3SCOESCO_POS;
-}
-
-static void iwlagn_bt_traffic_change_work(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, bt_traffic_change_work);
-       struct iwl_rxon_context *ctx;
-       int smps_request = -1;
-
-       if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
-               /* bt coex disabled */
-               return;
-       }
-
-       /*
-        * Note: bt_traffic_load can be overridden by scan complete and
-        * coex profile notifications. Ignore that since only bad consequence
-        * can be not matching debug print with actual state.
-        */
-       IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
-                      priv->bt_traffic_load);
-
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               if (priv->bt_status)
-                       smps_request = IEEE80211_SMPS_DYNAMIC;
-               else
-                       smps_request = IEEE80211_SMPS_AUTOMATIC;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               smps_request = IEEE80211_SMPS_DYNAMIC;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               smps_request = IEEE80211_SMPS_STATIC;
-               break;
-       default:
-               IWL_ERR(priv, "Invalid BT traffic load: %d\n",
-                       priv->bt_traffic_load);
-               break;
-       }
-
-       mutex_lock(&priv->mutex);
-
-       /*
-        * We can not send command to firmware while scanning. When the scan
-        * complete we will schedule this work again. We do check with mutex
-        * locked to prevent new scan request to arrive. We do not check
-        * STATUS_SCANNING to avoid race when queue_work two times from
-        * different notifications, but quit and not perform any work at all.
-        */
-       if (test_bit(STATUS_SCAN_HW, &priv->status))
-               goto out;
-
-       iwl_update_chain_flags(priv);
-
-       if (smps_request != -1) {
-               priv->current_ht_config.smps = smps_request;
-               for_each_context(priv, ctx) {
-                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
-                               ieee80211_request_smps(ctx->vif, smps_request);
-               }
-       }
-
-       /*
-        * Dynamic PS poll related functionality. Adjust RSSI measurements if
-        * necessary.
-        */
-       iwlagn_bt_coex_rssi_monitor(priv);
-out:
-       mutex_unlock(&priv->mutex);
-}
-
-/*
- * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
- * correct interface or disable it if this is the last interface to be
- * removed.
- */
-void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
-{
-       if (priv->bt_is_sco &&
-           priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
-               iwlagn_bt_adjust_rssi_monitor(priv, true);
-       else
-               iwlagn_bt_adjust_rssi_monitor(priv, false);
-}
-
-static void iwlagn_print_uartmsg(struct iwl_priv *priv,
-                               struct iwl_bt_uart_msg *uart_msg)
-{
-       IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, "
-                       "Update Req = 0x%X\n",
-               (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
-                       BT_UART_MSG_FRAME1MSGTYPE_POS,
-               (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
-                       BT_UART_MSG_FRAME1SSN_POS,
-               (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
-                       BT_UART_MSG_FRAME1UPDATEREQ_POS);
-
-       IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
-                       "Chl_SeqN = 0x%X, In band = 0x%X\n",
-               (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
-                       BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
-               (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
-                       BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
-               (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
-                       BT_UART_MSG_FRAME2CHLSEQN_POS,
-               (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
-                       BT_UART_MSG_FRAME2INBAND_POS);
-
-       IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
-                       "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n",
-               (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3SCOESCO_POS,
-               (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3SNIFF_POS,
-               (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3A2DP_POS,
-               (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3ACL_POS,
-               (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3MASTER_POS,
-               (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
-                       BT_UART_MSG_FRAME3OBEX_POS);
-
-       IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n",
-               (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
-                       BT_UART_MSG_FRAME4IDLEDURATION_POS);
-
-       IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
-                       "eSCO Retransmissions = 0x%X\n",
-               (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
-                       BT_UART_MSG_FRAME5TXACTIVITY_POS,
-               (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
-                       BT_UART_MSG_FRAME5RXACTIVITY_POS,
-               (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
-                       BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
-
-       IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n",
-               (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
-                       BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
-               (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
-                       BT_UART_MSG_FRAME6DISCOVERABLE_POS);
-
-       IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = "
-                       "0x%X, Inquiry = 0x%X, Connectable = 0x%X\n",
-               (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
-                       BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
-               (BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >>
-                       BT_UART_MSG_FRAME7PAGE_POS,
-               (BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >>
-                       BT_UART_MSG_FRAME7INQUIRY_POS,
-               (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
-                       BT_UART_MSG_FRAME7CONNECTABLE_POS);
-}
-
-static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
-                               struct iwl_bt_uart_msg *uart_msg)
-{
-       bool need_update = false;
-       u8 kill_msk = IWL_BT_KILL_REDUCE;
-       static const __le32 bt_kill_ack_msg[3] = {
-               IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
-               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
-               IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
-       static const __le32 bt_kill_cts_msg[3] = {
-               IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
-               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO,
-               IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE};
-
-       if (!priv->reduced_txpower)
-               kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
-                       ? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT;
-       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
-           priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
-               priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
-               priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
-               priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
-               priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
-               need_update = true;
-       }
-       return need_update;
-}
-
-/*
- * Upon RSSI changes, sends a bt config command with following changes
- *  1. enable/disable "reduced control frames tx power
- *  2. update the "kill)ack_mask" and "kill_cts_mask"
- *
- * If "reduced tx power" is enabled, uCode shall
- *  1. ACK/Back/CTS rate shall reduced to 6Mbps
- *  2. not use duplciate 20/40MHz mode
- */
-static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
-                               struct iwl_bt_uart_msg *uart_msg)
-{
-       bool need_update = false;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       int ave_rssi;
-
-       ave_rssi = ieee80211_ave_rssi(ctx->vif);
-       if (!ave_rssi) {
-               /* no rssi data, no changes to reduce tx power */
-               IWL_DEBUG_COEX(priv, "no rssi data available\n");
-               return need_update;
-       }
-       if (!priv->reduced_txpower &&
-           !iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
-           (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
-           (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
-           BT_UART_MSG_FRAME3OBEX_MSK)) &&
-           !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
-           BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) {
-               /* enabling reduced tx power */
-               priv->reduced_txpower = true;
-               priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
-               need_update = true;
-       } else if (priv->reduced_txpower &&
-                  (iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
-                  (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
-                  (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
-                  BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
-                  !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
-                  BT_UART_MSG_FRAME3OBEX_MSK)))) {
-               /* disable reduced tx power */
-               priv->reduced_txpower = false;
-               priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
-               need_update = true;
-       }
-
-       return need_update;
-}
-
-int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_cmd_buffer *rxb,
-                                 struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data;
-       struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
-
-       if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
-               /* bt coex disabled */
-               return 0;
-       }
-
-       IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
-       IWL_DEBUG_COEX(priv, "    status: %d\n", coex->bt_status);
-       IWL_DEBUG_COEX(priv, "    traffic load: %d\n", coex->bt_traffic_load);
-       IWL_DEBUG_COEX(priv, "    CI compliance: %d\n",
-                       coex->bt_ci_compliance);
-       iwlagn_print_uartmsg(priv, uart_msg);
-
-       priv->last_bt_traffic_load = priv->bt_traffic_load;
-       priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
-
-       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-               if (priv->bt_status != coex->bt_status ||
-                   priv->last_bt_traffic_load != coex->bt_traffic_load) {
-                       if (coex->bt_status) {
-                               /* BT on */
-                               if (!priv->bt_ch_announce)
-                                       priv->bt_traffic_load =
-                                               IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-                               else
-                                       priv->bt_traffic_load =
-                                               coex->bt_traffic_load;
-                       } else {
-                               /* BT off */
-                               priv->bt_traffic_load =
-                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE;
-                       }
-                       priv->bt_status = coex->bt_status;
-                       queue_work(priv->workqueue,
-                                  &priv->bt_traffic_change_work);
-               }
-       }
-
-       /* schedule to send runtime bt_config */
-       /* check reduce power before change ack/cts kill mask */
-       if (iwlagn_fill_txpower_mode(priv, uart_msg) ||
-           iwlagn_set_kill_msk(priv, uart_msg))
-               queue_work(priv->workqueue, &priv->bt_runtime_config);
-
-
-       /* FIXME: based on notification, adjust the prio_boost */
-
-       priv->bt_ci_compliance = coex->bt_ci_compliance;
-       return 0;
-}
-
-void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
-{
-       priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
-               iwlagn_bt_coex_profile_notif;
-}
-
-void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
-{
-       INIT_WORK(&priv->bt_traffic_change_work,
-                 iwlagn_bt_traffic_change_work);
-}
-
-void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
-{
-       cancel_work_sync(&priv->bt_traffic_change_work);
-}
-
-static bool is_single_rx_stream(struct iwl_priv *priv)
-{
-       return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
-              priv->current_ht_config.single_chain_sufficient;
-}
-
-#define IWL_NUM_RX_CHAINS_MULTIPLE     3
-#define IWL_NUM_RX_CHAINS_SINGLE       2
-#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
- * 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)
-{
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist &&
-           (priv->bt_full_concurrent ||
-            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
-               /*
-                * only use chain 'A' in bt high traffic load or
-                * full concurrency mode
-                */
-               return IWL_NUM_RX_CHAINS_SINGLE;
-       }
-       /* # of Rx chains to use when expecting MIMO. */
-       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 mode, unless device support spatial
- * multiplexing power save, use the active count for rx chain count.
- */
-static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
-{
-       /* # Rx chains when idling, depending on SMPS mode */
-       switch (priv->current_ht_config.smps) {
-       case IEEE80211_SMPS_STATIC:
-       case IEEE80211_SMPS_DYNAMIC:
-               return IWL_NUM_IDLE_CHAINS_SINGLE;
-       case IEEE80211_SMPS_AUTOMATIC:
-       case IEEE80211_SMPS_OFF:
-               return active_cnt;
-       default:
-               WARN(1, "invalid SMPS mode %d",
-                    priv->current_ht_config.smps);
-               return active_cnt;
-       }
-}
-
-/* up to 4 chains */
-static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
-{
-       u8 res;
-       res = (chain_bitmap & BIT(0)) >> 0;
-       res += (chain_bitmap & BIT(1)) >> 1;
-       res += (chain_bitmap & BIT(2)) >> 2;
-       res += (chain_bitmap & BIT(3)) >> 3;
-       return res;
-}
-
-/**
- * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
- *
- * Selects how many and which Rx receivers/antennas/chains to use.
- * This should not be used for scan command ... it puts data in wrong place.
- */
-void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       bool is_single = is_single_rx_stream(priv);
-       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-       u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
-       u32 active_chains;
-       u16 rx_chain;
-
-       /* Tell uCode which antennas are actually connected.
-        * Before first association, we assume all antennas are connected.
-        * Just after first association, iwl_chain_noise_calibration()
-        *    checks which antennas actually *are* connected. */
-       if (priv->chain_noise_data.active_chains)
-               active_chains = priv->chain_noise_data.active_chains;
-       else
-               active_chains = priv->hw_params.valid_rx_ant;
-
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist &&
-           (priv->bt_full_concurrent ||
-            priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
-               /*
-                * only use chain 'A' in bt high traffic load or
-                * full concurrency mode
-                */
-               active_chains = first_antenna(active_chains);
-       }
-
-       rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
-
-       /* How many receivers should we use? */
-       active_rx_cnt = iwl_get_active_rx_chain_count(priv);
-       idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
-
-
-       /* correct rx chain count according hw settings
-        * and chain noise calibration
-        */
-       valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
-       if (valid_rx_cnt < active_rx_cnt)
-               active_rx_cnt = valid_rx_cnt;
-
-       if (valid_rx_cnt < idle_rx_cnt)
-               idle_rx_cnt = valid_rx_cnt;
-
-       rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
-       rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
-
-       ctx->staging.rx_chain = cpu_to_le16(rx_chain);
-
-       if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
-               ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
-       else
-               ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
-
-       IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
-                       ctx->staging.rx_chain,
-                       active_rx_cnt, idle_rx_cnt);
-
-       WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
-               active_rx_cnt < idle_rx_cnt);
-}
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
-{
-       int i;
-       u8 ind = ant;
-
-       if (priv->band == IEEE80211_BAND_2GHZ &&
-           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
-               return 0;
-
-       for (i = 0; i < RATE_ANT_NUM - 1; i++) {
-               ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
-               if (valid & BIT(ind))
-                       return ind;
-       }
-       return ant;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
-{
-       int i;
-
-       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
-               out[i] = cpu_to_le16(p1k[i]);
-}
-
-struct wowlan_key_data {
-       struct iwl_rxon_context *ctx;
-       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
-       struct iwlagn_wowlan_tkip_params_cmd *tkip;
-       const u8 *bssid;
-       bool error, use_rsc_tsc, use_tkip;
-};
-
-
-static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct ieee80211_sta *sta,
-                              struct ieee80211_key_conf *key,
-                              void *_data)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct wowlan_key_data *data = _data;
-       struct iwl_rxon_context *ctx = data->ctx;
-       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
-       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
-       struct iwlagn_p1k_cache *rx_p1ks;
-       u8 *rx_mic_key;
-       struct ieee80211_key_seq seq;
-       u32 cur_rx_iv32 = 0;
-       u16 p1k[IWLAGN_P1K_SIZE];
-       int ret, i;
-
-       mutex_lock(&priv->mutex);
-
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
-            !sta && !ctx->key_mapping_keys)
-               ret = iwl_set_default_wep_key(priv, ctx, key);
-       else
-               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
-
-       if (ret) {
-               IWL_ERR(priv, "Error setting key during suspend!\n");
-               data->error = true;
-       }
-
-       switch (key->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               if (sta) {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
-                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
-
-                       rx_p1ks = data->tkip->rx_uni;
-
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
-
-                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
-                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
-
-                       memcpy(data->tkip->mic_keys.tx,
-                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
-                              IWLAGN_MIC_KEY_SIZE);
-
-                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
-               } else {
-                       tkip_sc =
-                               data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
-                       rx_p1ks = data->tkip->rx_multi;
-                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
-               }
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 (as they need to to avoid replay attacks)
-                * for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
-                       /* wrapping isn't allowed, AP must rekey */
-                       if (seq.tkip.iv32 > cur_rx_iv32)
-                               cur_rx_iv32 = seq.tkip.iv32;
-               }
-
-               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
-               ieee80211_get_tkip_rx_p1k(key, data->bssid,
-                                         cur_rx_iv32 + 1, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
-
-               memcpy(rx_mic_key,
-                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
-                      IWLAGN_MIC_KEY_SIZE);
-
-               data->use_tkip = true;
-               data->use_rsc_tsc = true;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               if (sta) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
-                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
-
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       aes_tx_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               } else
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       aes_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               }
-               data->use_rsc_tsc = true;
-               break;
-       }
-
-       mutex_unlock(&priv->mutex);
-}
-
-int iwlagn_send_patterns(struct iwl_priv *priv,
-                       struct cfg80211_wowlan *wowlan)
-{
-       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_WOWLAN_PATTERNS,
-               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-               .flags = CMD_SYNC,
-       };
-       int i, err;
-
-       if (!wowlan->n_patterns)
-               return 0;
-
-       cmd.len[0] = sizeof(*pattern_cmd) +
-               wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
-
-       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
-       if (!pattern_cmd)
-               return -ENOMEM;
-
-       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
-
-       for (i = 0; i < wowlan->n_patterns; i++) {
-               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
-
-               memcpy(&pattern_cmd->patterns[i].mask,
-                       wowlan->patterns[i].mask, mask_len);
-               memcpy(&pattern_cmd->patterns[i].pattern,
-                       wowlan->patterns[i].pattern,
-                       wowlan->patterns[i].pattern_len);
-               pattern_cmd->patterns[i].mask_size = mask_len;
-               pattern_cmd->patterns[i].pattern_size =
-                       wowlan->patterns[i].pattern_len;
-       }
-
-       cmd.data[0] = pattern_cmd;
-       err = iwl_dvm_send_cmd(priv, &cmd);
-       kfree(pattern_cmd);
-       return err;
-}
-
-int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
-{
-       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
-       struct iwl_rxon_cmd rxon;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
-       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
-       struct wowlan_key_data key_data = {
-               .ctx = ctx,
-               .bssid = ctx->active.bssid_addr,
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
-       int ret, i;
-       u16 seq;
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc)
-               return -ENOMEM;
-
-       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
-
-       /*
-        * We know the last used seqno, and the uCode expects to know that
-        * one, it will increment before TX.
-        */
-       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
-       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
-
-       /*
-        * For QoS counters, we store the one to use next, so subtract 0x10
-        * since the uCode will add 0x10 before using the value.
-        */
-       for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
-               seq = priv->tid_data[IWL_AP_ID][i].seq_number;
-               seq -= 0x10;
-               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
-       }
-
-       if (wowlan->disconnect)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
-                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
-       if (wowlan->magic_pkt)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
-       if (wowlan->gtk_rekey_failure)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
-       if (wowlan->eap_identity_req)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
-       if (wowlan->four_way_handshake)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
-       if (wowlan->n_patterns)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
-
-       if (wowlan->rfkill_release)
-               d3_cfg_cmd.wakeup_flags |=
-                       cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
-
-       iwl_scan_cancel_timeout(priv, 200);
-
-       memcpy(&rxon, &ctx->active, sizeof(rxon));
-
-       priv->ucode_loaded = false;
-       iwl_trans_stop_device(priv->trans);
-
-       priv->wowlan = true;
-
-       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
-       if (ret)
-               goto out;
-
-       /* now configure WoWLAN ucode */
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto out;
-
-       memcpy(&ctx->staging, &rxon, sizeof(rxon));
-       ret = iwlagn_commit_rxon(priv, ctx);
-       if (ret)
-               goto out;
-
-       ret = iwl_power_update_mode(priv, true);
-       if (ret)
-               goto out;
-
-       if (!iwlwifi_mod_params.sw_crypto) {
-               /* mark all keys clear */
-               priv->ucode_key_table = 0;
-               ctx->key_mapping_keys = 0;
-
-               /*
-                * This needs to be unlocked due to lock ordering
-                * constraints. Since we're in the suspend path
-                * that isn't really a problem though.
-                */
-               mutex_unlock(&priv->mutex);
-               ieee80211_iter_keys(priv->hw, ctx->vif,
-                                   iwlagn_wowlan_program_keys,
-                                   &key_data);
-               mutex_lock(&priv->mutex);
-               if (key_data.error) {
-                       ret = -EIO;
-                       goto out;
-               }
-
-               if (key_data.use_rsc_tsc) {
-                       struct iwl_host_cmd rsc_tsc_cmd = {
-                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
-                               .flags = CMD_SYNC,
-                               .data[0] = key_data.rsc_tsc,
-                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(*key_data.rsc_tsc),
-                       };
-
-                       ret = iwl_dvm_send_cmd(priv, &rsc_tsc_cmd);
-                       if (ret)
-                               goto out;
-               }
-
-               if (key_data.use_tkip) {
-                       ret = iwl_dvm_send_cmd_pdu(priv,
-                                                REPLY_WOWLAN_TKIP_PARAMS,
-                                                CMD_SYNC, sizeof(tkip_cmd),
-                                                &tkip_cmd);
-                       if (ret)
-                               goto out;
-               }
-
-               if (priv->have_rekey_data) {
-                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
-                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
-                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
-                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
-                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
-                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
-
-                       ret = iwl_dvm_send_cmd_pdu(priv,
-                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
-                                                CMD_SYNC, sizeof(kek_kck_cmd),
-                                                &kek_kck_cmd);
-                       if (ret)
-                               goto out;
-               }
-       }
-
-       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_D3_CONFIG, CMD_SYNC,
-                                    sizeof(d3_cfg_cmd), &d3_cfg_cmd);
-       if (ret)
-               goto out;
-
-       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_WAKEUP_FILTER,
-                                CMD_SYNC, sizeof(wakeup_filter_cmd),
-                                &wakeup_filter_cmd);
-       if (ret)
-               goto out;
-
-       ret = iwlagn_send_patterns(priv, wowlan);
- out:
-       kfree(key_data.rsc_tsc);
-       return ret;
-}
-#endif
-
-int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
-       if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
-               IWL_WARN(priv, "Not sending command - %s KILL\n",
-                        iwl_is_rfkill(priv) ? "RF" : "CT");
-               return -EIO;
-       }
-
-       if (test_bit(STATUS_FW_ERROR, &priv->status)) {
-               IWL_ERR(priv, "Command %s failed: FW Error\n",
-                       iwl_dvm_get_cmd_string(cmd->id));
-               return -EIO;
-       }
-
-       /*
-        * Synchronous commands from this op-mode must hold
-        * the mutex, this ensures we don't try to send two
-        * (or more) synchronous commands at a time.
-        */
-       if (cmd->flags & CMD_SYNC)
-               lockdep_assert_held(&priv->mutex);
-
-       if (priv->ucode_owner == IWL_OWNERSHIP_TM &&
-           !(cmd->flags & CMD_ON_DEMAND)) {
-               IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
-               return -EIO;
-       }
-
-       return iwl_trans_send_cmd(priv->trans, cmd);
-}
-
-int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
-                        u32 flags, u16 len, const void *data)
-{
-       struct iwl_host_cmd cmd = {
-               .id = id,
-               .len = { len, },
-               .data = { data, },
-               .flags = flags,
-       };
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
deleted file mode 100644 (file)
index 8cebd7c..0000000
+++ /dev/null
@@ -1,3369 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2005 - 2012 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/init.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <net/mac80211.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-
-#include <linux/workqueue.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-op-mode.h"
-#include "iwl-modparams.h"
-
-#define RS_NAME "iwl-agn-rs"
-
-#define NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define IWL_NUMBER_TRY      1
-#define IWL_HT_NUMBER_TRY   3
-
-#define IWL_RATE_MAX_WINDOW            62      /* # tx in history window */
-#define IWL_RATE_MIN_FAILURE_TH                6       /* min failures to calc tpt */
-#define IWL_RATE_MIN_SUCCESS_TH                8       /* min successes to calc tpt */
-
-/* max allowed rate miss before sync LQ cmd */
-#define IWL_MISSED_RATE_MAX            15
-/* max time to accum history 2 seconds */
-#define IWL_RATE_SCALE_FLUSH_INTVL   (3*HZ)
-
-static u8 rs_ht_to_legacy[] = {
-       IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
-       IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
-       IWL_RATE_6M_INDEX,
-       IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
-       IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
-       IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
-       IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
-};
-
-static const u8 ant_toggle_lookup[] = {
-       /*ANT_NONE -> */ ANT_NONE,
-       /*ANT_A    -> */ ANT_B,
-       /*ANT_B    -> */ ANT_C,
-       /*ANT_AB   -> */ ANT_BC,
-       /*ANT_C    -> */ ANT_A,
-       /*ANT_AC   -> */ ANT_AB,
-       /*ANT_BC   -> */ ANT_AC,
-       /*ANT_ABC  -> */ ANT_ABC,
-};
-
-#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
-       [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
-                                   IWL_RATE_SISO_##s##M_PLCP, \
-                                   IWL_RATE_MIMO2_##s##M_PLCP,\
-                                   IWL_RATE_MIMO3_##s##M_PLCP,\
-                                   IWL_RATE_##r##M_IEEE,      \
-                                   IWL_RATE_##ip##M_INDEX,    \
-                                   IWL_RATE_##in##M_INDEX,    \
-                                   IWL_RATE_##rp##M_INDEX,    \
-                                   IWL_RATE_##rn##M_INDEX,    \
-                                   IWL_RATE_##pp##M_INDEX,    \
-                                   IWL_RATE_##np##M_INDEX }
-
-/*
- * Parameter order:
- *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
- *
- * If there isn't a valid next or previous rate then INV is used which
- * maps to IWL_RATE_INVALID
- *
- */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
-       IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
-       IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
-       IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-       IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
-       IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
-       IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
-       IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
-       IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
-       IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
-       IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
-       IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
-       IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
-       IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
-       /* FIXME:RS:          ^^    should be INV (legacy) */
-};
-
-static inline u8 rs_extract_rate(u32 rate_n_flags)
-{
-       return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
-}
-
-static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
-{
-       int idx = 0;
-
-       /* HT rate format */
-       if (rate_n_flags & RATE_MCS_HT_MSK) {
-               idx = rs_extract_rate(rate_n_flags);
-
-               if (idx >= IWL_RATE_MIMO3_6M_PLCP)
-                       idx = idx - IWL_RATE_MIMO3_6M_PLCP;
-               else if (idx >= IWL_RATE_MIMO2_6M_PLCP)
-                       idx = idx - IWL_RATE_MIMO2_6M_PLCP;
-
-               idx += IWL_FIRST_OFDM_RATE;
-               /* skip 9M not supported in ht*/
-               if (idx >= IWL_RATE_9M_INDEX)
-                       idx += 1;
-               if ((idx >= IWL_FIRST_OFDM_RATE) && (idx <= IWL_LAST_OFDM_RATE))
-                       return idx;
-
-       /* legacy rate format, search for match in table */
-       } else {
-               for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
-                       if (iwl_rates[idx].plcp ==
-                                       rs_extract_rate(rate_n_flags))
-                               return idx;
-       }
-
-       return -1;
-}
-
-static void rs_rate_scale_perform(struct iwl_priv *priv,
-                                  struct sk_buff *skb,
-                                  struct ieee80211_sta *sta,
-                                  struct iwl_lq_sta *lq_sta);
-static void rs_fill_link_cmd(struct iwl_priv *priv,
-                            struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
-
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index);
-#else
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index)
-{}
-#endif
-
-/**
- * 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_legacy[IWL_RATE_COUNT] = {
-       7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
-};
-
-static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
-       {0, 0, 0, 0, 42, 0,  76, 102, 124, 159, 183, 193, 202}, /* Norm */
-       {0, 0, 0, 0, 46, 0,  82, 110, 132, 168, 192, 202, 210}, /* SGI */
-       {0, 0, 0, 0, 47, 0,  91, 133, 171, 242, 305, 334, 362}, /* AGG */
-       {0, 0, 0, 0, 52, 0, 101, 145, 187, 264, 330, 361, 390}, /* AGG+SGI */
-};
-
-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,  94, 0, 177, 249, 313, 423, 512, 550, 586}, /* AGG */
-       {0, 0, 0, 0, 104, 0, 193, 270, 338, 454, 545, 584, 620}, /* AGG+SGI */
-};
-
-static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
-       {0, 0, 0, 0,  74, 0, 123, 155, 179, 214, 236, 244, 251}, /* Norm */
-       {0, 0, 0, 0,  81, 0, 131, 164, 188, 223, 243, 251, 257}, /* SGI */
-       {0, 0, 0, 0,  89, 0, 167, 235, 296, 402, 488, 526, 560}, /* AGG */
-       {0, 0, 0, 0,  97, 0, 182, 255, 320, 431, 520, 558, 593}, /* AGG+SGI*/
-};
-
-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, 171, 0, 305, 410, 496, 634, 731, 771, 805}, /* AGG */
-       {0, 0, 0, 0, 186, 0, 329, 439, 527, 667, 764, 803, 838}, /* AGG+SGI */
-};
-
-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_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 */
-static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
-       {  "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)
-
-static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
-{
-       window->data = 0;
-       window->success_counter = 0;
-       window->success_ratio = IWL_INVALID_VALUE;
-       window->counter = 0;
-       window->average_tpt = IWL_INVALID_VALUE;
-       window->stamp = 0;
-}
-
-static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
-{
-       return (ant_type & valid_antenna) == ant_type;
-}
-
-/*
- *     removes the old data from the statistics. All data that is older than
- *     TID_MAX_TIME_DIFF, will be deleted.
- */
-static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
-{
-       /* The oldest age we want to keep */
-       u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
-
-       while (tl->queue_count &&
-              (tl->time_stamp < oldest_time)) {
-               tl->total -= tl->packet_count[tl->head];
-               tl->packet_count[tl->head] = 0;
-               tl->time_stamp += TID_QUEUE_CELL_SPACING;
-               tl->queue_count--;
-               tl->head++;
-               if (tl->head >= TID_QUEUE_MAX_SIZE)
-                       tl->head = 0;
-       }
-}
-
-/*
- *     increment traffic load value for tid and also remove
- *     any old values if passed the certain time period
- */
-static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
-                          struct ieee80211_hdr *hdr)
-{
-       u32 curr_time = jiffies_to_msecs(jiffies);
-       u32 time_diff;
-       s32 index;
-       struct iwl_traffic_load *tl = NULL;
-       u8 tid;
-
-       if (ieee80211_is_data_qos(hdr->frame_control)) {
-               u8 *qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & 0xf;
-       } else
-               return IWL_MAX_TID_COUNT;
-
-       if (unlikely(tid >= IWL_MAX_TID_COUNT))
-               return IWL_MAX_TID_COUNT;
-
-       tl = &lq_data->load[tid];
-
-       curr_time -= curr_time % TID_ROUND_VALUE;
-
-       /* Happens only for the first packet. Initialize the data */
-       if (!(tl->queue_count)) {
-               tl->total = 1;
-               tl->time_stamp = curr_time;
-               tl->queue_count = 1;
-               tl->head = 0;
-               tl->packet_count[0] = 1;
-               return IWL_MAX_TID_COUNT;
-       }
-
-       time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
-       index = time_diff / TID_QUEUE_CELL_SPACING;
-
-       /* The history is too long: remove data that is older than */
-       /* TID_MAX_TIME_DIFF */
-       if (index >= TID_QUEUE_MAX_SIZE)
-               rs_tl_rm_old_stats(tl, curr_time);
-
-       index = (tl->head + index) % TID_QUEUE_MAX_SIZE;
-       tl->packet_count[index] = tl->packet_count[index] + 1;
-       tl->total = tl->total + 1;
-
-       if ((index + 1) > tl->queue_count)
-               tl->queue_count = index + 1;
-
-       return tid;
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-/**
- * Program the device to use fixed rate for frame transmit
- * This is for debugging/testing only
- * once the device start use fixed rate, we need to reload the module
- * to being back the normal operation.
- */
-static void rs_program_fix_rate(struct iwl_priv *priv,
-                               struct iwl_lq_sta *lq_sta)
-{
-       struct iwl_station_priv *sta_priv =
-               container_of(lq_sta, struct iwl_station_priv, lq_sta);
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
-       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-       /* testmode has higher priority to overwirte the fixed rate */
-       if (priv->tm_fixed_rate)
-               lq_sta->dbg_fixed_rate = priv->tm_fixed_rate;
-#endif
-
-       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
-               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
-       if (lq_sta->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
-                               false);
-       }
-}
-#endif
-
-/*
-       get the traffic load value for tid
-*/
-static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
-{
-       u32 curr_time = jiffies_to_msecs(jiffies);
-       u32 time_diff;
-       s32 index;
-       struct iwl_traffic_load *tl = NULL;
-
-       if (tid >= IWL_MAX_TID_COUNT)
-               return 0;
-
-       tl = &(lq_data->load[tid]);
-
-       curr_time -= curr_time % TID_ROUND_VALUE;
-
-       if (!(tl->queue_count))
-               return 0;
-
-       time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time);
-       index = time_diff / TID_QUEUE_CELL_SPACING;
-
-       /* The history is too long: remove data that is older than */
-       /* TID_MAX_TIME_DIFF */
-       if (index >= TID_QUEUE_MAX_SIZE)
-               rs_tl_rm_old_stats(tl, curr_time);
-
-       return tl->total;
-}
-
-static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
-                                     struct iwl_lq_sta *lq_data, u8 tid,
-                                     struct ieee80211_sta *sta)
-{
-       int ret = -EAGAIN;
-       u32 load;
-
-       /*
-        * Don't create TX aggregation sessions when in high
-        * BT traffic, as they would just be disrupted by BT.
-        */
-       if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
-               IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
-                       priv->bt_traffic_load);
-               return ret;
-       }
-
-       load = rs_tl_get_load(lq_data, tid);
-
-       if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
-               IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
-                               sta->addr, tid);
-               ret = ieee80211_start_tx_ba_session(sta, tid, 5000);
-               if (ret == -EAGAIN) {
-                       /*
-                        * driver and mac80211 is out of sync
-                        * this might be cause by reloading firmware
-                        * stop the tx ba session here
-                        */
-                       IWL_ERR(priv, "Fail start Tx agg on tid: %d\n",
-                               tid);
-                       ieee80211_stop_tx_ba_session(sta, tid);
-               }
-       } else {
-               IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d "
-                       "because load = %u\n", tid, load);
-       }
-       return ret;
-}
-
-static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
-                             struct iwl_lq_sta *lq_data,
-                             struct ieee80211_sta *sta)
-{
-       if (tid < IWL_MAX_TID_COUNT)
-               rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
-       else
-               IWL_ERR(priv, "tid exceeds max TID count: %d/%d\n",
-                       tid, IWL_MAX_TID_COUNT);
-}
-
-static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
-{
-       return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
-              !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
-              !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
-}
-
-/*
- * 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;
-}
-
-/**
- * rs_collect_tx_data - Update the success/failure sliding window
- *
- * We keep a sliding window of the last 62 packets transmitted
- * at this rate.  window->data contains the bitmask of successful
- * packets.
- */
-static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
-                             int scale_index, int attempts, int successes)
-{
-       struct iwl_rate_scale_data *window = NULL;
-       static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
-       s32 fail_count, tpt;
-
-       if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
-               return -EINVAL;
-
-       /* Select window for current tx bit rate */
-       window = &(tbl->win[scale_index]);
-
-       /* Get expected throughput */
-       tpt = get_expected_tpt(tbl, scale_index);
-
-       /*
-        * Keep track of only the latest 62 tx frame attempts in this rate's
-        * history window; anything older isn't really relevant any more.
-        * If we have filled up the sliding window, drop the oldest attempt;
-        * if the oldest attempt (highest bit in bitmap) shows "success",
-        * subtract "1" from the success counter (this is the main reason
-        * we keep these bitmaps!).
-        */
-       while (attempts > 0) {
-               if (window->counter >= IWL_RATE_MAX_WINDOW) {
-
-                       /* remove earliest */
-                       window->counter = IWL_RATE_MAX_WINDOW - 1;
-
-                       if (window->data & mask) {
-                               window->data &= ~mask;
-                               window->success_counter--;
-                       }
-               }
-
-               /* Increment frames-attempted counter */
-               window->counter++;
-
-               /* 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--;
-               }
-
-               attempts--;
-       }
-
-       /* Calculate current success ratio, avoid divide-by-0! */
-       if (window->counter > 0)
-               window->success_ratio = 128 * (100 * window->success_counter)
-                                       / window->counter;
-       else
-               window->success_ratio = IWL_INVALID_VALUE;
-
-       fail_count = window->counter - window->success_counter;
-
-       /* Calculate average throughput, if we have enough history. */
-       if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
-           (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
-               window->average_tpt = (window->success_ratio * tpt + 64) / 128;
-       else
-               window->average_tpt = IWL_INVALID_VALUE;
-
-       /* Tag this window as having been updated */
-       window->stamp = jiffies;
-
-       return 0;
-}
-
-/*
- * Fill uCode API rate_n_flags field, based on "search" or "active" table.
- */
-/* FIXME:RS:remove this function and put the flags statically in the table */
-static u32 rate_n_flags_from_tbl(struct iwl_priv *priv,
-                                struct iwl_scale_tbl_info *tbl,
-                                int index, u8 use_green)
-{
-       u32 rate_n_flags = 0;
-
-       if (is_legacy(tbl->lq_type)) {
-               rate_n_flags = iwl_rates[index].plcp;
-               if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
-                       rate_n_flags |= RATE_MCS_CCK_MSK;
-
-       } else if (is_Ht(tbl->lq_type)) {
-               if (index > IWL_LAST_OFDM_RATE) {
-                       IWL_ERR(priv, "Invalid HT rate index %d\n", index);
-                       index = IWL_LAST_OFDM_RATE;
-               }
-               rate_n_flags = RATE_MCS_HT_MSK;
-
-               if (is_siso(tbl->lq_type))
-                       rate_n_flags |= iwl_rates[index].plcp_siso;
-               else if (is_mimo2(tbl->lq_type))
-                       rate_n_flags |= iwl_rates[index].plcp_mimo2;
-               else
-                       rate_n_flags |= iwl_rates[index].plcp_mimo3;
-       } else {
-               IWL_ERR(priv, "Invalid tbl->lq_type %d\n", tbl->lq_type);
-       }
-
-       rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
-                                                    RATE_MCS_ANT_ABC_MSK);
-
-       if (is_Ht(tbl->lq_type)) {
-               if (tbl->is_ht40) {
-                       if (tbl->is_dup)
-                               rate_n_flags |= RATE_MCS_DUP_MSK;
-                       else
-                               rate_n_flags |= RATE_MCS_HT40_MSK;
-               }
-               if (tbl->is_SGI)
-                       rate_n_flags |= RATE_MCS_SGI_MSK;
-
-               if (use_green) {
-                       rate_n_flags |= RATE_MCS_GF_MSK;
-                       if (is_siso(tbl->lq_type) && tbl->is_SGI) {
-                               rate_n_flags &= ~RATE_MCS_SGI_MSK;
-                               IWL_ERR(priv, "GF was set with SGI:SISO\n");
-                       }
-               }
-       }
-       return rate_n_flags;
-}
-
-/*
- * Interpret uCode API's rate_n_flags format,
- * fill "search" or "active" tx mode table.
- */
-static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
-                                   enum ieee80211_band band,
-                                   struct iwl_scale_tbl_info *tbl,
-                                   int *rate_idx)
-{
-       u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
-       u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
-       u8 mcs;
-
-       memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
-       *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
-
-       if (*rate_idx  == IWL_RATE_INVALID) {
-               *rate_idx = -1;
-               return -EINVAL;
-       }
-       tbl->is_SGI = 0;        /* default legacy setup */
-       tbl->is_ht40 = 0;
-       tbl->is_dup = 0;
-       tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
-       tbl->lq_type = LQ_NONE;
-       tbl->max_search = IWL_MAX_SEARCH;
-
-       /* legacy rate format */
-       if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
-               if (num_of_ant == 1) {
-                       if (band == IEEE80211_BAND_5GHZ)
-                               tbl->lq_type = LQ_A;
-                       else
-                               tbl->lq_type = LQ_G;
-               }
-       /* HT rate format */
-       } else {
-               if (rate_n_flags & RATE_MCS_SGI_MSK)
-                       tbl->is_SGI = 1;
-
-               if ((rate_n_flags & RATE_MCS_HT40_MSK) ||
-                   (rate_n_flags & RATE_MCS_DUP_MSK))
-                       tbl->is_ht40 = 1;
-
-               if (rate_n_flags & RATE_MCS_DUP_MSK)
-                       tbl->is_dup = 1;
-
-               mcs = rs_extract_rate(rate_n_flags);
-
-               /* SISO */
-               if (mcs <= IWL_RATE_SISO_60M_PLCP) {
-                       if (num_of_ant == 1)
-                               tbl->lq_type = LQ_SISO; /*else NONE*/
-               /* MIMO2 */
-               } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
-                       if (num_of_ant == 2)
-                               tbl->lq_type = LQ_MIMO2;
-               /* MIMO3 */
-               } else {
-                       if (num_of_ant == 3) {
-                               tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-                               tbl->lq_type = LQ_MIMO3;
-                       }
-               }
-       }
-       return 0;
-}
-
-/* switch to another antenna/antennas and return 1 */
-/* if no other valid antenna found, return 0 */
-static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
-                            struct iwl_scale_tbl_info *tbl)
-{
-       u8 new_ant_type;
-
-       if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
-               return 0;
-
-       if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
-               return 0;
-
-       new_ant_type = ant_toggle_lookup[tbl->ant_type];
-
-       while ((new_ant_type != tbl->ant_type) &&
-              !rs_is_valid_ant(valid_ant, new_ant_type))
-               new_ant_type = ant_toggle_lookup[new_ant_type];
-
-       if (new_ant_type == tbl->ant_type)
-               return 0;
-
-       tbl->ant_type = new_ant_type;
-       *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
-       *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
-       return 1;
-}
-
-/**
- * Green-field mode is valid if the station supports it and
- * there are no non-GF stations present in the BSS.
- */
-static bool rs_use_green(struct ieee80211_sta *sta)
-{
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-               !(ctx->ht.non_gf_sta_present);
-}
-
-/**
- * rs_get_supported_rates - get the available rates
- *
- * if management frame or broadcast frame only return
- * basic available rates.
- *
- */
-static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
-                                 struct ieee80211_hdr *hdr,
-                                 enum iwl_table_type rate_type)
-{
-       if (is_legacy(rate_type)) {
-               return lq_sta->active_legacy_rate;
-       } else {
-               if (is_siso(rate_type))
-                       return lq_sta->active_siso_rate;
-               else if (is_mimo2(rate_type))
-                       return lq_sta->active_mimo2_rate;
-               else
-                       return lq_sta->active_mimo3_rate;
-       }
-}
-
-static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
-                               int rate_type)
-{
-       u8 high = IWL_RATE_INVALID;
-       u8 low = IWL_RATE_INVALID;
-
-       /* 802.11A or ht walks to the next literal adjacent rate in
-        * the rate table */
-       if (is_a_band(rate_type) || !is_legacy(rate_type)) {
-               int i;
-               u32 mask;
-
-               /* Find the previous rate that is in the rate mask */
-               i = index - 1;
-               for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
-                       if (rate_mask & mask) {
-                               low = i;
-                               break;
-                       }
-               }
-
-               /* Find the next rate that is in the rate mask */
-               i = index + 1;
-               for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
-                       if (rate_mask & mask) {
-                               high = i;
-                               break;
-                       }
-               }
-
-               return (high << 8) | low;
-       }
-
-       low = index;
-       while (low != IWL_RATE_INVALID) {
-               low = iwl_rates[low].prev_rs;
-               if (low == IWL_RATE_INVALID)
-                       break;
-               if (rate_mask & (1 << low))
-                       break;
-               IWL_DEBUG_RATE(priv, "Skipping masked lower rate: %d\n", low);
-       }
-
-       high = index;
-       while (high != IWL_RATE_INVALID) {
-               high = iwl_rates[high].next_rs;
-               if (high == IWL_RATE_INVALID)
-                       break;
-               if (rate_mask & (1 << high))
-                       break;
-               IWL_DEBUG_RATE(priv, "Skipping masked higher rate: %d\n", high);
-       }
-
-       return (high << 8) | low;
-}
-
-static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
-                            struct iwl_scale_tbl_info *tbl,
-                            u8 scale_index, u8 ht_possible)
-{
-       s32 low;
-       u16 rate_mask;
-       u16 high_low;
-       u8 switch_to_legacy = 0;
-       u8 is_green = lq_sta->is_green;
-       struct iwl_priv *priv = lq_sta->drv;
-
-       /* check if we need to switch from HT to legacy rates.
-        * assumption is that mandatory rates (1Mbps or 6Mbps)
-        * are always supported (spec demand) */
-       if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
-               switch_to_legacy = 1;
-               scale_index = rs_ht_to_legacy[scale_index];
-               if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                       tbl->lq_type = LQ_A;
-               else
-                       tbl->lq_type = LQ_G;
-
-               if (num_of_ant(tbl->ant_type) > 1)
-                       tbl->ant_type =
-                           first_antenna(priv->hw_params.valid_tx_ant);
-
-               tbl->is_ht40 = 0;
-               tbl->is_SGI = 0;
-               tbl->max_search = IWL_MAX_SEARCH;
-       }
-
-       rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
-
-       /* Mask with station rate restriction */
-       if (is_legacy(tbl->lq_type)) {
-               /* supp_rates has no CCK bits in A mode */
-               if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                       rate_mask  = (u16)(rate_mask &
-                          (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-               else
-                       rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
-       }
-
-       /* If we switched from HT to legacy, check current rate */
-       if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
-               low = scale_index;
-               goto out;
-       }
-
-       high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
-                                       tbl->lq_type);
-       low = high_low & 0xff;
-
-       if (low == IWL_RATE_INVALID)
-               low = scale_index;
-
-out:
-       return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green);
-}
-
-/*
- * 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 void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                           struct iwl_lq_sta *lq_sta)
-{
-       struct iwl_scale_tbl_info *tbl;
-       bool full_concurrent = priv->bt_full_concurrent;
-
-       if (priv->bt_ant_couple_ok) {
-               /*
-                * Is there a need to switch between
-                * full concurrency and 3-wire?
-                */
-               if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
-                       full_concurrent = true;
-               else
-                       full_concurrent = false;
-       }
-       if ((priv->bt_traffic_load != priv->last_bt_traffic_load) ||
-           (priv->bt_full_concurrent != full_concurrent)) {
-               priv->bt_full_concurrent = full_concurrent;
-               priv->last_bt_traffic_load = priv->bt_traffic_load;
-
-               /* Update uCode's rate table. */
-               tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-               iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-
-               queue_work(priv->workqueue, &priv->bt_full_concurrency);
-       }
-}
-
-/*
- * 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 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_op_mode *op_mode = (struct iwl_op_mode *)priv_r;
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       enum mac80211_rate_control_flags mac_flags;
-       u32 tx_rate;
-       struct iwl_scale_tbl_info tbl_type;
-       struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
-
-       /* Treat uninitialized rate scaling data same as non-existing. */
-       if (!lq_sta) {
-               IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n");
-               return;
-       } else if (!lq_sta->drv) {
-               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
-               return;
-       }
-
-       if (!ieee80211_is_data(hdr->frame_control) ||
-           info->flags & IEEE80211_TX_CTL_NO_ACK)
-               return;
-
-       /* This packet was aggregated but doesn't carry status info */
-       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
-           !(info->flags & IEEE80211_TX_STAT_AMPDU))
-               return;
-
-       /*
-        * Ignore this Tx frame response if its initial rate doesn't match
-        * that of latest Link Quality command.  There may be stragglers
-        * from a previous Link Quality command, but we're no longer interested
-        * in those; they're either from the "active" mode while we're trying
-        * 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)
-               rs_index -= IWL_FIRST_OFDM_RATE;
-       mac_flags = info->status.rates[0].flags;
-       mac_index = info->status.rates[0].idx;
-       /* For HT packets, map MCS to PLCP */
-       if (mac_flags & IEEE80211_TX_RC_MCS) {
-               mac_index &= RATE_MCS_CODE_MSK; /* Remove # of streams */
-               if (mac_index >= (IWL_RATE_9M_INDEX - IWL_FIRST_OFDM_RATE))
-                       mac_index++;
-               /*
-                * mac80211 HT index is always zero-indexed; we need to move
-                * HT OFDM rates after CCK rates in 2.4 GHz band
-                */
-               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)) ||
-           (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) ||
-           (tbl_type.ant_type != info->status.antenna) ||
-           (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) ||
-           (!!(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);
-               /*
-                * 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, ctx, &lq_sta->lq, CMD_ASYNC, false);
-               }
-               /* 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");
-               tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
-                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
-               tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
-               IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
-                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
-               IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
-                       tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
-               /*
-                * no matching table found, let's by-pass the data collection
-                * and continue to perform rate scale to find the rate table
-                */
-               rs_stay_in_table(lq_sta, true);
-               goto done;
-       }
-
-       /*
-        * 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);
-               rs_collect_tx_data(curr_tbl, rs_index,
-                                  info->status.ampdu_len,
-                                  info->status.ampdu_ack_len);
-
-               /* Update success/fail counts if not searching for new mode */
-               if (lq_sta->stay_in_tbl) {
-                       lq_sta->total_success += info->status.ampdu_ack_len;
-                       lq_sta->total_failed += (info->status.ampdu_len -
-                                       info->status.ampdu_ack_len);
-               }
-       } else {
-       /*
-        * For legacy, update frame history with for each Tx retry.
-        */
-               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))
-                               tmp_tbl = curr_tbl;
-                       else if (table_type_matches(&tbl_type, other_tbl))
-                               tmp_tbl = other_tbl;
-                       else
-                               continue;
-                       rs_collect_tx_data(tmp_tbl, rs_index, 1,
-                                          i < retries ? 0 : 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;
-done:
-       /* 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);
-
-#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_IWLWIFI_DEVICE_TESTMODE)
-       if ((priv->tm_fixed_rate) &&
-           (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
-               rs_program_fix_rate(priv, lq_sta);
-#endif
-       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
-               rs_bt_update_lq(priv, ctx, lq_sta);
-}
-
-/*
- * Begin a period of staying with a selected modulation mode.
- * Set "stay_in_tbl" flag to prevent any mode switches.
- * Set frame tx success limits according to legacy vs. high-throughput,
- * and reset overall (spanning all rates) tx success history statistics.
- * These control how long we stay using same modulation mode before
- * searching for a new mode.
- */
-static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
-                                struct iwl_lq_sta *lq_sta)
-{
-       IWL_DEBUG_RATE(priv, "we are staying in the same table\n");
-       lq_sta->stay_in_tbl = 1;        /* only place this gets set */
-       if (is_legacy) {
-               lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
-               lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
-               lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
-       } else {
-               lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
-               lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
-               lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
-       }
-       lq_sta->table_count = 0;
-       lq_sta->total_failed = 0;
-       lq_sta->total_success = 0;
-       lq_sta->flush_timer = jiffies;
-       lq_sta->action_counter = 0;
-}
-
-/*
- * Find correct throughput table for given mode of modulation
- */
-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)) {
-               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];
-}
-
-/*
- * Find starting rate for new "search" high-throughput mode of modulation.
- * Goal is to find lowest expected rate (under perfect conditions) that is
- * above the current measured throughput of "active" mode, to give new mode
- * a fair chance to prove itself without too many challenges.
- *
- * This gets called when transitioning to more aggressive modulation
- * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
- * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
- * to decrease to match "active" throughput.  When moving from MIMO to SISO,
- * bit rate will typically need to increase, but not if performance was bad.
- */
-static s32 rs_get_best_rate(struct iwl_priv *priv,
-                           struct iwl_lq_sta *lq_sta,
-                           struct iwl_scale_tbl_info *tbl,     /* "search" */
-                           u16 rate_mask, s8 index)
-{
-       /* "active" values */
-       struct iwl_scale_tbl_info *active_tbl =
-           &(lq_sta->lq_info[lq_sta->active_tbl]);
-       s32 active_sr = active_tbl->win[index].success_ratio;
-       s32 active_tpt = active_tbl->expected_tpt[index];
-
-       /* expected "search" throughput */
-       s32 *tpt_tbl = tbl->expected_tpt;
-
-       s32 new_rate, high, low, start_hi;
-       u16 high_low;
-       s8 rate = index;
-
-       new_rate = high = low = start_hi = IWL_RATE_INVALID;
-
-       for (; ;) {
-               high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
-                                               tbl->lq_type);
-
-               low = high_low & 0xff;
-               high = (high_low >> 8) & 0xff;
-
-               /*
-                * Lower the "search" bit rate, to give new "search" mode
-                * approximately the same throughput as "active" if:
-                *
-                * 1) "Active" mode has been working modestly well (but not
-                *    great), and expected "search" throughput (under perfect
-                *    conditions) at candidate rate is above the actual
-                *    measured "active" throughput (but less than expected
-                *    "active" throughput under perfect conditions).
-                * OR
-                * 2) "Active" mode has been working perfectly or very well
-                *    and expected "search" throughput (under perfect
-                *    conditions) at candidate rate is above expected
-                *    "active" throughput (under perfect conditions).
-                */
-               if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
-                    ((active_sr > IWL_RATE_DECREASE_TH) &&
-                     (active_sr <= IWL_RATE_HIGH_TH) &&
-                     (tpt_tbl[rate] <= active_tpt))) ||
-                   ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
-                    (tpt_tbl[rate] > active_tpt))) {
-
-                       /* (2nd or later pass)
-                        * If we've already tried to raise the rate, and are
-                        * now trying to lower it, use the higher rate. */
-                       if (start_hi != IWL_RATE_INVALID) {
-                               new_rate = start_hi;
-                               break;
-                       }
-
-                       new_rate = rate;
-
-                       /* Loop again with lower rate */
-                       if (low != IWL_RATE_INVALID)
-                               rate = low;
-
-                       /* Lower rate not available, use the original */
-                       else
-                               break;
-
-               /* Else try to raise the "search" rate to match "active" */
-               } else {
-                       /* (2nd or later pass)
-                        * If we've already tried to lower the rate, and are
-                        * now trying to raise it, use the lower rate. */
-                       if (new_rate != IWL_RATE_INVALID)
-                               break;
-
-                       /* Loop again with higher rate */
-                       else if (high != IWL_RATE_INVALID) {
-                               start_hi = high;
-                               rate = high;
-
-                       /* Higher rate not available, use the original */
-                       } else {
-                               new_rate = rate;
-                               break;
-                       }
-               }
-       }
-
-       return new_rate;
-}
-
-/*
- * Set up search table for MIMO2
- */
-static int rs_switch_to_mimo2(struct iwl_priv *priv,
-                            struct iwl_lq_sta *lq_sta,
-                            struct ieee80211_conf *conf,
-                            struct ieee80211_sta *sta,
-                            struct iwl_scale_tbl_info *tbl, int index)
-{
-       u16 rate_mask;
-       s32 rate;
-       s8 is_green = lq_sta->is_green;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-               return -1;
-
-       if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-                                               == WLAN_HT_CAP_SM_PS_STATIC)
-               return -1;
-
-       /* Need both Tx chains/antennas to support MIMO */
-       if (priv->hw_params.tx_chains_num < 2)
-               return -1;
-
-       IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n");
-
-       tbl->lq_type = LQ_MIMO2;
-       tbl->is_dup = lq_sta->is_dup;
-       tbl->action = 0;
-       tbl->max_search = IWL_MAX_SEARCH;
-       rate_mask = lq_sta->active_mimo2_rate;
-
-       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-               tbl->is_ht40 = 1;
-       else
-               tbl->is_ht40 = 0;
-
-       rs_set_expected_tpt_table(lq_sta, tbl);
-
-       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-       IWL_DEBUG_RATE(priv, "LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
-       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-               IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
-                                               rate, rate_mask);
-               return -1;
-       }
-       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-
-       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-                    tbl->current_rate, is_green);
-       return 0;
-}
-
-/*
- * Set up search table for MIMO3
- */
-static int rs_switch_to_mimo3(struct iwl_priv *priv,
-                            struct iwl_lq_sta *lq_sta,
-                            struct ieee80211_conf *conf,
-                            struct ieee80211_sta *sta,
-                            struct iwl_scale_tbl_info *tbl, int index)
-{
-       u16 rate_mask;
-       s32 rate;
-       s8 is_green = lq_sta->is_green;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-               return -1;
-
-       if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
-                                               == WLAN_HT_CAP_SM_PS_STATIC)
-               return -1;
-
-       /* Need both Tx chains/antennas to support MIMO */
-       if (priv->hw_params.tx_chains_num < 3)
-               return -1;
-
-       IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n");
-
-       tbl->lq_type = LQ_MIMO3;
-       tbl->is_dup = lq_sta->is_dup;
-       tbl->action = 0;
-       tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
-       rate_mask = lq_sta->active_mimo3_rate;
-
-       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-               tbl->is_ht40 = 1;
-       else
-               tbl->is_ht40 = 0;
-
-       rs_set_expected_tpt_table(lq_sta, tbl);
-
-       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-       IWL_DEBUG_RATE(priv, "LQ: MIMO3 best rate %d mask %X\n",
-               rate, rate_mask);
-       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-               IWL_DEBUG_RATE(priv, "Can't switch with index %d rate mask %x\n",
-                                               rate, rate_mask);
-               return -1;
-       }
-       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-
-       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-                    tbl->current_rate, is_green);
-       return 0;
-}
-
-/*
- * Set up search table for SISO
- */
-static int rs_switch_to_siso(struct iwl_priv *priv,
-                            struct iwl_lq_sta *lq_sta,
-                            struct ieee80211_conf *conf,
-                            struct ieee80211_sta *sta,
-                            struct iwl_scale_tbl_info *tbl, int index)
-{
-       u16 rate_mask;
-       u8 is_green = lq_sta->is_green;
-       s32 rate;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
-               return -1;
-
-       IWL_DEBUG_RATE(priv, "LQ: try to switch to SISO\n");
-
-       tbl->is_dup = lq_sta->is_dup;
-       tbl->lq_type = LQ_SISO;
-       tbl->action = 0;
-       tbl->max_search = IWL_MAX_SEARCH;
-       rate_mask = lq_sta->active_siso_rate;
-
-       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-               tbl->is_ht40 = 1;
-       else
-               tbl->is_ht40 = 0;
-
-       if (is_green)
-               tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
-
-       rs_set_expected_tpt_table(lq_sta, tbl);
-       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
-
-       IWL_DEBUG_RATE(priv, "LQ: get best rate %d mask %X\n", rate, rate_mask);
-       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-               IWL_DEBUG_RATE(priv, "can not switch with index %d rate mask %x\n",
-                            rate, rate_mask);
-               return -1;
-       }
-       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, rate, is_green);
-       IWL_DEBUG_RATE(priv, "LQ: Switch to new mcs %X index is green %X\n",
-                    tbl->current_rate, is_green);
-       return 0;
-}
-
-/*
- * Try to switch to new modulation mode from legacy
- */
-static int rs_move_legacy_other(struct iwl_priv *priv,
-                               struct iwl_lq_sta *lq_sta,
-                               struct ieee80211_conf *conf,
-                               struct ieee80211_sta *sta,
-                               int index)
-{
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-       struct iwl_rate_scale_data *window = &(tbl->win[index]);
-       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action;
-       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-       u8 tx_chains_num = priv->hw_params.tx_chains_num;
-       int ret = 0;
-       u8 update_search_tbl_counter = 0;
-
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               /* nothing */
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_LEGACY_SWITCH_SISO;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               /* avoid antenna B and MIMO */
-               valid_tx_ant =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
-                   tbl->action != IWL_LEGACY_SWITCH_SISO)
-                       tbl->action = IWL_LEGACY_SWITCH_SISO;
-               break;
-       default:
-               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-               break;
-       }
-
-       if (!iwl_ht_enabled(priv))
-               /* stay in Legacy */
-               tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-       else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
-                  tbl->action > IWL_LEGACY_SWITCH_SISO)
-               tbl->action = IWL_LEGACY_SWITCH_SISO;
-
-       /* configure as 1x1 if bt full concurrency */
-       if (priv->bt_full_concurrent) {
-               if (!iwl_ht_enabled(priv))
-                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-               else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_LEGACY_SWITCH_SISO;
-               valid_tx_ant =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-       }
-
-       start_action = tbl->action;
-       for (; ;) {
-               lq_sta->action_counter++;
-               switch (tbl->action) {
-               case IWL_LEGACY_SWITCH_ANTENNA1:
-               case IWL_LEGACY_SWITCH_ANTENNA2:
-                       IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
-
-                       if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
-                                                       tx_chains_num <= 1) ||
-                           (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
-                                                       tx_chains_num <= 2))
-                               break;
-
-                       /* Don't change antenna if success has been great */
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
-                           !priv->bt_full_concurrent &&
-                           priv->bt_traffic_load ==
-                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
-                               break;
-
-                       /* Set up search table to try other antenna */
-                       memcpy(search_tbl, tbl, sz);
-
-                       if (rs_toggle_antenna(valid_tx_ant,
-                               &search_tbl->current_rate, search_tbl)) {
-                               update_search_tbl_counter = 1;
-                               rs_set_expected_tpt_table(lq_sta, search_tbl);
-                               goto out;
-                       }
-                       break;
-               case IWL_LEGACY_SWITCH_SISO:
-                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to SISO\n");
-
-                       /* Set up search table to try SISO */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret) {
-                               lq_sta->action_counter = 0;
-                               goto out;
-                       }
-
-                       break;
-               case IWL_LEGACY_SWITCH_MIMO2_AB:
-               case IWL_LEGACY_SWITCH_MIMO2_AC:
-               case IWL_LEGACY_SWITCH_MIMO2_BC:
-                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO2\n");
-
-                       /* Set up search table to try MIMO */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-
-                       if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_LEGACY_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret) {
-                               lq_sta->action_counter = 0;
-                               goto out;
-                       }
-                       break;
-
-               case IWL_LEGACY_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(priv, "LQ: Legacy switch to MIMO3\n");
-
-                       /* Set up search table to try MIMO3 */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-
-                       search_tbl->ant_type = ANT_ABC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret) {
-                               lq_sta->action_counter = 0;
-                               goto out;
-                       }
-                       break;
-               }
-               tbl->action++;
-               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-
-               if (tbl->action == start_action)
-                       break;
-
-       }
-       search_tbl->lq_type = LQ_NONE;
-       return 0;
-
-out:
-       lq_sta->search_better_tbl = 1;
-       tbl->action++;
-       if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-               tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
-       if (update_search_tbl_counter)
-               search_tbl->action = tbl->action;
-       return 0;
-
-}
-
-/*
- * Try to switch to new modulation mode from SISO
- */
-static int rs_move_siso_to_other(struct iwl_priv *priv,
-                                struct iwl_lq_sta *lq_sta,
-                                struct ieee80211_conf *conf,
-                                struct ieee80211_sta *sta, int index)
-{
-       u8 is_green = lq_sta->is_green;
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-       struct iwl_rate_scale_data *window = &(tbl->win[index]);
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action;
-       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-       u8 tx_chains_num = priv->hw_params.tx_chains_num;
-       u8 update_search_tbl_counter = 0;
-       int ret;
-
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               /* nothing */
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               /* avoid antenna B and MIMO */
-               valid_tx_ant =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-               if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-               break;
-       default:
-               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-               break;
-       }
-
-       if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
-           tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
-               /* stay in SISO */
-               tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-       }
-
-       /* configure as 1x1 if bt full concurrency */
-       if (priv->bt_full_concurrent) {
-               valid_tx_ant =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-       }
-
-       start_action = tbl->action;
-       for (;;) {
-               lq_sta->action_counter++;
-               switch (tbl->action) {
-               case IWL_SISO_SWITCH_ANTENNA1:
-               case IWL_SISO_SWITCH_ANTENNA2:
-                       IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
-                       if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
-                                               tx_chains_num <= 1) ||
-                           (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
-                                               tx_chains_num <= 2))
-                               break;
-
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
-                           !priv->bt_full_concurrent &&
-                           priv->bt_traffic_load ==
-                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
-                               break;
-
-                       memcpy(search_tbl, tbl, sz);
-                       if (rs_toggle_antenna(valid_tx_ant,
-                                      &search_tbl->current_rate, search_tbl)) {
-                               update_search_tbl_counter = 1;
-                               goto out;
-                       }
-                       break;
-               case IWL_SISO_SWITCH_MIMO2_AB:
-               case IWL_SISO_SWITCH_MIMO2_AC:
-               case IWL_SISO_SWITCH_MIMO2_BC:
-                       IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO2\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-
-                       if (tbl->action == IWL_SISO_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_SISO_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
-               case IWL_SISO_SWITCH_GI:
-                       if (!tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_20))
-                               break;
-                       if (tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_40))
-                               break;
-
-                       IWL_DEBUG_RATE(priv, "LQ: SISO toggle SGI/NGI\n");
-
-                       memcpy(search_tbl, tbl, sz);
-                       if (is_green) {
-                               if (!tbl->is_SGI)
-                                       break;
-                               else
-                                       IWL_ERR(priv,
-                                               "SGI was set in GF+SISO\n");
-                       }
-                       search_tbl->is_SGI = !tbl->is_SGI;
-                       rs_set_expected_tpt_table(lq_sta, search_tbl);
-                       if (tbl->is_SGI) {
-                               s32 tpt = lq_sta->last_tpt / 100;
-                               if (tpt >= search_tbl->expected_tpt[index])
-                                       break;
-                       }
-                       search_tbl->current_rate =
-                               rate_n_flags_from_tbl(priv, search_tbl,
-                                                     index, is_green);
-                       update_search_tbl_counter = 1;
-                       goto out;
-               case IWL_SISO_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       search_tbl->ant_type = ANT_ABC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-                       break;
-               }
-               tbl->action++;
-               if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-
-               if (tbl->action == start_action)
-                       break;
-       }
-       search_tbl->lq_type = LQ_NONE;
-       return 0;
-
- out:
-       lq_sta->search_better_tbl = 1;
-       tbl->action++;
-       if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
-               tbl->action = IWL_SISO_SWITCH_ANTENNA1;
-       if (update_search_tbl_counter)
-               search_tbl->action = tbl->action;
-
-       return 0;
-}
-
-/*
- * Try to switch to new modulation mode from MIMO2
- */
-static int rs_move_mimo2_to_other(struct iwl_priv *priv,
-                                struct iwl_lq_sta *lq_sta,
-                                struct ieee80211_conf *conf,
-                                struct ieee80211_sta *sta, int index)
-{
-       s8 is_green = lq_sta->is_green;
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-       struct iwl_rate_scale_data *window = &(tbl->win[index]);
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action;
-       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-       u8 tx_chains_num = priv->hw_params.tx_chains_num;
-       u8 update_search_tbl_counter = 0;
-       int ret;
-
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               /* nothing */
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               /* avoid antenna B and MIMO */
-               if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
-                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
-                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
-                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-               break;
-       default:
-               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-               break;
-       }
-
-       if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
-           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
-            tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
-               /* switch in SISO */
-               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-       }
-
-       /* configure as 1x1 if bt full concurrency */
-       if (priv->bt_full_concurrent &&
-           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
-            tbl->action > IWL_MIMO2_SWITCH_SISO_C))
-               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
-
-       start_action = tbl->action;
-       for (;;) {
-               lq_sta->action_counter++;
-               switch (tbl->action) {
-               case IWL_MIMO2_SWITCH_ANTENNA1:
-               case IWL_MIMO2_SWITCH_ANTENNA2:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle Antennas\n");
-
-                       if (tx_chains_num <= 2)
-                               break;
-
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
-                               break;
-
-                       memcpy(search_tbl, tbl, sz);
-                       if (rs_toggle_antenna(valid_tx_ant,
-                                      &search_tbl->current_rate, search_tbl)) {
-                               update_search_tbl_counter = 1;
-                               goto out;
-                       }
-                       break;
-               case IWL_MIMO2_SWITCH_SISO_A:
-               case IWL_MIMO2_SWITCH_SISO_B:
-               case IWL_MIMO2_SWITCH_SISO_C:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to SISO\n");
-
-                       /* Set up new search table for SISO */
-                       memcpy(search_tbl, tbl, sz);
-
-                       if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
-                               search_tbl->ant_type = ANT_A;
-                       else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
-                               search_tbl->ant_type = ANT_B;
-                       else
-                               search_tbl->ant_type = ANT_C;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-
-                       break;
-
-               case IWL_MIMO2_SWITCH_GI:
-                       if (!tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_20))
-                               break;
-                       if (tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_40))
-                               break;
-
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 toggle SGI/NGI\n");
-
-                       /* Set up new search table for MIMO2 */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = !tbl->is_SGI;
-                       rs_set_expected_tpt_table(lq_sta, search_tbl);
-                       /*
-                        * If active table already uses the fastest possible
-                        * modulation (dual stream with short guard interval),
-                        * and it's working well, there's no need to look
-                        * for a better type of modulation!
-                        */
-                       if (tbl->is_SGI) {
-                               s32 tpt = lq_sta->last_tpt / 100;
-                               if (tpt >= search_tbl->expected_tpt[index])
-                                       break;
-                       }
-                       search_tbl->current_rate =
-                               rate_n_flags_from_tbl(priv, search_tbl,
-                                                     index, is_green);
-                       update_search_tbl_counter = 1;
-                       goto out;
-
-               case IWL_MIMO2_SWITCH_MIMO3_ABC:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO2 switch to MIMO3\n");
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       search_tbl->ant_type = ANT_ABC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo3(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-
-                       break;
-               }
-               tbl->action++;
-               if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
-                       tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
-
-               if (tbl->action == start_action)
-                       break;
-       }
-       search_tbl->lq_type = LQ_NONE;
-       return 0;
- out:
-       lq_sta->search_better_tbl = 1;
-       tbl->action++;
-       if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
-               tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
-       if (update_search_tbl_counter)
-               search_tbl->action = tbl->action;
-
-       return 0;
-
-}
-
-/*
- * Try to switch to new modulation mode from MIMO3
- */
-static int rs_move_mimo3_to_other(struct iwl_priv *priv,
-                                struct iwl_lq_sta *lq_sta,
-                                struct ieee80211_conf *conf,
-                                struct ieee80211_sta *sta, int index)
-{
-       s8 is_green = lq_sta->is_green;
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-       struct iwl_scale_tbl_info *search_tbl =
-                               &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-       struct iwl_rate_scale_data *window = &(tbl->win[index]);
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-                 (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action;
-       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
-       u8 tx_chains_num = priv->hw_params.tx_chains_num;
-       int ret;
-       u8 update_search_tbl_counter = 0;
-
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-               /* nothing */
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               /* avoid antenna B and MIMO */
-               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
-                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               /* avoid antenna B unless MIMO */
-               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
-                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
-                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-               break;
-       default:
-               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
-               break;
-       }
-
-       if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
-           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
-            tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
-               /* switch in SISO */
-               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-       }
-
-       /* configure as 1x1 if bt full concurrency */
-       if (priv->bt_full_concurrent &&
-           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
-            tbl->action > IWL_MIMO3_SWITCH_SISO_C))
-               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
-
-       start_action = tbl->action;
-       for (;;) {
-               lq_sta->action_counter++;
-               switch (tbl->action) {
-               case IWL_MIMO3_SWITCH_ANTENNA1:
-               case IWL_MIMO3_SWITCH_ANTENNA2:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle Antennas\n");
-
-                       if (tx_chains_num <= 3)
-                               break;
-
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
-                               break;
-
-                       memcpy(search_tbl, tbl, sz);
-                       if (rs_toggle_antenna(valid_tx_ant,
-                                      &search_tbl->current_rate, search_tbl))
-                               goto out;
-                       break;
-               case IWL_MIMO3_SWITCH_SISO_A:
-               case IWL_MIMO3_SWITCH_SISO_B:
-               case IWL_MIMO3_SWITCH_SISO_C:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to SISO\n");
-
-                       /* Set up new search table for SISO */
-                       memcpy(search_tbl, tbl, sz);
-
-                       if (tbl->action == IWL_MIMO3_SWITCH_SISO_A)
-                               search_tbl->ant_type = ANT_A;
-                       else if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
-                               search_tbl->ant_type = ANT_B;
-                       else
-                               search_tbl->ant_type = ANT_C;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-
-                       break;
-
-               case IWL_MIMO3_SWITCH_MIMO2_AB:
-               case IWL_MIMO3_SWITCH_MIMO2_AC:
-               case IWL_MIMO3_SWITCH_MIMO2_BC:
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 switch to MIMO2\n");
-
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = 0;
-                       if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB)
-                               search_tbl->ant_type = ANT_AB;
-                       else if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC)
-                               search_tbl->ant_type = ANT_AC;
-                       else
-                               search_tbl->ant_type = ANT_BC;
-
-                       if (!rs_is_valid_ant(valid_tx_ant, search_tbl->ant_type))
-                               break;
-
-                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
-                                                search_tbl, index);
-                       if (!ret)
-                               goto out;
-
-                       break;
-
-               case IWL_MIMO3_SWITCH_GI:
-                       if (!tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_20))
-                               break;
-                       if (tbl->is_ht40 && !(ht_cap->cap &
-                                               IEEE80211_HT_CAP_SGI_40))
-                               break;
-
-                       IWL_DEBUG_RATE(priv, "LQ: MIMO3 toggle SGI/NGI\n");
-
-                       /* Set up new search table for MIMO */
-                       memcpy(search_tbl, tbl, sz);
-                       search_tbl->is_SGI = !tbl->is_SGI;
-                       rs_set_expected_tpt_table(lq_sta, search_tbl);
-                       /*
-                        * If active table already uses the fastest possible
-                        * modulation (dual stream with short guard interval),
-                        * and it's working well, there's no need to look
-                        * for a better type of modulation!
-                        */
-                       if (tbl->is_SGI) {
-                               s32 tpt = lq_sta->last_tpt / 100;
-                               if (tpt >= search_tbl->expected_tpt[index])
-                                       break;
-                       }
-                       search_tbl->current_rate =
-                               rate_n_flags_from_tbl(priv, search_tbl,
-                                                     index, is_green);
-                       update_search_tbl_counter = 1;
-                       goto out;
-               }
-               tbl->action++;
-               if (tbl->action > IWL_MIMO3_SWITCH_GI)
-                       tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-
-               if (tbl->action == start_action)
-                       break;
-       }
-       search_tbl->lq_type = LQ_NONE;
-       return 0;
- out:
-       lq_sta->search_better_tbl = 1;
-       tbl->action++;
-       if (tbl->action > IWL_MIMO3_SWITCH_GI)
-               tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
-       if (update_search_tbl_counter)
-               search_tbl->action = tbl->action;
-
-       return 0;
-
-}
-
-/*
- * Check whether we should continue using same modulation mode, or
- * begin search for a new mode, based on:
- * 1) # tx successes or failures while using this mode
- * 2) # times calling this function
- * 3) elapsed time in this mode (not used, for now)
- */
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
-{
-       struct iwl_scale_tbl_info *tbl;
-       int i;
-       int active_tbl;
-       int flush_interval_passed = 0;
-       struct iwl_priv *priv;
-
-       priv = lq_sta->drv;
-       active_tbl = lq_sta->active_tbl;
-
-       tbl = &(lq_sta->lq_info[active_tbl]);
-
-       /* If we've been disallowing search, see if we should now allow it */
-       if (lq_sta->stay_in_tbl) {
-
-               /* Elapsed time using current modulation mode */
-               if (lq_sta->flush_timer)
-                       flush_interval_passed =
-                       time_after(jiffies,
-                                       (unsigned long)(lq_sta->flush_timer +
-                                       IWL_RATE_SCALE_FLUSH_INTVL));
-
-               /*
-                * Check if we should allow search for new modulation mode.
-                * If many frames have failed or succeeded, or we've used
-                * this same modulation for a long time, allow search, and
-                * reset history stats that keep track of whether we should
-                * allow a new search.  Also (below) reset all bitmaps and
-                * stats in active history.
-                */
-               if (force_search ||
-                   (lq_sta->total_failed > lq_sta->max_failure_limit) ||
-                   (lq_sta->total_success > lq_sta->max_success_limit) ||
-                   ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
-                    && (flush_interval_passed))) {
-                       IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n",
-                                    lq_sta->total_failed,
-                                    lq_sta->total_success,
-                                    flush_interval_passed);
-
-                       /* Allow search for new mode */
-                       lq_sta->stay_in_tbl = 0;        /* only place reset */
-                       lq_sta->total_failed = 0;
-                       lq_sta->total_success = 0;
-                       lq_sta->flush_timer = 0;
-
-               /*
-                * Else if we've used this modulation mode enough repetitions
-                * (regardless of elapsed time or success/failure), reset
-                * history bitmaps and rate-specific stats for all rates in
-                * active table.
-                */
-               } else {
-                       lq_sta->table_count++;
-                       if (lq_sta->table_count >=
-                           lq_sta->table_count_limit) {
-                               lq_sta->table_count = 0;
-
-                               IWL_DEBUG_RATE(priv, "LQ: stay in table clear win\n");
-                               for (i = 0; i < IWL_RATE_COUNT; i++)
-                                       rs_rate_scale_clear_window(
-                                               &(tbl->win[i]));
-                       }
-               }
-
-               /* If transitioning to allow "search", reset all history
-                * bitmaps and stats in active table (this will become the new
-                * "search" table). */
-               if (!lq_sta->stay_in_tbl) {
-                       for (i = 0; i < IWL_RATE_COUNT; i++)
-                               rs_rate_scale_clear_window(&(tbl->win[i]));
-               }
-       }
-}
-
-/*
- * setup rate table in uCode
- */
-static void rs_update_rate_tbl(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx,
-                              struct iwl_lq_sta *lq_sta,
-                              struct iwl_scale_tbl_info *tbl,
-                              int index, u8 is_green)
-{
-       u32 rate;
-
-       /* Update uCode's rate table. */
-       rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
-       rs_fill_link_cmd(priv, lq_sta, rate);
-       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-}
-
-/*
- * Do rate scaling and search for new modulation mode.
- */
-static void rs_rate_scale_perform(struct iwl_priv *priv,
-                                 struct sk_buff *skb,
-                                 struct ieee80211_sta *sta,
-                                 struct iwl_lq_sta *lq_sta)
-{
-       struct ieee80211_hw *hw = priv->hw;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       int low = IWL_RATE_INVALID;
-       int high = IWL_RATE_INVALID;
-       int index;
-       int i;
-       struct iwl_rate_scale_data *window = NULL;
-       int current_tpt = IWL_INVALID_VALUE;
-       int low_tpt = IWL_INVALID_VALUE;
-       int high_tpt = IWL_INVALID_VALUE;
-       u32 fail_count;
-       s8 scale_action = 0;
-       u16 rate_mask;
-       u8 update_lq = 0;
-       struct iwl_scale_tbl_info *tbl, *tbl1;
-       u16 rate_scale_index_msk = 0;
-       u8 is_green = 0;
-       u8 active_tbl = 0;
-       u8 done_search = 0;
-       u16 high_low;
-       s32 sr;
-       u8 tid = IWL_MAX_TID_COUNT;
-       struct iwl_tid_data *tid_data;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
-
-       /* Send management frames and NO_ACK data using lowest rate. */
-       /* TODO: this could probably be improved.. */
-       if (!ieee80211_is_data(hdr->frame_control) ||
-           info->flags & IEEE80211_TX_CTL_NO_ACK)
-               return;
-
-       lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
-
-       tid = rs_tl_add_packet(lq_sta, hdr);
-       if ((tid != IWL_MAX_TID_COUNT) &&
-           (lq_sta->tx_agg_tid_en & (1 << tid))) {
-               tid_data = &priv->tid_data[lq_sta->lq.sta_id][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
-        * the rest of this function:  "search" if searching for better
-        * modulation mode, or "active" if doing rate scaling within a mode.
-        */
-       if (!lq_sta->search_better_tbl)
-               active_tbl = lq_sta->active_tbl;
-       else
-               active_tbl = 1 - lq_sta->active_tbl;
-
-       tbl = &(lq_sta->lq_info[active_tbl]);
-       if (is_legacy(tbl->lq_type))
-               lq_sta->is_green = 0;
-       else
-               lq_sta->is_green = rs_use_green(sta);
-       is_green = lq_sta->is_green;
-
-       /* current tx rate */
-       index = lq_sta->last_txrate_idx;
-
-       IWL_DEBUG_RATE(priv, "Rate scale index %d for type %d\n", index,
-                      tbl->lq_type);
-
-       /* rates available for this association, and for modulation mode */
-       rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
-
-       IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
-
-       /* mask with station rate restriction */
-       if (is_legacy(tbl->lq_type)) {
-               if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                       /* supp_rates has no CCK bits in A mode */
-                       rate_scale_index_msk = (u16) (rate_mask &
-                               (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
-               else
-                       rate_scale_index_msk = (u16) (rate_mask &
-                                                     lq_sta->supp_rates);
-
-       } else
-               rate_scale_index_msk = rate_mask;
-
-       if (!rate_scale_index_msk)
-               rate_scale_index_msk = rate_mask;
-
-       if (!((1 << index) & rate_scale_index_msk)) {
-               IWL_ERR(priv, "Current Rate is not valid\n");
-               if (lq_sta->search_better_tbl) {
-                       /* revert to active table if search table is not valid*/
-                       tbl->lq_type = LQ_NONE;
-                       lq_sta->search_better_tbl = 0;
-                       tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-                       /* get "active" rate info */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
-                                          index, is_green);
-               }
-               return;
-       }
-
-       /* Get expected throughput table and history window for current rate */
-       if (!tbl->expected_tpt) {
-               IWL_ERR(priv, "tbl->expected_tpt is NULL\n");
-               return;
-       }
-
-       /* force user max rate if set by user */
-       if ((lq_sta->max_rate_idx != -1) &&
-           (lq_sta->max_rate_idx < index)) {
-               index = lq_sta->max_rate_idx;
-               update_lq = 1;
-               window = &(tbl->win[index]);
-               goto lq_update;
-       }
-
-       window = &(tbl->win[index]);
-
-       /*
-        * If there is not enough history to calculate actual average
-        * throughput, keep analyzing results of more tx frames, without
-        * changing rate or mode (bypass most of the rest of this function).
-        * Set up new rate table in uCode only if old rate is not supported
-        * in current association (use new rate found above).
-        */
-       fail_count = window->counter - window->success_counter;
-       if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
-                       (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
-               IWL_DEBUG_RATE(priv, "LQ: still below TH. succ=%d total=%d "
-                              "for index %d\n",
-                              window->success_counter, window->counter, index);
-
-               /* Can't calculate this yet; not enough history */
-               window->average_tpt = IWL_INVALID_VALUE;
-
-               /* Should we stay with this modulation mode,
-                * or search for a new one? */
-               rs_stay_in_table(lq_sta, false);
-
-               goto out;
-       }
-       /* Else we have enough samples; calculate estimate of
-        * actual average throughput */
-       if (window->average_tpt != ((window->success_ratio *
-                       tbl->expected_tpt[index] + 64) / 128)) {
-               IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
-               window->average_tpt = ((window->success_ratio *
-                                       tbl->expected_tpt[index] + 64) / 128);
-       }
-
-       /* If we are searching for better modulation mode, check success. */
-       if (lq_sta->search_better_tbl &&
-           (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI)) {
-               /* If good success, continue using the "search" mode;
-                * no need to send new link quality command, since we're
-                * continuing to use the setup that we've been trying. */
-               if (window->average_tpt > lq_sta->last_tpt) {
-
-                       IWL_DEBUG_RATE(priv, "LQ: SWITCHING TO NEW TABLE "
-                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
-                                       window->success_ratio,
-                                       window->average_tpt,
-                                       lq_sta->last_tpt);
-
-                       if (!is_legacy(tbl->lq_type))
-                               lq_sta->enable_counter = 1;
-
-                       /* Swap tables; "search" becomes "active" */
-                       lq_sta->active_tbl = active_tbl;
-                       current_tpt = window->average_tpt;
-
-               /* Else poor success; go back to mode in "active" table */
-               } else {
-
-                       IWL_DEBUG_RATE(priv, "LQ: GOING BACK TO THE OLD TABLE "
-                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
-                                       window->success_ratio,
-                                       window->average_tpt,
-                                       lq_sta->last_tpt);
-
-                       /* Nullify "search" table */
-                       tbl->lq_type = LQ_NONE;
-
-                       /* Revert to "active" table */
-                       active_tbl = lq_sta->active_tbl;
-                       tbl = &(lq_sta->lq_info[active_tbl]);
-
-                       /* Revert to "active" rate and throughput info */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       current_tpt = lq_sta->last_tpt;
-
-                       /* Need to set up a new rate table in uCode */
-                       update_lq = 1;
-               }
-
-               /* Either way, we've made a decision; modulation mode
-                * search is done, allow rate adjustment next time. */
-               lq_sta->search_better_tbl = 0;
-               done_search = 1;        /* Don't switch modes below! */
-               goto lq_update;
-       }
-
-       /* (Else) not in search of better modulation mode, try for better
-        * starting rate, while staying in this mode. */
-       high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
-                                       tbl->lq_type);
-       low = high_low & 0xff;
-       high = (high_low >> 8) & 0xff;
-
-       /* If user set max rate, dont allow higher than user constrain */
-       if ((lq_sta->max_rate_idx != -1) &&
-           (lq_sta->max_rate_idx < high))
-               high = IWL_RATE_INVALID;
-
-       sr = window->success_ratio;
-
-       /* Collect measured throughputs for current and adjacent rates */
-       current_tpt = window->average_tpt;
-       if (low != IWL_RATE_INVALID)
-               low_tpt = tbl->win[low].average_tpt;
-       if (high != IWL_RATE_INVALID)
-               high_tpt = tbl->win[high].average_tpt;
-
-       scale_action = 0;
-
-       /* Too many failures, decrease rate */
-       if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
-               IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
-               scale_action = -1;
-
-       /* No throughput measured yet for adjacent rates; try increase. */
-       } else if ((low_tpt == IWL_INVALID_VALUE) &&
-                  (high_tpt == IWL_INVALID_VALUE)) {
-
-               if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
-                       scale_action = 1;
-               else if (low != IWL_RATE_INVALID)
-                       scale_action = 0;
-       }
-
-       /* Both adjacent throughputs are measured, but neither one has better
-        * throughput; we're using the best rate, don't change it! */
-       else if ((low_tpt != IWL_INVALID_VALUE) &&
-                (high_tpt != IWL_INVALID_VALUE) &&
-                (low_tpt < current_tpt) &&
-                (high_tpt < current_tpt))
-               scale_action = 0;
-
-       /* At least one adjacent rate's throughput is measured,
-        * and may have better performance. */
-       else {
-               /* Higher adjacent rate's throughput is measured */
-               if (high_tpt != IWL_INVALID_VALUE) {
-                       /* Higher rate has better throughput */
-                       if (high_tpt > current_tpt &&
-                                       sr >= IWL_RATE_INCREASE_TH) {
-                               scale_action = 1;
-                       } else {
-                               scale_action = 0;
-                       }
-
-               /* Lower adjacent rate's throughput is measured */
-               } else if (low_tpt != IWL_INVALID_VALUE) {
-                       /* Lower rate has better throughput */
-                       if (low_tpt > current_tpt) {
-                               IWL_DEBUG_RATE(priv,
-                                   "decrease rate because of low tpt\n");
-                               scale_action = -1;
-                       } else if (sr >= IWL_RATE_INCREASE_TH) {
-                               scale_action = 1;
-                       }
-               }
-       }
-
-       /* Sanity check; asked for decrease, but success rate or throughput
-        * has been good at old rate.  Don't change it. */
-       if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
-                   ((sr > IWL_RATE_HIGH_TH) ||
-                    (current_tpt > (100 * tbl->expected_tpt[low]))))
-               scale_action = 0;
-       if (!iwl_ht_enabled(priv) && !is_legacy(tbl->lq_type))
-               scale_action = -1;
-       if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
-               (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
-               scale_action = -1;
-
-       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
-               if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
-                       /*
-                        * don't set scale_action, don't want to scale up if
-                        * the rate scale doesn't otherwise think that is a
-                        * good idea.
-                        */
-               } else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
-                       scale_action = -1;
-               }
-       }
-       lq_sta->last_bt_traffic = priv->bt_traffic_load;
-
-       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
-            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
-               /* search for a new modulation */
-               rs_stay_in_table(lq_sta, true);
-               goto lq_update;
-       }
-
-       switch (scale_action) {
-       case -1:
-               /* Decrease starting rate, update uCode's rate table */
-               if (low != IWL_RATE_INVALID) {
-                       update_lq = 1;
-                       index = low;
-               }
-
-               break;
-       case 1:
-               /* Increase starting rate, update uCode's rate table */
-               if (high != IWL_RATE_INVALID) {
-                       update_lq = 1;
-                       index = high;
-               }
-
-               break;
-       case 0:
-               /* No change */
-       default:
-               break;
-       }
-
-       IWL_DEBUG_RATE(priv, "choose rate scale index %d action %d low %d "
-                   "high %d type %d\n",
-                    index, scale_action, low, high, tbl->lq_type);
-
-lq_update:
-       /* Replace uCode's rate table for the destination station. */
-       if (update_lq)
-               rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
-
-       if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
-               /* Should we stay with this modulation mode,
-                * or search for a new one? */
-         rs_stay_in_table(lq_sta, false);
-       }
-       /*
-        * Search for new modulation mode if we're:
-        * 1)  Not changing rates right now
-        * 2)  Not just finishing up a search
-        * 3)  Allowing a new search
-        */
-       if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
-               /* Save current throughput to compare with "search" throughput*/
-               lq_sta->last_tpt = current_tpt;
-
-               /* Select a new "search" modulation mode to try.
-                * If one is found, set up the new "search" table. */
-               if (is_legacy(tbl->lq_type))
-                       rs_move_legacy_other(priv, lq_sta, conf, sta, index);
-               else if (is_siso(tbl->lq_type))
-                       rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
-               else if (is_mimo2(tbl->lq_type))
-                       rs_move_mimo2_to_other(priv, lq_sta, conf, sta, index);
-               else
-                       rs_move_mimo3_to_other(priv, lq_sta, conf, sta, index);
-
-               /* If new "search" mode was selected, set up in uCode table */
-               if (lq_sta->search_better_tbl) {
-                       /* Access the "search" table, clear its history. */
-                       tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
-                       for (i = 0; i < IWL_RATE_COUNT; i++)
-                               rs_rate_scale_clear_window(&(tbl->win[i]));
-
-                       /* Use new "search" start rate */
-                       index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-
-                       IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
-                                    tbl->current_rate, index);
-                       rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-               } else
-                       done_search = 1;
-       }
-
-       if (done_search && !lq_sta->stay_in_tbl) {
-               /* If the "active" (non-search) mode was legacy,
-                * and we've tried switching antennas,
-                * but we haven't been able to try HT modes (not available),
-                * stay with best antenna legacy modulation for a while
-                * before next round of mode comparisons. */
-               tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
-               if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
-                   lq_sta->action_counter > tbl1->max_search) {
-                       IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
-                       rs_set_stay_in_table(priv, 1, lq_sta);
-               }
-
-               /* If we're in an HT mode, and all 3 mode switch actions
-                * have been tried and compared, stay in this best modulation
-                * mode for a while before next round of mode comparisons. */
-               if (lq_sta->enable_counter &&
-                   (lq_sta->action_counter >= tbl1->max_search) &&
-                   iwl_ht_enabled(priv)) {
-                       if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
-                           (lq_sta->tx_agg_tid_en & (1 << tid)) &&
-                           (tid != IWL_MAX_TID_COUNT)) {
-                               u8 sta_id = lq_sta->lq.sta_id;
-                               tid_data = &priv->tid_data[sta_id][tid];
-                               if (tid_data->agg.state == IWL_AGG_OFF) {
-                                       IWL_DEBUG_RATE(priv,
-                                                      "try to aggregate tid %d\n",
-                                                      tid);
-                                       rs_tl_turn_on_agg(priv, tid,
-                                                         lq_sta, sta);
-                               }
-                       }
-                       rs_set_stay_in_table(priv, 0, lq_sta);
-               }
-       }
-
-out:
-       tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
-       lq_sta->last_txrate_idx = index;
-}
-
-/**
- * rs_initialize_lq - Initialize a station's hardware rate table
- *
- * The uCode's station table contains a table of fallback rates
- * for automatic fallback during transmission.
- *
- * NOTE: This sets up a default set of values.  These will be replaced later
- *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
- *       rc80211_simple.
- *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- *       which requires station table entry to exist).
- */
-static void rs_initialize_lq(struct iwl_priv *priv,
-                            struct ieee80211_sta *sta,
-                            struct iwl_lq_sta *lq_sta)
-{
-       struct iwl_scale_tbl_info *tbl;
-       int rate_idx;
-       int i;
-       u32 rate;
-       u8 use_green = rs_use_green(sta);
-       u8 active_tbl = 0;
-       u8 valid_tx_ant;
-       struct iwl_station_priv *sta_priv;
-       struct iwl_rxon_context *ctx;
-
-       if (!sta || !lq_sta)
-               return;
-
-       sta_priv = (void *)sta->drv_priv;
-       ctx = sta_priv->ctx;
-
-       i = lq_sta->last_txrate_idx;
-
-       valid_tx_ant = priv->hw_params.valid_tx_ant;
-
-       if (!lq_sta->search_better_tbl)
-               active_tbl = lq_sta->active_tbl;
-       else
-               active_tbl = 1 - lq_sta->active_tbl;
-
-       tbl = &(lq_sta->lq_info[active_tbl]);
-
-       if ((i < 0) || (i >= IWL_RATE_COUNT))
-               i = 0;
-
-       rate = iwl_rates[i].plcp;
-       tbl->ant_type = first_antenna(valid_tx_ant);
-       rate |= tbl->ant_type << RATE_MCS_ANT_POS;
-
-       if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
-               rate |= RATE_MCS_CCK_MSK;
-
-       rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
-       if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
-           rs_toggle_antenna(valid_tx_ant, &rate, tbl);
-
-       rate = rate_n_flags_from_tbl(priv, tbl, rate_idx, use_green);
-       tbl->current_rate = rate;
-       rs_set_expected_tpt_table(lq_sta, tbl);
-       rs_fill_link_cmd(NULL, lq_sta, rate);
-       priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
-       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
-}
-
-static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
-                       struct ieee80211_tx_rate_control *txrc)
-{
-
-       struct sk_buff *skb = txrc->skb;
-       struct ieee80211_supported_band *sband = txrc->sband;
-       struct iwl_op_mode *op_mode __maybe_unused =
-                       (struct iwl_op_mode *)priv_r;
-       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct iwl_lq_sta *lq_sta = priv_sta;
-       int rate_idx;
-
-       IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
-
-       /* Get max rate if user set max rate */
-       if (lq_sta) {
-               lq_sta->max_rate_idx = txrc->max_rate_idx;
-               if ((sband->band == IEEE80211_BAND_5GHZ) &&
-                   (lq_sta->max_rate_idx != -1))
-                       lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
-               if ((lq_sta->max_rate_idx < 0) ||
-                   (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
-                       lq_sta->max_rate_idx = -1;
-       }
-
-       /* Treat uninitialized rate scaling data same as non-existing. */
-       if (lq_sta && !lq_sta->drv) {
-               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
-               priv_sta = NULL;
-       }
-
-       /* Send management frames and NO_ACK data using lowest rate. */
-       if (rate_control_send_low(sta, priv_sta, txrc))
-               return;
-
-       rate_idx  = lq_sta->last_txrate_idx;
-
-       if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
-               rate_idx -= IWL_FIRST_OFDM_RATE;
-               /* 6M and 9M shared same MCS index */
-               rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
-               if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-                   IWL_RATE_MIMO3_6M_PLCP)
-                       rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
-               else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
-                        IWL_RATE_MIMO2_6M_PLCP)
-                       rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
-               info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
-               if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
-                       info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
-               if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
-                       info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
-               if (lq_sta->last_rate_n_flags & RATE_MCS_HT40_MSK)
-                       info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-               if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
-                       info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
-       } else {
-               /* Check for invalid rates */
-               if ((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT_LEGACY) ||
-                               ((sband->band == IEEE80211_BAND_5GHZ) &&
-                                (rate_idx < IWL_FIRST_OFDM_RATE)))
-                       rate_idx = rate_lowest_index(sband, sta);
-               /* On valid 5 GHz rate, adjust index */
-               else if (sband->band == IEEE80211_BAND_5GHZ)
-                       rate_idx -= IWL_FIRST_OFDM_RATE;
-               info->control.rates[0].flags = 0;
-       }
-       info->control.rates[0].idx = rate_idx;
-
-}
-
-static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
-                         gfp_t gfp)
-{
-       struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-       struct iwl_op_mode *op_mode __maybe_unused =
-                       (struct iwl_op_mode *)priv_rate;
-       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-
-       IWL_DEBUG_RATE(priv, "create station rate scale window\n");
-
-       return &sta_priv->lq_sta;
-}
-
-/*
- * Called after adding a new station to initialize rate scaling
- */
-void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
-{
-       int i, j;
-       struct ieee80211_hw *hw = priv->hw;
-       struct ieee80211_conf *conf = &priv->hw->conf;
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       struct iwl_station_priv *sta_priv;
-       struct iwl_lq_sta *lq_sta;
-       struct ieee80211_supported_band *sband;
-       unsigned long supp; /* must be unsigned long for for_each_set_bit */
-
-       sta_priv = (struct iwl_station_priv *) sta->drv_priv;
-       lq_sta = &sta_priv->lq_sta;
-       sband = hw->wiphy->bands[conf->channel->band];
-
-
-       lq_sta->lq.sta_id = sta_id;
-
-       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]);
-
-       lq_sta->flush_timer = 0;
-       lq_sta->supp_rates = sta->supp_rates[sband->band];
-       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]);
-
-       IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n",
-                      sta_id);
-       /* TODO: what is a good starting rate for STA? About middle? Maybe not
-        * the lowest or the highest rate.. Could consider using RSSI from
-        * previous packets? Need to have IEEE 802.1X auth succeed immediately
-        * after assoc.. */
-
-       lq_sta->is_dup = 0;
-       lq_sta->max_rate_idx = -1;
-       lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
-       lq_sta->is_green = rs_use_green(sta);
-       lq_sta->band = sband->band;
-       /*
-        * active legacy rates as per supported rates bitmap
-        */
-       supp = sta->supp_rates[sband->band];
-       lq_sta->active_legacy_rate = 0;
-       for_each_set_bit(i, &supp, BITS_PER_LONG)
-               lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
-
-       /*
-        * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
-        * supp_rates[] does not; shift to convert format, force 9 MBits off.
-        */
-       lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
-       lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
-       lq_sta->active_siso_rate &= ~((u16)0x2);
-       lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
-
-       /* Same here */
-       lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
-       lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
-       lq_sta->active_mimo2_rate &= ~((u16)0x2);
-       lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
-
-       lq_sta->active_mimo3_rate = ht_cap->mcs.rx_mask[2] << 1;
-       lq_sta->active_mimo3_rate |= ht_cap->mcs.rx_mask[2] & 0x1;
-       lq_sta->active_mimo3_rate &= ~((u16)0x2);
-       lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
-
-       IWL_DEBUG_RATE(priv, "SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
-                    lq_sta->active_siso_rate,
-                    lq_sta->active_mimo2_rate,
-                    lq_sta->active_mimo3_rate);
-
-       /* These values will be overridden later */
-       lq_sta->lq.general_params.single_stream_ant_msk =
-               first_antenna(priv->hw_params.valid_tx_ant);
-       lq_sta->lq.general_params.dual_stream_ant_msk =
-               priv->hw_params.valid_tx_ant &
-               ~first_antenna(priv->hw_params.valid_tx_ant);
-       if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
-               lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
-       } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
-               lq_sta->lq.general_params.dual_stream_ant_msk =
-                       priv->hw_params.valid_tx_ant;
-       }
-
-       /* as default allow aggregation for all tids */
-       lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-       lq_sta->drv = priv;
-
-       /* Set last_txrate_idx to lowest rate */
-       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;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-       priv->tm_fixed_rate = 0;
-#endif
-#ifdef CONFIG_MAC80211_DEBUGFS
-       lq_sta->dbg_fixed_rate = 0;
-#endif
-
-       rs_initialize_lq(priv, sta, lq_sta);
-}
-
-static void rs_fill_link_cmd(struct iwl_priv *priv,
-                            struct iwl_lq_sta *lq_sta, u32 new_rate)
-{
-       struct iwl_scale_tbl_info tbl_type;
-       int index = 0;
-       int rate_idx;
-       int repeat_rate = 0;
-       u8 ant_toggle_cnt = 0;
-       u8 use_ht_possible = 1;
-       u8 valid_tx_ant = 0;
-       struct iwl_station_priv *sta_priv =
-               container_of(lq_sta, struct iwl_station_priv, lq_sta);
-       struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
-
-       /* Override starting rate (index 0) if needed for debug purposes */
-       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-       /* Interpret new_rate (rate_n_flags) */
-       rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
-                                 &tbl_type, &rate_idx);
-
-       if (priv && priv->bt_full_concurrent) {
-               /* 1x1 only */
-               tbl_type.ant_type =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-       }
-
-       /* How many times should we repeat the initial rate? */
-       if (is_legacy(tbl_type.lq_type)) {
-               ant_toggle_cnt = 1;
-               repeat_rate = IWL_NUMBER_TRY;
-       } else {
-               repeat_rate = min(IWL_HT_NUMBER_TRY,
-                                 LINK_QUAL_AGG_DISABLE_START_DEF - 1);
-       }
-
-       lq_cmd->general_params.mimo_delimiter =
-                       is_mimo(tbl_type.lq_type) ? 1 : 0;
-
-       /* Fill 1st table entry (index 0) */
-       lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
-
-       if (num_of_ant(tbl_type.ant_type) == 1) {
-               lq_cmd->general_params.single_stream_ant_msk =
-                                               tbl_type.ant_type;
-       } else if (num_of_ant(tbl_type.ant_type) == 2) {
-               lq_cmd->general_params.dual_stream_ant_msk =
-                                               tbl_type.ant_type;
-       } /* otherwise we don't modify the existing value */
-
-       index++;
-       repeat_rate--;
-       if (priv) {
-               if (priv->bt_full_concurrent)
-                       valid_tx_ant = ANT_A;
-               else
-                       valid_tx_ant = priv->hw_params.valid_tx_ant;
-       }
-
-       /* Fill rest of rate table */
-       while (index < LINK_QUAL_MAX_RETRY_NUM) {
-               /* Repeat initial/next rate.
-                * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
-                * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
-               while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
-                       if (is_legacy(tbl_type.lq_type)) {
-                               if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-                                       ant_toggle_cnt++;
-                               else if (priv &&
-                                        rs_toggle_antenna(valid_tx_ant,
-                                                       &new_rate, &tbl_type))
-                                       ant_toggle_cnt = 1;
-                       }
-
-                       /* Override next rate if needed for debug purposes */
-                       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-                       /* Fill next table entry */
-                       lq_cmd->rs_table[index].rate_n_flags =
-                                       cpu_to_le32(new_rate);
-                       repeat_rate--;
-                       index++;
-               }
-
-               rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
-                                               &rate_idx);
-
-               if (priv && priv->bt_full_concurrent) {
-                       /* 1x1 only */
-                       tbl_type.ant_type =
-                           first_antenna(priv->hw_params.valid_tx_ant);
-               }
-
-               /* Indicate to uCode which entries might be MIMO.
-                * If initial rate was MIMO, this will finally end up
-                * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
-               if (is_mimo(tbl_type.lq_type))
-                       lq_cmd->general_params.mimo_delimiter = index;
-
-               /* Get next rate */
-               new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
-                                            use_ht_possible);
-
-               /* How many times should we repeat the next rate? */
-               if (is_legacy(tbl_type.lq_type)) {
-                       if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
-                               ant_toggle_cnt++;
-                       else if (priv &&
-                                rs_toggle_antenna(valid_tx_ant,
-                                                  &new_rate, &tbl_type))
-                               ant_toggle_cnt = 1;
-
-                       repeat_rate = IWL_NUMBER_TRY;
-               } else {
-                       repeat_rate = IWL_HT_NUMBER_TRY;
-               }
-
-               /* Don't allow HT rates after next pass.
-                * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
-               use_ht_possible = 0;
-
-               /* Override next rate if needed for debug purposes */
-               rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
-
-               /* Fill next table entry */
-               lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
-
-               index++;
-               repeat_rate--;
-       }
-
-       lq_cmd->agg_params.agg_frame_cnt_limit =
-               sta_priv->max_agg_bufsize ?: 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);
-       /*
-        * overwrite if needed, pass aggregation time limit
-        * to uCode in uSec
-        */
-       if (priv && priv->cfg->bt_params &&
-           priv->cfg->bt_params->agg_time_limit &&
-           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
-               lq_cmd->agg_params.agg_time_limit =
-                       cpu_to_le16(priv->cfg->bt_params->agg_time_limit);
-}
-
-static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
-{
-       return hw->priv;
-}
-/* rate scale requires free function to be implemented */
-static void rs_free(void *priv_rate)
-{
-       return;
-}
-
-static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
-                       void *priv_sta)
-{
-       struct iwl_op_mode *op_mode __maybe_unused = priv_r;
-       struct iwl_priv *priv __maybe_unused = IWL_OP_MODE_GET_DVM(op_mode);
-
-       IWL_DEBUG_RATE(priv, "enter\n");
-       IWL_DEBUG_RATE(priv, "leave\n");
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
-                            u32 *rate_n_flags, int index)
-{
-       struct iwl_priv *priv;
-       u8 valid_tx_ant;
-       u8 ant_sel_tx;
-
-       priv = lq_sta->drv;
-       valid_tx_ant = priv->hw_params.valid_tx_ant;
-       if (lq_sta->dbg_fixed_rate) {
-               ant_sel_tx =
-                 ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
-                 >> RATE_MCS_ANT_POS);
-               if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
-                       *rate_n_flags = lq_sta->dbg_fixed_rate;
-                       IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
-               } else {
-                       lq_sta->dbg_fixed_rate = 0;
-                       IWL_ERR(priv,
-                           "Invalid antenna selection 0x%X, Valid is 0x%X\n",
-                           ant_sel_tx, valid_tx_ant);
-                       IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
-               }
-       } else {
-               IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
-       }
-}
-
-static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
-                       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_priv *priv;
-       char buf[64];
-       size_t buf_size;
-       u32 parsed_rate;
-
-
-       priv = lq_sta->drv;
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       if (sscanf(buf, "%x", &parsed_rate) == 1)
-               lq_sta->dbg_fixed_rate = parsed_rate;
-       else
-               lq_sta->dbg_fixed_rate = 0;
-
-       rs_program_fix_rate(priv, lq_sta);
-
-       return count;
-}
-
-static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
-                       char __user *user_buf, size_t count, loff_t *ppos)
-{
-       char *buff;
-       int desc = 0;
-       int i = 0;
-       int index = 0;
-       ssize_t ret;
-
-       struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_priv *priv;
-       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-
-       priv = lq_sta->drv;
-       buff = kmalloc(1024, GFP_KERNEL);
-       if (!buff)
-               return -ENOMEM;
-
-       desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
-       desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
-                       lq_sta->total_failed, lq_sta->total_success,
-                       lq_sta->active_legacy_rate);
-       desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-                       lq_sta->dbg_fixed_rate);
-       desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
-           (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
-           (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
-           (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
-       desc += sprintf(buff+desc, "lq type %s\n",
-          (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
-       if (is_Ht(tbl->lq_type)) {
-               desc += sprintf(buff+desc, " %s",
-                  (is_siso(tbl->lq_type)) ? "SISO" :
-                  ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
-                  desc += sprintf(buff+desc, " %s",
-                  (tbl->is_ht40) ? "40MHz" : "20MHz");
-                  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);
-       desc += sprintf(buff+desc, "general:"
-               "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
-               lq_sta->lq.general_params.flags,
-               lq_sta->lq.general_params.mimo_delimiter,
-               lq_sta->lq.general_params.single_stream_ant_msk,
-               lq_sta->lq.general_params.dual_stream_ant_msk);
-
-       desc += sprintf(buff+desc, "agg:"
-                       "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
-                       le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
-                       lq_sta->lq.agg_params.agg_dis_start_th,
-                       lq_sta->lq.agg_params.agg_frame_cnt_limit);
-
-       desc += sprintf(buff+desc,
-                       "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
-                       lq_sta->lq.general_params.start_rate_index[0],
-                       lq_sta->lq.general_params.start_rate_index[1],
-                       lq_sta->lq.general_params.start_rate_index[2],
-                       lq_sta->lq.general_params.start_rate_index[3]);
-
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               index = iwl_hwrate_to_plcp_idx(
-                       le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
-               if (is_legacy(tbl->lq_type)) {
-                       desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
-                               i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
-                               iwl_rate_mcs[index].mbps);
-               } else {
-                       desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps (%s)\n",
-                               i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
-                               iwl_rate_mcs[index].mbps, iwl_rate_mcs[index].mcs);
-               }
-       }
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-       kfree(buff);
-       return ret;
-}
-
-static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
-       .write = rs_sta_dbgfs_scale_table_write,
-       .read = rs_sta_dbgfs_scale_table_read,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
-                       char __user *user_buf, size_t count, loff_t *ppos)
-{
-       char *buff;
-       int desc = 0;
-       int i, j;
-       ssize_t ret;
-
-       struct iwl_lq_sta *lq_sta = file->private_data;
-
-       buff = kmalloc(1024, GFP_KERNEL);
-       if (!buff)
-               return -ENOMEM;
-
-       for (i = 0; i < LQ_SIZE; i++) {
-               desc += sprintf(buff+desc,
-                               "%s type=%d SGI=%d HT40=%d DUP=%d GF=%d\n"
-                               "rate=0x%X\n",
-                               lq_sta->active_tbl == i ? "*" : "x",
-                               lq_sta->lq_info[i].lq_type,
-                               lq_sta->lq_info[i].is_SGI,
-                               lq_sta->lq_info[i].is_ht40,
-                               lq_sta->lq_info[i].is_dup,
-                               lq_sta->is_green,
-                               lq_sta->lq_info[i].current_rate);
-               for (j = 0; j < IWL_RATE_COUNT; j++) {
-                       desc += sprintf(buff+desc,
-                               "counter=%d success=%d %%=%d\n",
-                               lq_sta->lq_info[i].win[j].counter,
-                               lq_sta->lq_info[i].win[j].success_counter,
-                               lq_sta->lq_info[i].win[j].success_ratio);
-               }
-       }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-       kfree(buff);
-       return ret;
-}
-
-static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
-       .read = rs_sta_dbgfs_stats_table_read,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
-                       char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-       char buff[120];
-       int desc = 0;
-
-       if (is_Ht(tbl->lq_type))
-               desc += sprintf(buff+desc,
-                               "Bit Rate= %d Mb/s\n",
-                               tbl->expected_tpt[lq_sta->last_txrate_idx]);
-       else
-               desc += sprintf(buff+desc,
-                               "Bit Rate= %d Mb/s\n",
-                               iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
-}
-
-static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
-       .read = rs_sta_dbgfs_rate_scale_data_read,
-       .open = simple_open,
-       .llseek = default_llseek,
-};
-
-static void rs_add_debugfs(void *priv, void *priv_sta,
-                                       struct dentry *dir)
-{
-       struct iwl_lq_sta *lq_sta = priv_sta;
-       lq_sta->rs_sta_dbgfs_scale_table_file =
-               debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
-                               lq_sta, &rs_sta_dbgfs_scale_table_ops);
-       lq_sta->rs_sta_dbgfs_stats_table_file =
-               debugfs_create_file("rate_stats_table", S_IRUSR, dir,
-                       lq_sta, &rs_sta_dbgfs_stats_table_ops);
-       lq_sta->rs_sta_dbgfs_rate_scale_data_file =
-               debugfs_create_file("rate_scale_data", S_IRUSR, dir,
-                       lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
-       lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
-               debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir,
-               &lq_sta->tx_agg_tid_en);
-
-}
-
-static void rs_remove_debugfs(void *priv, void *priv_sta)
-{
-       struct iwl_lq_sta *lq_sta = priv_sta;
-       debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
-       debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
-       debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
-       debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
-}
-#endif
-
-/*
- * Initialization of rate scaling information is done by driver after
- * the station is added. Since mac80211 calls this function before a
- * station is added we ignore it.
- */
-static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta)
-{
-}
-static struct rate_control_ops rs_ops = {
-       .module = NULL,
-       .name = RS_NAME,
-       .tx_status = rs_tx_status,
-       .get_rate = rs_get_rate,
-       .rate_init = rs_rate_init_stub,
-       .alloc = rs_alloc,
-       .free = rs_free,
-       .alloc_sta = rs_alloc_sta,
-       .free_sta = rs_free_sta,
-#ifdef CONFIG_MAC80211_DEBUGFS
-       .add_sta_debugfs = rs_add_debugfs,
-       .remove_sta_debugfs = rs_remove_debugfs,
-#endif
-};
-
-int iwlagn_rate_control_register(void)
-{
-       return ieee80211_rate_control_register(&rs_ops);
-}
-
-void iwlagn_rate_control_unregister(void)
-{
-       ieee80211_rate_control_unregister(&rs_ops);
-}
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
deleted file mode 100644 (file)
index 82d02e1..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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_rs_h__
-#define __iwl_agn_rs_h__
-
-#include <net/mac80211.h>
-
-#include "iwl-commands.h"
-#include "iwl-config.h"
-
-struct iwl_rate_info {
-       u8 plcp;        /* uCode API:  IWL_RATE_6M_PLCP, etc. */
-       u8 plcp_siso;   /* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
-       u8 plcp_mimo2;  /* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
-       u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
-       u8 ieee;        /* MAC header:  IWL_RATE_6M_IEEE, etc. */
-       u8 prev_ieee;    /* previous rate in IEEE speeds */
-       u8 next_ieee;    /* next rate in IEEE speeds */
-       u8 prev_rs;      /* previous rate used in rs algo */
-       u8 next_rs;      /* next rate used in rs algo */
-       u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
-       u8 next_rs_tgg;  /* next rate used in TGG rs algo */
-};
-
-/*
- * These serve as indexes into
- * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
- */
-enum {
-       IWL_RATE_1M_INDEX = 0,
-       IWL_RATE_2M_INDEX,
-       IWL_RATE_5M_INDEX,
-       IWL_RATE_11M_INDEX,
-       IWL_RATE_6M_INDEX,
-       IWL_RATE_9M_INDEX,
-       IWL_RATE_12M_INDEX,
-       IWL_RATE_18M_INDEX,
-       IWL_RATE_24M_INDEX,
-       IWL_RATE_36M_INDEX,
-       IWL_RATE_48M_INDEX,
-       IWL_RATE_54M_INDEX,
-       IWL_RATE_60M_INDEX,
-       IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
-       IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1,     /* Excluding 60M */
-       IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
-       IWL_RATE_INVALID = IWL_RATE_COUNT,
-};
-
-enum {
-       IWL_RATE_6M_INDEX_TABLE = 0,
-       IWL_RATE_9M_INDEX_TABLE,
-       IWL_RATE_12M_INDEX_TABLE,
-       IWL_RATE_18M_INDEX_TABLE,
-       IWL_RATE_24M_INDEX_TABLE,
-       IWL_RATE_36M_INDEX_TABLE,
-       IWL_RATE_48M_INDEX_TABLE,
-       IWL_RATE_54M_INDEX_TABLE,
-       IWL_RATE_1M_INDEX_TABLE,
-       IWL_RATE_2M_INDEX_TABLE,
-       IWL_RATE_5M_INDEX_TABLE,
-       IWL_RATE_11M_INDEX_TABLE,
-       IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1,
-};
-
-enum {
-       IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
-       IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
-       IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
-       IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
-};
-
-/* #define vs. enum to keep from defaulting to 'large integer' */
-#define        IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
-#define        IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
-#define        IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
-#define        IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
-#define        IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
-#define        IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
-#define        IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
-#define        IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
-#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
-#define        IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
-#define        IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
-#define        IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
-#define        IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
-
-/* uCode API values for legacy bit rates, both OFDM and CCK */
-enum {
-       IWL_RATE_6M_PLCP  = 13,
-       IWL_RATE_9M_PLCP  = 15,
-       IWL_RATE_12M_PLCP = 5,
-       IWL_RATE_18M_PLCP = 7,
-       IWL_RATE_24M_PLCP = 9,
-       IWL_RATE_36M_PLCP = 11,
-       IWL_RATE_48M_PLCP = 1,
-       IWL_RATE_54M_PLCP = 3,
-       IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
-       IWL_RATE_1M_PLCP  = 10,
-       IWL_RATE_2M_PLCP  = 20,
-       IWL_RATE_5M_PLCP  = 55,
-       IWL_RATE_11M_PLCP = 110,
-       /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */
-       /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
-};
-
-/* uCode API values for OFDM high-throughput (HT) bit rates */
-enum {
-       IWL_RATE_SISO_6M_PLCP = 0,
-       IWL_RATE_SISO_12M_PLCP = 1,
-       IWL_RATE_SISO_18M_PLCP = 2,
-       IWL_RATE_SISO_24M_PLCP = 3,
-       IWL_RATE_SISO_36M_PLCP = 4,
-       IWL_RATE_SISO_48M_PLCP = 5,
-       IWL_RATE_SISO_54M_PLCP = 6,
-       IWL_RATE_SISO_60M_PLCP = 7,
-       IWL_RATE_MIMO2_6M_PLCP  = 0x8,
-       IWL_RATE_MIMO2_12M_PLCP = 0x9,
-       IWL_RATE_MIMO2_18M_PLCP = 0xa,
-       IWL_RATE_MIMO2_24M_PLCP = 0xb,
-       IWL_RATE_MIMO2_36M_PLCP = 0xc,
-       IWL_RATE_MIMO2_48M_PLCP = 0xd,
-       IWL_RATE_MIMO2_54M_PLCP = 0xe,
-       IWL_RATE_MIMO2_60M_PLCP = 0xf,
-       IWL_RATE_MIMO3_6M_PLCP  = 0x10,
-       IWL_RATE_MIMO3_12M_PLCP = 0x11,
-       IWL_RATE_MIMO3_18M_PLCP = 0x12,
-       IWL_RATE_MIMO3_24M_PLCP = 0x13,
-       IWL_RATE_MIMO3_36M_PLCP = 0x14,
-       IWL_RATE_MIMO3_48M_PLCP = 0x15,
-       IWL_RATE_MIMO3_54M_PLCP = 0x16,
-       IWL_RATE_MIMO3_60M_PLCP = 0x17,
-       IWL_RATE_SISO_INVM_PLCP,
-       IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
-       IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
-};
-
-/* MAC header values for bit rates */
-enum {
-       IWL_RATE_6M_IEEE  = 12,
-       IWL_RATE_9M_IEEE  = 18,
-       IWL_RATE_12M_IEEE = 24,
-       IWL_RATE_18M_IEEE = 36,
-       IWL_RATE_24M_IEEE = 48,
-       IWL_RATE_36M_IEEE = 72,
-       IWL_RATE_48M_IEEE = 96,
-       IWL_RATE_54M_IEEE = 108,
-       IWL_RATE_60M_IEEE = 120,
-       IWL_RATE_1M_IEEE  = 2,
-       IWL_RATE_2M_IEEE  = 4,
-       IWL_RATE_5M_IEEE  = 11,
-       IWL_RATE_11M_IEEE = 22,
-};
-
-#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
-
-#define IWL_INVALID_VALUE    -1
-
-#define IWL_MIN_RSSI_VAL                 -100
-#define IWL_MAX_RSSI_VAL                    0
-
-/* These values specify how many Tx frame attempts before
- * searching for a new modulation mode */
-#define IWL_LEGACY_FAILURE_LIMIT       160
-#define IWL_LEGACY_SUCCESS_LIMIT       480
-#define IWL_LEGACY_TABLE_COUNT         160
-
-#define IWL_NONE_LEGACY_FAILURE_LIMIT  400
-#define IWL_NONE_LEGACY_SUCCESS_LIMIT  4500
-#define IWL_NONE_LEGACY_TABLE_COUNT    1500
-
-/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
-#define IWL_RS_GOOD_RATIO              12800   /* 100% */
-#define IWL_RATE_SCALE_SWITCH          10880   /*  85% */
-#define IWL_RATE_HIGH_TH               10880   /*  85% */
-#define IWL_RATE_INCREASE_TH           6400    /*  50% */
-#define IWL_RATE_DECREASE_TH           1920    /*  15% */
-
-/* possible actions when in legacy mode */
-#define IWL_LEGACY_SWITCH_ANTENNA1      0
-#define IWL_LEGACY_SWITCH_ANTENNA2      1
-#define IWL_LEGACY_SWITCH_SISO          2
-#define IWL_LEGACY_SWITCH_MIMO2_AB      3
-#define IWL_LEGACY_SWITCH_MIMO2_AC      4
-#define IWL_LEGACY_SWITCH_MIMO2_BC      5
-#define IWL_LEGACY_SWITCH_MIMO3_ABC     6
-
-/* possible actions when in siso mode */
-#define IWL_SISO_SWITCH_ANTENNA1        0
-#define IWL_SISO_SWITCH_ANTENNA2        1
-#define IWL_SISO_SWITCH_MIMO2_AB        2
-#define IWL_SISO_SWITCH_MIMO2_AC        3
-#define IWL_SISO_SWITCH_MIMO2_BC        4
-#define IWL_SISO_SWITCH_GI              5
-#define IWL_SISO_SWITCH_MIMO3_ABC       6
-
-
-/* possible actions when in mimo mode */
-#define IWL_MIMO2_SWITCH_ANTENNA1       0
-#define IWL_MIMO2_SWITCH_ANTENNA2       1
-#define IWL_MIMO2_SWITCH_SISO_A         2
-#define IWL_MIMO2_SWITCH_SISO_B         3
-#define IWL_MIMO2_SWITCH_SISO_C         4
-#define IWL_MIMO2_SWITCH_GI             5
-#define IWL_MIMO2_SWITCH_MIMO3_ABC      6
-
-
-/* possible actions when in mimo3 mode */
-#define IWL_MIMO3_SWITCH_ANTENNA1       0
-#define IWL_MIMO3_SWITCH_ANTENNA2       1
-#define IWL_MIMO3_SWITCH_SISO_A         2
-#define IWL_MIMO3_SWITCH_SISO_B         3
-#define IWL_MIMO3_SWITCH_SISO_C         4
-#define IWL_MIMO3_SWITCH_MIMO2_AB       5
-#define IWL_MIMO3_SWITCH_MIMO2_AC       6
-#define IWL_MIMO3_SWITCH_MIMO2_BC       7
-#define IWL_MIMO3_SWITCH_GI             8
-
-
-#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
-#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
-
-/*FIXME:RS:add possible actions for MIMO3*/
-
-#define IWL_ACTION_LIMIT               3       /* # possible actions */
-
-#define LQ_SIZE                2       /* 2 mode tables:  "Active" and "Search" */
-
-/* load per tid defines for A-MPDU activation */
-#define IWL_AGG_TPT_THREHOLD   0
-#define IWL_AGG_LOAD_THRESHOLD 10
-#define IWL_AGG_ALL_TID                0xff
-#define TID_QUEUE_CELL_SPACING 50      /*mS */
-#define TID_QUEUE_MAX_SIZE     20
-#define TID_ROUND_VALUE                5       /* mS */
-
-#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
-#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
-
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
-
-enum iwl_table_type {
-       LQ_NONE,
-       LQ_G,           /* legacy types */
-       LQ_A,
-       LQ_SISO,        /* high-throughput types */
-       LQ_MIMO2,
-       LQ_MIMO3,
-       LQ_MAX,
-};
-
-#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) ((tbl) == LQ_SISO)
-#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
-#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
-#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
-#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) ((tbl) == LQ_A)
-#define is_g_and(tbl) ((tbl) == LQ_G)
-
-#define IWL_MAX_MCS_DISPLAY_SIZE       12
-
-struct iwl_rate_mcs_info {
-       char    mbps[IWL_MAX_MCS_DISPLAY_SIZE];
-       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;
-
-       /* 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;
-       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[IWL_MAX_TID_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;
-       /* BT traffic this sta was last updated in */
-       u8 last_bt_traffic;
-};
-
-static inline u8 num_of_ant(u8 mask)
-{
-       return  !!((mask) & ANT_A) +
-               !!((mask) & ANT_B) +
-               !!((mask) & ANT_C);
-}
-
-static inline u8 first_antenna(u8 mask)
-{
-       if (mask & ANT_A)
-               return ANT_A;
-       if (mask & ANT_B)
-               return ANT_B;
-       return ANT_C;
-}
-
-
-/* Initialize station's rate scaling information after adding station */
-extern void iwl_rs_rate_init(struct iwl_priv *priv,
-                            struct ieee80211_sta *sta, u8 sta_id);
-
-/**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
- *
- * Since the rate control algorithm is hardware specific, there is no need
- * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
- * with the mac80211 subsystem.  This should be performed prior to calling
- * ieee80211_register_hw
- *
- */
-extern int iwlagn_rate_control_register(void);
-
-/**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
- *
- * This should be called after calling ieee80211_unregister_hw, but before
- * the driver is unloaded.
- */
-extern void iwlagn_rate_control_unregister(void);
-
-#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
deleted file mode 100644 (file)
index 403de96..0000000
+++ /dev/null
@@ -1,1166 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portionhelp of the ieee80211 subsystem header files.
- *
- * 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/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <net/mac80211.h>
-#include <asm/unaligned.h>
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-modparams.h"
-
-#define IWL_CMD_ENTRY(x) [x] = #x
-
-const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
-       IWL_CMD_ENTRY(REPLY_ALIVE),
-       IWL_CMD_ENTRY(REPLY_ERROR),
-       IWL_CMD_ENTRY(REPLY_ECHO),
-       IWL_CMD_ENTRY(REPLY_RXON),
-       IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
-       IWL_CMD_ENTRY(REPLY_QOS_PARAM),
-       IWL_CMD_ENTRY(REPLY_RXON_TIMING),
-       IWL_CMD_ENTRY(REPLY_ADD_STA),
-       IWL_CMD_ENTRY(REPLY_REMOVE_STA),
-       IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
-       IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
-       IWL_CMD_ENTRY(REPLY_WEPKEY),
-       IWL_CMD_ENTRY(REPLY_TX),
-       IWL_CMD_ENTRY(REPLY_LEDS_CMD),
-       IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
-       IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
-       IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
-       IWL_CMD_ENTRY(COEX_EVENT_CMD),
-       IWL_CMD_ENTRY(REPLY_QUIET_CMD),
-       IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
-       IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
-       IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
-       IWL_CMD_ENTRY(POWER_TABLE_CMD),
-       IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
-       IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
-       IWL_CMD_ENTRY(REPLY_SCAN_CMD),
-       IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
-       IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
-       IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
-       IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
-       IWL_CMD_ENTRY(BEACON_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_BEACON),
-       IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
-       IWL_CMD_ENTRY(QUIET_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
-       IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_BT_CONFIG),
-       IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
-       IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
-       IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
-       IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
-       IWL_CMD_ENTRY(SENSITIVITY_CMD),
-       IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
-       IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
-       IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
-       IWL_CMD_ENTRY(REPLY_RX),
-       IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
-       IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
-       IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
-       IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
-       IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
-       IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
-       IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
-       IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
-       IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
-       IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
-       IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
-       IWL_CMD_ENTRY(REPLY_D3_CONFIG),
-};
-#undef IWL_CMD_ENTRY
-
-/******************************************************************************
- *
- * Generic RX handler implementations
- *
- ******************************************************************************/
-
-static int iwlagn_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_error_resp *err_resp = (void *)pkt->data;
-
-       IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
-               "seq 0x%04X ser 0x%08X\n",
-               le32_to_cpu(err_resp->error_type),
-               err_resp->cmd_id,
-               le16_to_cpu(err_resp->bad_cmd_seq_num),
-               le32_to_cpu(err_resp->error_info));
-       return 0;
-}
-
-static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_csa_notification *csa = (void *)pkt->data;
-       /*
-        * MULTI-FIXME
-        * See iwlagn_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
-
-       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-               return 0;
-
-       if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
-               rxon->channel = csa->channel;
-               ctx->staging.channel = csa->channel;
-               IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
-                             le16_to_cpu(csa->channel));
-               iwl_chswitch_done(priv, true);
-       } else {
-               IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
-                       le16_to_cpu(csa->channel));
-               iwl_chswitch_done(priv, false);
-       }
-       return 0;
-}
-
-
-static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_cmd_buffer *rxb,
-                                         struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_spectrum_notification *report = (void *)pkt->data;
-
-       if (!report->state) {
-               IWL_DEBUG_11H(priv,
-                       "Spectrum Measure Notification: Start\n");
-               return 0;
-       }
-
-       memcpy(&priv->measure_report, report, sizeof(*report));
-       priv->measurement_status |= MEASUREMENT_READY;
-       return 0;
-}
-
-static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_cmd_buffer *rxb,
-                                 struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_sleep_notification *sleep = (void *)pkt->data;
-       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
-                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
-       return 0;
-}
-
-static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_cmd_buffer *rxb,
-                                            struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u32 __maybe_unused len =
-               le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-                       "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
-       return 0;
-}
-
-static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
-                               struct iwl_rx_cmd_buffer *rxb,
-                               struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwlagn_beacon_notif *beacon = (void *)pkt->data;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status);
-       u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
-
-       IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d "
-               "tsf:0x%.8x%.8x rate:%d\n",
-               status & TX_STATUS_MSK,
-               beacon->beacon_notify_hdr.failure_frame,
-               le32_to_cpu(beacon->ibss_mgr_status),
-               le32_to_cpu(beacon->high_tsf),
-               le32_to_cpu(beacon->low_tsf), rate);
-#endif
-
-       priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
-
-       return 0;
-}
-
-/**
- * iwl_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
-                                struct statistics_rx_phy *cur_ofdm,
-                                struct statistics_rx_ht_phy *cur_ofdm_ht,
-                                unsigned int msecs)
-{
-       int delta;
-       int threshold = priv->plcp_delta_threshold;
-
-       if (threshold == IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
-               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
-               return true;
-       }
-
-       delta = le32_to_cpu(cur_ofdm->plcp_err) -
-               le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
-               le32_to_cpu(cur_ofdm_ht->plcp_err) -
-               le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
-
-       /* Can be negative if firmware reset statistics */
-       if (delta <= 0)
-               return true;
-
-       if ((delta * 100 / msecs) > threshold) {
-               IWL_DEBUG_RADIO(priv,
-                               "plcp health threshold %u delta %d msecs %u\n",
-                               threshold, delta, msecs);
-               return false;
-       }
-
-       return true;
-}
-
-int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
-{
-       struct iwl_rf_reset *rf_reset;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return -EAGAIN;
-
-       if (!iwl_is_any_associated(priv)) {
-               IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
-               return -ENOLINK;
-       }
-
-       rf_reset = &priv->rf_reset;
-       rf_reset->reset_request_count++;
-       if (!external && rf_reset->last_reset_jiffies &&
-           time_after(rf_reset->last_reset_jiffies +
-                      IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
-               IWL_DEBUG_INFO(priv, "RF reset rejected\n");
-               rf_reset->reset_reject_count++;
-               return -EAGAIN;
-       }
-       rf_reset->reset_success_count++;
-       rf_reset->last_reset_jiffies = jiffies;
-
-       /*
-        * There is no easy and better way to force reset the radio,
-        * the only known method is switching channel which will force to
-        * reset and tune the radio.
-        * Use internal short scan (single channel) operation to should
-        * achieve this objective.
-        * Driver should reset the radio when number of consecutive missed
-        * beacon, or any other uCode error condition detected.
-        */
-       IWL_DEBUG_INFO(priv, "perform radio reset.\n");
-       iwl_internal_short_hw_scan(priv);
-       return 0;
-}
-
-
-static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
-                               struct statistics_rx_phy *cur_ofdm,
-                               struct statistics_rx_ht_phy *cur_ofdm_ht,
-                               struct statistics_tx *tx,
-                               unsigned long stamp)
-{
-       unsigned int msecs;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
-
-       /* Only gather statistics and update time stamp when not associated */
-       if (!iwl_is_any_associated(priv))
-               return;
-
-       /* Do not check/recover when do not have enough statistics data */
-       if (msecs < 99)
-               return;
-
-       if (iwlwifi_mod_params.plcp_check &&
-           !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
-               iwl_force_rf_reset(priv, false);
-}
-
-/* Calculate noise level, based on measurements during network silence just
- *   before arriving beacon.  This measurement can be done only if we know
- *   exactly when to expect beacons, therefore only when we're associated. */
-static void iwlagn_rx_calc_noise(struct iwl_priv *priv)
-{
-       struct statistics_rx_non_phy *rx_info;
-       int num_active_rx = 0;
-       int total_silence = 0;
-       int bcn_silence_a, bcn_silence_b, bcn_silence_c;
-       int last_rx_noise;
-
-       rx_info = &priv->statistics.rx_non_phy;
-
-       bcn_silence_a =
-               le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
-       bcn_silence_b =
-               le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
-       bcn_silence_c =
-               le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
-
-       if (bcn_silence_a) {
-               total_silence += bcn_silence_a;
-               num_active_rx++;
-       }
-       if (bcn_silence_b) {
-               total_silence += bcn_silence_b;
-               num_active_rx++;
-       }
-       if (bcn_silence_c) {
-               total_silence += bcn_silence_c;
-               num_active_rx++;
-       }
-
-       /* Average among active antennas */
-       if (num_active_rx)
-               last_rx_noise = (total_silence / num_active_rx) - 107;
-       else
-               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-       IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
-                       bcn_silence_a, bcn_silence_b, bcn_silence_c,
-                       last_rx_noise);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-/*
- *  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 accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
-                       __le32 *max_delta, __le32 *accum, int size)
-{
-       int i;
-
-       for (i = 0;
-            i < size / sizeof(__le32);
-            i++, prev++, cur++, delta++, max_delta++, accum++) {
-               if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
-                       *delta = cpu_to_le32(
-                               le32_to_cpu(*cur) - le32_to_cpu(*prev));
-                       le32_add_cpu(accum, le32_to_cpu(*delta));
-                       if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta))
-                               *max_delta = *delta;
-               }
-       }
-}
-
-static void
-iwlagn_accumulative_statistics(struct iwl_priv *priv,
-                           struct statistics_general_common *common,
-                           struct statistics_rx_non_phy *rx_non_phy,
-                           struct statistics_rx_phy *rx_ofdm,
-                           struct statistics_rx_ht_phy *rx_ofdm_ht,
-                           struct statistics_rx_phy *rx_cck,
-                           struct statistics_tx *tx,
-                           struct statistics_bt_activity *bt_activity)
-{
-#define ACCUM(_name)   \
-       accum_stats((__le32 *)&priv->statistics._name,          \
-                   (__le32 *)_name,                            \
-                   (__le32 *)&priv->delta_stats._name,         \
-                   (__le32 *)&priv->max_delta_stats._name,     \
-                   (__le32 *)&priv->accum_stats._name,         \
-                   sizeof(*_name));
-
-       ACCUM(common);
-       ACCUM(rx_non_phy);
-       ACCUM(rx_ofdm);
-       ACCUM(rx_ofdm_ht);
-       ACCUM(rx_cck);
-       ACCUM(tx);
-       if (bt_activity)
-               ACCUM(bt_activity);
-#undef ACCUM
-}
-#else
-static inline void
-iwlagn_accumulative_statistics(struct iwl_priv *priv,
-                           struct statistics_general_common *common,
-                           struct statistics_rx_non_phy *rx_non_phy,
-                           struct statistics_rx_phy *rx_ofdm,
-                           struct statistics_rx_ht_phy *rx_ofdm_ht,
-                           struct statistics_rx_phy *rx_cck,
-                           struct statistics_tx *tx,
-                           struct statistics_bt_activity *bt_activity)
-{
-}
-#endif
-
-static int iwlagn_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_cmd_buffer *rxb,
-                             struct iwl_device_cmd *cmd)
-{
-       unsigned long stamp = jiffies;
-       const int reg_recalib_period = 60;
-       int change;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       __le32 *flag;
-       struct statistics_general_common *common;
-       struct statistics_rx_non_phy *rx_non_phy;
-       struct statistics_rx_phy *rx_ofdm;
-       struct statistics_rx_ht_phy *rx_ofdm_ht;
-       struct statistics_rx_phy *rx_cck;
-       struct statistics_tx *tx;
-       struct statistics_bt_activity *bt_activity;
-
-       len -= sizeof(struct iwl_cmd_header); /* skip header */
-
-       IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
-                    len);
-
-       spin_lock(&priv->statistics.lock);
-
-       if (len == sizeof(struct iwl_bt_notif_statistics)) {
-               struct iwl_bt_notif_statistics *stats;
-               stats = (void *)&pkt->data;
-               flag = &stats->flag;
-               common = &stats->general.common;
-               rx_non_phy = &stats->rx.general.common;
-               rx_ofdm = &stats->rx.ofdm;
-               rx_ofdm_ht = &stats->rx.ofdm_ht;
-               rx_cck = &stats->rx.cck;
-               tx = &stats->tx;
-               bt_activity = &stats->general.activity;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               /* handle this exception directly */
-               priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
-               le32_add_cpu(&priv->statistics.accum_num_bt_kills,
-                            le32_to_cpu(stats->rx.general.num_bt_kills));
-#endif
-       } else if (len == sizeof(struct iwl_notif_statistics)) {
-               struct iwl_notif_statistics *stats;
-               stats = (void *)&pkt->data;
-               flag = &stats->flag;
-               common = &stats->general.common;
-               rx_non_phy = &stats->rx.general;
-               rx_ofdm = &stats->rx.ofdm;
-               rx_ofdm_ht = &stats->rx.ofdm_ht;
-               rx_cck = &stats->rx.cck;
-               tx = &stats->tx;
-               bt_activity = NULL;
-       } else {
-               WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
-                         len, sizeof(struct iwl_bt_notif_statistics),
-                         sizeof(struct iwl_notif_statistics));
-               spin_unlock(&priv->statistics.lock);
-               return 0;
-       }
-
-       change = common->temperature != priv->statistics.common.temperature ||
-                (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-                (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
-
-       iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
-                                   rx_ofdm_ht, rx_cck, tx, bt_activity);
-
-       iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
-
-       priv->statistics.flag = *flag;
-       memcpy(&priv->statistics.common, common, sizeof(*common));
-       memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
-       memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
-       memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
-       memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
-       memcpy(&priv->statistics.tx, tx, sizeof(*tx));
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       if (bt_activity)
-               memcpy(&priv->statistics.bt_activity, bt_activity,
-                       sizeof(*bt_activity));
-#endif
-
-       priv->rx_statistics_jiffies = stamp;
-
-       set_bit(STATUS_STATISTICS, &priv->status);
-
-       /* Reschedule the statistics timer to occur in
-        * reg_recalib_period seconds to ensure we get a
-        * thermal update even if the uCode doesn't give
-        * us one */
-       mod_timer(&priv->statistics_periodic, jiffies +
-                 msecs_to_jiffies(reg_recalib_period * 1000));
-
-       if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
-           (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
-               iwlagn_rx_calc_noise(priv);
-               queue_work(priv->workqueue, &priv->run_time_calib_work);
-       }
-       if (priv->lib->temperature && change)
-               priv->lib->temperature(priv);
-
-       spin_unlock(&priv->statistics.lock);
-
-       return 0;
-}
-
-static int iwlagn_rx_reply_statistics(struct iwl_priv *priv,
-                                   struct iwl_rx_cmd_buffer *rxb,
-                                   struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_notif_statistics *stats = (void *)pkt->data;
-
-       if (le32_to_cpu(stats->flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               memset(&priv->accum_stats, 0,
-                       sizeof(priv->accum_stats));
-               memset(&priv->delta_stats, 0,
-                       sizeof(priv->delta_stats));
-               memset(&priv->max_delta_stats, 0,
-                       sizeof(priv->max_delta_stats));
-#endif
-               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
-       }
-       iwlagn_rx_statistics(priv, rxb, cmd);
-       return 0;
-}
-
-/* Handle notification from uCode that card's power state is changing
- * due to software, hardware, or critical temperature RFKILL */
-static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_cmd_buffer *rxb,
-                                   struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_card_state_notif *card_state_notif = (void *)pkt->data;
-       u32 flags = le32_to_cpu(card_state_notif->flags);
-       unsigned long status = priv->status;
-
-       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
-                         (flags & HW_CARD_DISABLED) ? "Kill" : "On",
-                         (flags & SW_CARD_DISABLED) ? "Kill" : "On",
-                         (flags & CT_CARD_DISABLED) ?
-                         "Reached" : "Not reached");
-
-       if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
-                    CT_CARD_DISABLED)) {
-
-               iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
-                           CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-               iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
-                                       HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-               if (!(flags & RXON_CARD_DISABLED)) {
-                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-                                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-                       iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C,
-                                       HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-               }
-               if (flags & CT_CARD_DISABLED)
-                       iwl_tt_enter_ct_kill(priv);
-       }
-       if (!(flags & CT_CARD_DISABLED))
-               iwl_tt_exit_ct_kill(priv);
-
-       if (flags & HW_CARD_DISABLED)
-               set_bit(STATUS_RF_KILL_HW, &priv->status);
-       else
-               clear_bit(STATUS_RF_KILL_HW, &priv->status);
-
-
-       if (!(flags & RXON_CARD_DISABLED))
-               iwl_scan_cancel(priv);
-
-       if ((test_bit(STATUS_RF_KILL_HW, &status) !=
-            test_bit(STATUS_RF_KILL_HW, &priv->status)))
-               wiphy_rfkill_set_hw_state(priv->hw->wiphy,
-                       test_bit(STATUS_RF_KILL_HW, &priv->status));
-       else
-               wake_up(&priv->trans->wait_command_queue);
-       return 0;
-}
-
-static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_cmd_buffer *rxb,
-                                      struct iwl_device_cmd *cmd)
-
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_missed_beacon_notif *missed_beacon = (void *)pkt->data;
-
-       if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
-           priv->missed_beacon_threshold) {
-               IWL_DEBUG_CALIB(priv,
-                   "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-                   le32_to_cpu(missed_beacon->consecutive_missed_beacons),
-                   le32_to_cpu(missed_beacon->total_missed_becons),
-                   le32_to_cpu(missed_beacon->num_recvd_beacons),
-                   le32_to_cpu(missed_beacon->num_expected_beacons));
-               if (!test_bit(STATUS_SCANNING, &priv->status))
-                       iwl_init_sensitivity(priv);
-       }
-       return 0;
-}
-
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
-                               struct iwl_rx_cmd_buffer *rxb,
-                               struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-
-       priv->last_phy_res_valid = true;
-       memcpy(&priv->last_phy_res, pkt->data,
-              sizeof(struct iwl_rx_phy_res));
-       return 0;
-}
-
-/*
- * returns non-zero if packet should be dropped
- */
-static int iwlagn_set_decrypted_flag(struct iwl_priv *priv,
-                                 struct ieee80211_hdr *hdr,
-                                 u32 decrypt_res,
-                                 struct ieee80211_rx_status *stats)
-{
-       u16 fc = le16_to_cpu(hdr->frame_control);
-
-       /*
-        * All contexts have the same setting here due to it being
-        * a module parameter, so OK to check any context.
-        */
-       if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
-                                               RXON_FILTER_DIS_DECRYPT_MSK)
-               return 0;
-
-       if (!(fc & IEEE80211_FCTL_PROTECTED))
-               return 0;
-
-       IWL_DEBUG_RX(priv, "decrypt_res:0x%x\n", decrypt_res);
-       switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
-       case RX_RES_STATUS_SEC_TYPE_TKIP:
-               /* The uCode has got a bad phase 1 Key, pushes the packet.
-                * Decryption will be done in SW. */
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_BAD_KEY_TTAK)
-                       break;
-
-       case RX_RES_STATUS_SEC_TYPE_WEP:
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_BAD_ICV_MIC) {
-                       /* bad ICV, the packet is destroyed since the
-                        * decryption is inplace, drop it */
-                       IWL_DEBUG_RX(priv, "Packet destroyed\n");
-                       return -1;
-               }
-       case RX_RES_STATUS_SEC_TYPE_CCMP:
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_DECRYPT_OK) {
-                       IWL_DEBUG_RX(priv, "hw decrypt successfully!!!\n");
-                       stats->flag |= RX_FLAG_DECRYPTED;
-               }
-               break;
-
-       default:
-               break;
-       }
-       return 0;
-}
-
-static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
-                                       struct ieee80211_hdr *hdr,
-                                       u16 len,
-                                       u32 ampdu_status,
-                                       struct iwl_rx_cmd_buffer *rxb,
-                                       struct ieee80211_rx_status *stats)
-{
-       struct sk_buff *skb;
-       __le16 fc = hdr->frame_control;
-       struct iwl_rxon_context *ctx;
-       unsigned int hdrlen, fraglen;
-
-       /* We only process data packets if the interface is open */
-       if (unlikely(!priv->is_open)) {
-               IWL_DEBUG_DROP_LIMIT(priv,
-                   "Dropping packet while interface is not open.\n");
-               return;
-       }
-
-       /* In case of HW accelerated crypto and bad decryption, drop */
-       if (!iwlwifi_mod_params.sw_crypto &&
-           iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats))
-               return;
-
-       /* Dont use dev_alloc_skb(), we'll have enough headroom once
-        * ieee80211_hdr pulled.
-        */
-       skb = alloc_skb(128, GFP_ATOMIC);
-       if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
-               return;
-       }
-       /* If frame is small enough to fit in skb->head, pull it completely.
-        * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
-        * are more efficient.
-        */
-       hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
-
-       memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
-       fraglen = len - hdrlen;
-
-       if (fraglen) {
-               int offset = (void *)hdr + hdrlen -
-                            rxb_addr(rxb) + rxb_offset(rxb);
-
-               skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
-                               fraglen, rxb->truesize);
-       }
-
-       /*
-       * Wake any queues that were stopped due to a passive channel tx
-       * failure. This can happen because the regulatory enforcement in
-       * the device waits for a beacon before allowing transmission,
-       * sometimes even after already having transmitted frames for the
-       * association because the new RXON may reset the information.
-       */
-       if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) {
-               for_each_context(priv, ctx) {
-                       if (!ether_addr_equal(hdr->addr3,
-                                             ctx->active.bssid_addr))
-                               continue;
-                       iwlagn_lift_passive_no_rx(priv);
-               }
-       }
-
-       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
-
-       ieee80211_rx(priv->hw, skb);
-}
-
-static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
-{
-       u32 decrypt_out = 0;
-
-       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
-                                       RX_RES_STATUS_STATION_FOUND)
-               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
-                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
-
-       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
-
-       /* packet was not encrypted */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_NONE)
-               return decrypt_out;
-
-       /* packet was encrypted with unknown alg */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_ERR)
-               return decrypt_out;
-
-       /* decryption was not done in HW */
-       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
-                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
-               return decrypt_out;
-
-       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
-
-       case RX_RES_STATUS_SEC_TYPE_CCMP:
-               /* alg is CCM: check MIC only */
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
-                       /* Bad MIC */
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-
-               break;
-
-       case RX_RES_STATUS_SEC_TYPE_TKIP:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
-                       /* Bad TTAK */
-                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
-                       break;
-               }
-               /* fall through if TTAK OK */
-       default:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-               break;
-       }
-
-       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
-                                       decrypt_in, decrypt_out);
-
-       return decrypt_out;
-}
-
-/* Calc max signal level (dBm) among 3 possible receivers */
-static int iwlagn_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp)
-{
-       /* data from PHY/DSP regarding signal strength, etc.,
-        *   contents are always there, not configurable by host
-        */
-       struct iwlagn_non_cfg_phy *ncphy =
-               (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
-       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
-       u8 agc;
-
-       val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
-       agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
-
-       /* Find max rssi among 3 possible receivers.
-        * These values are measured by the digital signal processor (DSP).
-        * They should stay fairly constant even as the signal strength varies,
-        *   if the radio's automatic gain control (AGC) is working right.
-        * AGC value (see below) will provide the "interesting" info.
-        */
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
-       rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
-               IWLAGN_OFDM_RSSI_A_BIT_POS;
-       rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
-               IWLAGN_OFDM_RSSI_B_BIT_POS;
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
-       rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
-               IWLAGN_OFDM_RSSI_C_BIT_POS;
-
-       max_rssi = max_t(u32, rssi_a, rssi_b);
-       max_rssi = max_t(u32, max_rssi, rssi_c);
-
-       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
-               rssi_a, rssi_b, rssi_c, max_rssi, agc);
-
-       /* dBm = max_rssi dB - agc dB - constant.
-        * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
-}
-
-/* Called for REPLY_RX (legacy ABG frames), or
- * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
-                           struct iwl_rx_cmd_buffer *rxb,
-                           struct iwl_device_cmd *cmd)
-{
-       struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_rx_phy_res *phy_res;
-       __le32 rx_pkt_status;
-       struct iwl_rx_mpdu_res_start *amsdu;
-       u32 len;
-       u32 ampdu_status;
-       u32 rate_n_flags;
-
-       /**
-        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
-        *      REPLY_RX: physical layer info is in this buffer
-        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
-        *              command and cached in priv->last_phy_res
-        *
-        * Here we set up local variables depending on which command is
-        * received.
-        */
-       if (pkt->hdr.cmd == REPLY_RX) {
-               phy_res = (struct iwl_rx_phy_res *)pkt->data;
-               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res)
-                               + phy_res->cfg_phy_cnt);
-
-               len = le16_to_cpu(phy_res->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) +
-                               phy_res->cfg_phy_cnt + len);
-               ampdu_status = le32_to_cpu(rx_pkt_status);
-       } else {
-               if (!priv->last_phy_res_valid) {
-                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-                       return 0;
-               }
-               phy_res = &priv->last_phy_res;
-               amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data;
-               header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu));
-               len = le16_to_cpu(amsdu->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len);
-               ampdu_status = iwlagn_translate_rx_status(priv,
-                                               le32_to_cpu(rx_pkt_status));
-       }
-
-       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
-               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n",
-                               phy_res->cfg_phy_cnt);
-               return 0;
-       }
-
-       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
-           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
-                               le32_to_cpu(rx_pkt_status));
-               return 0;
-       }
-
-       /* This will be used in several places later */
-       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-       /* rx_status carries information about the packet to mac80211 */
-       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
-       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-       rx_status.freq =
-               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
-                                              rx_status.band);
-       rx_status.rate_idx =
-               iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
-       rx_status.flag = 0;
-
-       /* TSF isn't reliable. In order to allow smooth user experience,
-        * this W/A doesn't propagate it to the mac80211 */
-       /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
-
-       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
-
-       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
-       rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
-
-       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
-               rx_status.signal, (unsigned long long)rx_status.mactime);
-
-       /*
-        * "antenna number"
-        *
-        * It seems that the antenna field in the phy flags value
-        * is actually a bit field. This is undefined by radiotap,
-        * it wants an actual antenna number but I always get "7"
-        * for most legacy frames I receive indicating that the
-        * same frame was received on all three RX chains.
-        *
-        * I think this field should be removed in favor of a
-        * new 802.11n radiotap field "RX chains" that is defined
-        * as a bitmask.
-        */
-       rx_status.antenna =
-               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
-               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
-
-       /* set the preamble flag if appropriate */
-       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-               rx_status.flag |= RX_FLAG_SHORTPRE;
-
-       /* Set up the HT phy flags */
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               rx_status.flag |= RX_FLAG_HT;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               rx_status.flag |= RX_FLAG_40MHZ;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               rx_status.flag |= RX_FLAG_SHORT_GI;
-
-       iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
-                                   rxb, &rx_status);
-       return 0;
-}
-
-static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
-                                     struct iwl_rx_cmd_buffer *rxb,
-                                     struct iwl_device_cmd *cmd)
-{
-       struct iwl_wipan_noa_data *new_data, *old_data;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->data;
-
-       /* no condition -- we're in softirq */
-       old_data = rcu_dereference_protected(priv->noa_data, true);
-
-       if (noa_notif->noa_active) {
-               u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
-               u32 copylen = len;
-
-               /* EID, len, OUI, subtype */
-               len += 1 + 1 + 3 + 1;
-               /* P2P id, P2P length */
-               len += 1 + 2;
-               copylen += 1 + 2;
-
-               new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
-               if (new_data) {
-                       new_data->length = len;
-                       new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
-                       new_data->data[1] = len - 2; /* not counting EID, len */
-                       new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
-                       new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
-                       new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
-                       new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
-                       memcpy(&new_data->data[6], &noa_notif->noa_attribute,
-                              copylen);
-               }
-       } else
-               new_data = NULL;
-
-       rcu_assign_pointer(priv->noa_data, new_data);
-
-       if (old_data)
-               kfree_rcu(old_data, rcu_head);
-
-       return 0;
-}
-
-/**
- * iwl_setup_rx_handlers - Initialize Rx handler callbacks
- *
- * Setup the RX handlers for each of the reply types sent from the uCode
- * to the host.
- */
-void iwl_setup_rx_handlers(struct iwl_priv *priv)
-{
-       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd);
-
-       handlers = priv->rx_handlers;
-
-       handlers[REPLY_ERROR]                   = iwlagn_rx_reply_error;
-       handlers[CHANNEL_SWITCH_NOTIFICATION]   = iwlagn_rx_csa;
-       handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-               iwlagn_rx_spectrum_measure_notif;
-       handlers[PM_SLEEP_NOTIFICATION]         = iwlagn_rx_pm_sleep_notif;
-       handlers[PM_DEBUG_STATISTIC_NOTIFIC]    =
-               iwlagn_rx_pm_debug_statistics_notif;
-       handlers[BEACON_NOTIFICATION]           = iwlagn_rx_beacon_notif;
-       handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
-
-       handlers[REPLY_WIPAN_NOA_NOTIFICATION]  = iwlagn_rx_noa_notification;
-
-       /*
-        * The same handler is used for both the REPLY to a discrete
-        * statistics request from the host as well as for the periodic
-        * statistics notifications (after received beacons) from the uCode.
-        */
-       handlers[REPLY_STATISTICS_CMD]          = iwlagn_rx_reply_statistics;
-       handlers[STATISTICS_NOTIFICATION]       = iwlagn_rx_statistics;
-
-       iwl_setup_rx_scan_handlers(priv);
-
-       handlers[CARD_STATE_NOTIFICATION]       = iwlagn_rx_card_state_notif;
-       handlers[MISSED_BEACONS_NOTIFICATION]   =
-               iwlagn_rx_missed_beacon_notif;
-
-       /* Rx handlers */
-       handlers[REPLY_RX_PHY_CMD]              = iwlagn_rx_reply_rx_phy;
-       handlers[REPLY_RX_MPDU_CMD]             = iwlagn_rx_reply_rx;
-
-       /* block ack */
-       handlers[REPLY_COMPRESSED_BA]           =
-               iwlagn_rx_reply_compressed_ba;
-
-       priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
-
-       /* set up notification wait support */
-       iwl_notification_wait_init(&priv->notif_wait);
-
-       /* Set up BT Rx handlers */
-       if (priv->cfg->bt_params)
-               iwlagn_bt_rx_handler_setup(priv);
-}
-
-int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
-                   struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-       void (*pre_rx_handler)(struct iwl_priv *,
-                              struct iwl_rx_cmd_buffer *);
-       int err = 0;
-
-       /*
-        * Do the notification wait before RX handlers so
-        * even if the RX handler consumes the RXB we have
-        * access to it in the notification wait entry.
-        */
-       iwl_notification_wait_notify(&priv->notif_wait, pkt);
-
-       /* RX data may be forwarded to userspace (using pre_rx_handler) in one
-        * of two cases: the first, that the user owns the uCode through
-        * testmode - in such case the pre_rx_handler is set and no further
-        * processing takes place. The other case is when the user want to
-        * monitor the rx w/o affecting the regular flow - the pre_rx_handler
-        * will be set but the ownership flag != IWL_OWNERSHIP_TM and the flow
-        * continues.
-        * We need to use ACCESS_ONCE to prevent a case where the handler
-        * changes between the check and the call.
-        */
-       pre_rx_handler = ACCESS_ONCE(priv->pre_rx_handler);
-       if (pre_rx_handler)
-               pre_rx_handler(priv, rxb);
-       if (priv->ucode_owner != IWL_OWNERSHIP_TM) {
-               /* Based on type of command response or notification,
-                *   handle those that need handling via function in
-                *   rx_handlers table.  See iwl_setup_rx_handlers() */
-               if (priv->rx_handlers[pkt->hdr.cmd]) {
-                       priv->rx_handlers_stats[pkt->hdr.cmd]++;
-                       err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
-               } else {
-                       /* No handling needed */
-                       IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
-                                    iwl_dvm_get_cmd_string(pkt->hdr.cmd),
-                                    pkt->hdr.cmd);
-               }
-       }
-       return err;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
deleted file mode 100644 (file)
index 0a3aa7c..0000000
+++ /dev/null
@@ -1,1593 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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/etherdevice.h>
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/*
- * initialize rxon structure with default values from eeprom
- */
-void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct iwl_rxon_context *ctx)
-{
-       const struct iwl_channel_info *ch_info;
-
-       memset(&ctx->staging, 0, sizeof(ctx->staging));
-
-       if (!ctx->vif) {
-               ctx->staging.dev_type = ctx->unused_devtype;
-       } else
-       switch (ctx->vif->type) {
-       case NL80211_IFTYPE_AP:
-               ctx->staging.dev_type = ctx->ap_devtype;
-               break;
-
-       case NL80211_IFTYPE_STATION:
-               ctx->staging.dev_type = ctx->station_devtype;
-               ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
-               break;
-
-       case NL80211_IFTYPE_ADHOC:
-               ctx->staging.dev_type = ctx->ibss_devtype;
-               ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
-               ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
-                                                 RXON_FILTER_ACCEPT_GRP_MSK;
-               break;
-
-       case NL80211_IFTYPE_MONITOR:
-               ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
-               break;
-
-       default:
-               IWL_ERR(priv, "Unsupported interface type %d\n",
-                       ctx->vif->type);
-               break;
-       }
-
-#if 0
-       /* TODO:  Figure out when short_preamble would be set and cache from
-        * that */
-       if (!hw_to_local(priv->hw)->short_preamble)
-               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-       else
-               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-#endif
-
-       ch_info = iwl_get_channel_info(priv, priv->band,
-                                      le16_to_cpu(ctx->active.channel));
-
-       if (!ch_info)
-               ch_info = &priv->channel_info[0];
-
-       ctx->staging.channel = cpu_to_le16(ch_info->channel);
-       priv->band = ch_info->band;
-
-       iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
-
-       /* clear both MIX and PURE40 mode flag */
-       ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
-                                       RXON_FLG_CHANNEL_MODE_PURE_40);
-       if (ctx->vif)
-               memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
-
-       ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
-       ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
-       ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
-}
-
-static int iwlagn_disable_bss(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                             struct iwl_rxon_cmd *send)
-{
-       __le32 old_filter = send->filter_flags;
-       int ret;
-
-       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
-                               CMD_SYNC, sizeof(*send), send);
-
-       send->filter_flags = old_filter;
-
-       if (ret)
-               IWL_DEBUG_QUIET_RFKILL(priv,
-                       "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
-
-       return ret;
-}
-
-static int iwlagn_disable_pan(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                             struct iwl_rxon_cmd *send)
-{
-       struct iwl_notification_wait disable_wait;
-       __le32 old_filter = send->filter_flags;
-       u8 old_dev_type = send->dev_type;
-       int ret;
-       static const u8 deactivate_cmd[] = {
-               REPLY_WIPAN_DEACTIVATION_COMPLETE
-       };
-
-       iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
-                                  deactivate_cmd, ARRAY_SIZE(deactivate_cmd),
-                                  NULL, NULL);
-
-       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       send->dev_type = RXON_DEV_TYPE_P2P;
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd,
-                               CMD_SYNC, sizeof(*send), send);
-
-       send->filter_flags = old_filter;
-       send->dev_type = old_dev_type;
-
-       if (ret) {
-               IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
-               iwl_remove_notification(&priv->notif_wait, &disable_wait);
-       } else {
-               ret = iwl_wait_notification(&priv->notif_wait,
-                                           &disable_wait, HZ);
-               if (ret)
-                       IWL_ERR(priv, "Timed out waiting for PAN disable\n");
-       }
-
-       return ret;
-}
-
-static int iwlagn_disconn_pan(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                             struct iwl_rxon_cmd *send)
-{
-       __le32 old_filter = send->filter_flags;
-       int ret;
-
-       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
-                               sizeof(*send), send);
-
-       send->filter_flags = old_filter;
-
-       return ret;
-}
-
-void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       int ret;
-
-       if (!ctx->is_active)
-               return;
-
-       ctx->qos_data.def_qos_parm.qos_flags = 0;
-
-       if (ctx->qos_data.qos_active)
-               ctx->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
-
-       if (ctx->ht.enabled)
-               ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
-
-       IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                     ctx->qos_data.qos_active,
-                     ctx->qos_data.def_qos_parm.qos_flags);
-
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
-                              sizeof(struct iwl_qosparam_cmd),
-                              &ctx->qos_data.def_qos_parm);
-       if (ret)
-               IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
-}
-
-int iwlagn_update_beacon(struct iwl_priv *priv,
-                        struct ieee80211_vif *vif)
-{
-       lockdep_assert_held(&priv->mutex);
-
-       dev_kfree_skb(priv->beacon_skb);
-       priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif);
-       if (!priv->beacon_skb)
-               return -ENOMEM;
-       return iwlagn_send_beacon_cmd(priv);
-}
-
-static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
-                          struct iwl_rxon_context *ctx)
-{
-       int ret = 0;
-       struct iwl_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
-       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
-
-       if ((rxon1->flags == rxon2->flags) &&
-           (rxon1->filter_flags == rxon2->filter_flags) &&
-           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-           (rxon1->ofdm_ht_single_stream_basic_rates ==
-            rxon2->ofdm_ht_single_stream_basic_rates) &&
-           (rxon1->ofdm_ht_dual_stream_basic_rates ==
-            rxon2->ofdm_ht_dual_stream_basic_rates) &&
-           (rxon1->ofdm_ht_triple_stream_basic_rates ==
-            rxon2->ofdm_ht_triple_stream_basic_rates) &&
-           (rxon1->acquisition_data == rxon2->acquisition_data) &&
-           (rxon1->rx_chain == rxon2->rx_chain) &&
-           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
-               return 0;
-       }
-
-       rxon_assoc.flags = ctx->staging.flags;
-       rxon_assoc.filter_flags = ctx->staging.filter_flags;
-       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
-       rxon_assoc.reserved1 = 0;
-       rxon_assoc.reserved2 = 0;
-       rxon_assoc.reserved3 = 0;
-       rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           ctx->staging.ofdm_ht_single_stream_basic_rates;
-       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           ctx->staging.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
-       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-                ctx->staging.ofdm_ht_triple_stream_basic_rates;
-       rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
-
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
-                               CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
-       return ret;
-}
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
-{
-       u16 new_val;
-       u16 beacon_factor;
-
-       /*
-        * If mac80211 hasn't given us a beacon interval, program
-        * the default into the device (not checking this here
-        * would cause the adjustment below to return the maximum
-        * value, which may break PAN.)
-        */
-       if (!beacon_val)
-               return DEFAULT_BEACON_INTERVAL;
-
-       /*
-        * If the beacon interval we obtained from the peer
-        * is too large, we'll have to wake up more often
-        * (and in IBSS case, we'll beacon too much)
-        *
-        * For example, if max_beacon_val is 4096, and the
-        * requested beacon interval is 7000, we'll have to
-        * use 3500 to be able to wake up on the beacons.
-        *
-        * This could badly influence beacon detection stats.
-        */
-
-       beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
-       new_val = beacon_val / beacon_factor;
-
-       if (!new_val)
-               new_val = max_beacon_val;
-
-       return new_val;
-}
-
-static int iwl_send_rxon_timing(struct iwl_priv *priv,
-                               struct iwl_rxon_context *ctx)
-{
-       u64 tsf;
-       s32 interval_tm, rem;
-       struct ieee80211_conf *conf = NULL;
-       u16 beacon_int;
-       struct ieee80211_vif *vif = ctx->vif;
-
-       conf = &priv->hw->conf;
-
-       lockdep_assert_held(&priv->mutex);
-
-       memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
-
-       ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
-       ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
-       beacon_int = vif ? vif->bss_conf.beacon_int : 0;
-
-       /*
-        * TODO: For IBSS we need to get atim_window from mac80211,
-        *       for now just always use 0
-        */
-       ctx->timing.atim_window = 0;
-
-       if (ctx->ctxid == IWL_RXON_CTX_PAN &&
-           (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) &&
-           iwl_is_associated(priv, IWL_RXON_CTX_BSS) &&
-           priv->contexts[IWL_RXON_CTX_BSS].vif &&
-           priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) {
-               ctx->timing.beacon_interval =
-                       priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
-               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
-       } else if (ctx->ctxid == IWL_RXON_CTX_BSS &&
-                  iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
-                  priv->contexts[IWL_RXON_CTX_PAN].vif &&
-                  priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int &&
-                  (!iwl_is_associated_ctx(ctx) || !ctx->vif ||
-                   !ctx->vif->bss_conf.beacon_int)) {
-               ctx->timing.beacon_interval =
-                       priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval;
-               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
-       } else {
-               beacon_int = iwl_adjust_beacon_interval(beacon_int,
-                       IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT);
-               ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
-       }
-
-       ctx->beacon_int = beacon_int;
-
-       tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
-       interval_tm = beacon_int * TIME_UNIT;
-       rem = do_div(tsf, interval_tm);
-       ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
-       ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
-
-       IWL_DEBUG_ASSOC(priv,
-                       "beacon interval %d beacon timer %d beacon tim %d\n",
-                       le16_to_cpu(ctx->timing.beacon_interval),
-                       le32_to_cpu(ctx->timing.beacon_init_val),
-                       le16_to_cpu(ctx->timing.atim_window));
-
-       return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
-                               CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
-}
-
-static int iwlagn_rxon_disconn(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       int ret;
-       struct iwl_rxon_cmd *active = (void *)&ctx->active;
-
-       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
-               ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
-       } else {
-               ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
-               if (ret)
-                       return ret;
-               if (ctx->vif) {
-                       ret = iwl_send_rxon_timing(priv, ctx);
-                       if (ret) {
-                               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-                               return ret;
-                       }
-                       ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
-               }
-       }
-       if (ret)
-               return ret;
-
-       /*
-        * Un-assoc RXON clears the station table and WEP
-        * keys, so we have to restore those afterwards.
-        */
-       iwl_clear_ucode_stations(priv, ctx);
-       /* update -- might need P2P now */
-       iwl_update_bcast_station(priv, ctx);
-       iwl_restore_stations(priv, ctx);
-       ret = iwl_restore_default_wep_keys(priv, ctx);
-       if (ret) {
-               IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
-               return ret;
-       }
-
-       memcpy(active, &ctx->staging, sizeof(*active));
-       return 0;
-}
-
-static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
-{
-       int ret;
-       s8 prev_tx_power;
-       bool defer;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-       if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED)
-               return 0;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (priv->tx_power_user_lmt == tx_power && !force)
-               return 0;
-
-       if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
-               IWL_WARN(priv,
-                        "Requested user TXPOWER %d below lower limit %d.\n",
-                        tx_power,
-                        IWLAGN_TX_POWER_TARGET_POWER_MIN);
-               return -EINVAL;
-       }
-
-       if (tx_power > priv->tx_power_device_lmt) {
-               IWL_WARN(priv,
-                       "Requested user TXPOWER %d above upper limit %d.\n",
-                        tx_power, priv->tx_power_device_lmt);
-               return -EINVAL;
-       }
-
-       if (!iwl_is_ready_rf(priv))
-               return -EIO;
-
-       /* scan complete and commit_rxon use tx_power_next value,
-        * it always need to be updated for newest request */
-       priv->tx_power_next = tx_power;
-
-       /* do not set tx power when scanning or channel changing */
-       defer = test_bit(STATUS_SCANNING, &priv->status) ||
-               memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
-       if (defer && !force) {
-               IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
-               return 0;
-       }
-
-       prev_tx_power = priv->tx_power_user_lmt;
-       priv->tx_power_user_lmt = tx_power;
-
-       ret = iwlagn_send_tx_power(priv);
-
-       /* if fail to set tx_power, restore the orig. tx power */
-       if (ret) {
-               priv->tx_power_user_lmt = prev_tx_power;
-               priv->tx_power_next = prev_tx_power;
-       }
-       return ret;
-}
-
-static int iwlagn_rxon_connect(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       int ret;
-       struct iwl_rxon_cmd *active = (void *)&ctx->active;
-
-       /* RXON timing must be before associated RXON */
-       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
-               ret = iwl_send_rxon_timing(priv, ctx);
-               if (ret) {
-                       IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-                       return ret;
-               }
-       }
-       /* QoS info may be cleared by previous un-assoc RXON */
-       iwlagn_update_qos(priv, ctx);
-
-       /*
-        * We'll run into this code path when beaconing is
-        * enabled, but then we also need to send the beacon
-        * to the device.
-        */
-       if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
-               ret = iwlagn_update_beacon(priv, ctx->vif);
-               if (ret) {
-                       IWL_ERR(priv,
-                               "Error sending required beacon (%d)!\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       priv->start_calib = 0;
-       /*
-        * Apply the new configuration.
-        *
-        * Associated RXON doesn't clear the station table in uCode,
-        * so we don't need to restore stations etc. after this.
-        */
-       ret = iwl_dvm_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
-                     sizeof(struct iwl_rxon_cmd), &ctx->staging);
-       if (ret) {
-               IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
-               return ret;
-       }
-       memcpy(active, &ctx->staging, sizeof(*active));
-
-       /* IBSS beacon needs to be sent after setting assoc */
-       if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
-               if (iwlagn_update_beacon(priv, ctx->vif))
-                       IWL_ERR(priv, "Error sending IBSS beacon\n");
-       iwl_init_sensitivity(priv);
-
-       /*
-        * If we issue a new RXON command which required a tune then
-        * we must send a new TXPOWER command or we won't be able to
-        * Tx any frames.
-        *
-        * It's expected we set power here if channel is changing.
-        */
-       ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
-       if (ret) {
-               IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
-               return ret;
-       }
-
-       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
-           priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
-               ieee80211_request_smps(ctx->vif,
-                                      priv->cfg->ht_params->smps_mode);
-
-       return 0;
-}
-
-int iwlagn_set_pan_params(struct iwl_priv *priv)
-{
-       struct iwl_wipan_params_cmd cmd;
-       struct iwl_rxon_context *ctx_bss, *ctx_pan;
-       int slot0 = 300, slot1 = 0;
-       int ret;
-
-       if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
-               return 0;
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       lockdep_assert_held(&priv->mutex);
-
-       ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
-       ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
-
-       /*
-        * If the PAN context is inactive, then we don't need
-        * to update the PAN parameters, the last thing we'll
-        * have done before it goes inactive is making the PAN
-        * parameters be WLAN-only.
-        */
-       if (!ctx_pan->is_active)
-               return 0;
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       /* only 2 slots are currently allowed */
-       cmd.num_slots = 2;
-
-       cmd.slots[0].type = 0; /* BSS */
-       cmd.slots[1].type = 1; /* PAN */
-
-       if (priv->hw_roc_setup) {
-               /* both contexts must be used for this to happen */
-               slot1 = IWL_MIN_SLOT_TIME;
-               slot0 = 3000;
-       } else if (ctx_bss->vif && ctx_pan->vif) {
-               int bcnint = ctx_pan->beacon_int;
-               int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
-
-               /* should be set, but seems unused?? */
-               cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
-
-               if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
-                   bcnint &&
-                   bcnint != ctx_bss->beacon_int) {
-                       IWL_ERR(priv,
-                               "beacon intervals don't match (%d, %d)\n",
-                               ctx_bss->beacon_int, ctx_pan->beacon_int);
-               } else
-                       bcnint = max_t(int, bcnint,
-                                      ctx_bss->beacon_int);
-               if (!bcnint)
-                       bcnint = DEFAULT_BEACON_INTERVAL;
-               slot0 = bcnint / 2;
-               slot1 = bcnint - slot0;
-
-               if (test_bit(STATUS_SCAN_HW, &priv->status) ||
-                   (!ctx_bss->vif->bss_conf.idle &&
-                    !ctx_bss->vif->bss_conf.assoc)) {
-                       slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
-                       slot1 = IWL_MIN_SLOT_TIME;
-               } else if (!ctx_pan->vif->bss_conf.idle &&
-                          !ctx_pan->vif->bss_conf.assoc) {
-                       slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
-                       slot0 = IWL_MIN_SLOT_TIME;
-               }
-       } else if (ctx_pan->vif) {
-               slot0 = 0;
-               slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
-                                       ctx_pan->beacon_int;
-               slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
-
-               if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-                       slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
-                       slot1 = IWL_MIN_SLOT_TIME;
-               }
-       }
-
-       cmd.slots[0].width = cpu_to_le16(slot0);
-       cmd.slots[1].width = cpu_to_le16(slot1);
-
-       ret = iwl_dvm_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
-                       sizeof(cmd), &cmd);
-       if (ret)
-               IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
-
-       return ret;
-}
-
-static void _iwl_set_rxon_ht(struct iwl_priv *priv,
-                            struct iwl_ht_config *ht_conf,
-                            struct iwl_rxon_context *ctx)
-{
-       struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-       if (!ctx->ht.enabled) {
-               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-                       RXON_FLG_HT40_PROT_MSK |
-                       RXON_FLG_HT_PROT_MSK);
-               return;
-       }
-
-       /* FIXME: if the definition of ht.protection changed, the "translation"
-        * will be needed for rxon->flags
-        */
-       rxon->flags |= cpu_to_le32(ctx->ht.protection <<
-                                  RXON_FLG_HT_OPERATING_MODE_POS);
-
-       /* Set up channel bandwidth:
-        * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
-       /* clear the HT channel mode before set the mode */
-       rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-       if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
-               /* pure ht40 */
-               if (ctx->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 (ctx->ht.extension_chan_offset) {
-                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-                               rxon->flags &=
-                                       ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-                               break;
-                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                               rxon->flags |=
-                                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-                               break;
-                       }
-               } else {
-                       /*
-                        * Note: control channel is opposite of extension
-                        * channel
-                        */
-                       switch (ctx->ht.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;
-                               break;
-                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-                               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
-                               break;
-                       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-                       default:
-                               /*
-                                * channel location only valid if in Mixed
-                                * mode
-                                */
-                               IWL_ERR(priv,
-                                       "invalid extension channel offset\n");
-                               break;
-                       }
-               }
-       } else {
-               rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
-       }
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
-                       "extension channel offset 0x%x\n",
-                       le32_to_cpu(rxon->flags), ctx->ht.protection,
-                       ctx->ht.extension_chan_offset);
-}
-
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
-{
-       struct iwl_rxon_context *ctx;
-
-       for_each_context(priv, ctx)
-               _iwl_set_rxon_ht(priv, ht_conf, ctx);
-}
-
-/**
- * iwl_set_rxon_channel - Set the band and channel values in staging RXON
- * @ch: requested channel as a pointer to struct ieee80211_channel
-
- * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the ch->band
- */
-void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
-                        struct iwl_rxon_context *ctx)
-{
-       enum ieee80211_band band = ch->band;
-       u16 channel = ch->hw_value;
-
-       if ((le16_to_cpu(ctx->staging.channel) == channel) &&
-           (priv->band == band))
-               return;
-
-       ctx->staging.channel = cpu_to_le16(channel);
-       if (band == IEEE80211_BAND_5GHZ)
-               ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
-       else
-               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
-
-       priv->band = band;
-
-       IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band);
-
-}
-
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           enum ieee80211_band band,
-                           struct ieee80211_vif *vif)
-{
-       if (band == IEEE80211_BAND_5GHZ) {
-               ctx->staging.flags &=
-                   ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
-                     | RXON_FLG_CCK_MSK);
-               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-       } else {
-               /* Copied from iwl_post_associate() */
-               if (vif && vif->bss_conf.use_short_slot)
-                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-               else
-                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
-               ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
-               ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
-       }
-}
-
-static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv,
-                                 struct iwl_rxon_context *ctx, int hw_decrypt)
-{
-       struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-       if (hw_decrypt)
-               rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
-       else
-               rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
-
-}
-
-/* validate RXON structure is valid */
-static int iwl_check_rxon_cmd(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx)
-{
-       struct iwl_rxon_cmd *rxon = &ctx->staging;
-       u32 errors = 0;
-
-       if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
-               if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
-                       IWL_WARN(priv, "check 2.4G: wrong narrow\n");
-                       errors |= BIT(0);
-               }
-               if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
-                       IWL_WARN(priv, "check 2.4G: wrong radar\n");
-                       errors |= BIT(1);
-               }
-       } else {
-               if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
-                       IWL_WARN(priv, "check 5.2G: not short slot!\n");
-                       errors |= BIT(2);
-               }
-               if (rxon->flags & RXON_FLG_CCK_MSK) {
-                       IWL_WARN(priv, "check 5.2G: CCK!\n");
-                       errors |= BIT(3);
-               }
-       }
-       if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
-               IWL_WARN(priv, "mac/bssid mcast!\n");
-               errors |= BIT(4);
-       }
-
-       /* make sure basic rates 6Mbps and 1Mbps are supported */
-       if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
-           (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
-               IWL_WARN(priv, "neither 1 nor 6 are basic\n");
-               errors |= BIT(5);
-       }
-
-       if (le16_to_cpu(rxon->assoc_id) > 2007) {
-               IWL_WARN(priv, "aid > 2007\n");
-               errors |= BIT(6);
-       }
-
-       if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
-                       == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
-               IWL_WARN(priv, "CCK and short slot\n");
-               errors |= BIT(7);
-       }
-
-       if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
-                       == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
-               IWL_WARN(priv, "CCK and auto detect");
-               errors |= BIT(8);
-       }
-
-       if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
-                           RXON_FLG_TGG_PROTECT_MSK)) ==
-                           RXON_FLG_TGG_PROTECT_MSK) {
-               IWL_WARN(priv, "TGg but no auto-detect\n");
-               errors |= BIT(9);
-       }
-
-       if (rxon->channel == 0) {
-               IWL_WARN(priv, "zero channel is invalid\n");
-               errors |= BIT(10);
-       }
-
-       WARN(errors, "Invalid RXON (%#x), channel %d",
-            errors, le16_to_cpu(rxon->channel));
-
-       return errors ? -EINVAL : 0;
-}
-
-/**
- * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
- * @priv: staging_rxon is compared to active_rxon
- *
- * If the RXON structure is changing enough to require a new tune,
- * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
- * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
- */
-int iwl_full_rxon_required(struct iwl_priv *priv,
-                          struct iwl_rxon_context *ctx)
-{
-       const struct iwl_rxon_cmd *staging = &ctx->staging;
-       const struct iwl_rxon_cmd *active = &ctx->active;
-
-#define CHK(cond)                                                      \
-       if ((cond)) {                                                   \
-               IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");   \
-               return 1;                                               \
-       }
-
-#define CHK_NEQ(c1, c2)                                                \
-       if ((c1) != (c2)) {                                     \
-               IWL_DEBUG_INFO(priv, "need full RXON - "        \
-                              #c1 " != " #c2 " - %d != %d\n",  \
-                              (c1), (c2));                     \
-               return 1;                                       \
-       }
-
-       /* These items are only settable from the full RXON command */
-       CHK(!iwl_is_associated_ctx(ctx));
-       CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
-       CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
-       CHK(!ether_addr_equal(staging->wlap_bssid_addr,
-                             active->wlap_bssid_addr));
-       CHK_NEQ(staging->dev_type, active->dev_type);
-       CHK_NEQ(staging->channel, active->channel);
-       CHK_NEQ(staging->air_propagation, active->air_propagation);
-       CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
-               active->ofdm_ht_single_stream_basic_rates);
-       CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
-               active->ofdm_ht_dual_stream_basic_rates);
-       CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
-               active->ofdm_ht_triple_stream_basic_rates);
-       CHK_NEQ(staging->assoc_id, active->assoc_id);
-
-       /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
-        * be updated with the RXON_ASSOC command -- however only some
-        * flag transitions are allowed using RXON_ASSOC */
-
-       /* Check if we are not switching bands */
-       CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
-               active->flags & RXON_FLG_BAND_24G_MSK);
-
-       /* Check if we are switching association toggle */
-       CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
-               active->filter_flags & RXON_FILTER_ASSOC_MSK);
-
-#undef CHK
-#undef CHK_NEQ
-
-       return 0;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-                            enum iwl_rxon_context_id ctxid)
-{
-       struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
-       struct iwl_rxon_cmd *rxon = &ctx->staging;
-
-       IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
-       IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n",
-                       le16_to_cpu(rxon->channel));
-       IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n",
-                       le32_to_cpu(rxon->flags));
-       IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
-                       le32_to_cpu(rxon->filter_flags));
-       IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
-       IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
-                       rxon->ofdm_basic_rates);
-       IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n",
-                       rxon->cck_basic_rates);
-       IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
-       IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
-       IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n",
-                       le16_to_cpu(rxon->assoc_id));
-}
-#endif
-
-static void iwl_calc_basic_rates(struct iwl_priv *priv,
-                                struct iwl_rxon_context *ctx)
-{
-       int lowest_present_ofdm = 100;
-       int lowest_present_cck = 100;
-       u8 cck = 0;
-       u8 ofdm = 0;
-
-       if (ctx->vif) {
-               struct ieee80211_supported_band *sband;
-               unsigned long basic = ctx->vif->bss_conf.basic_rates;
-               int i;
-
-               sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
-
-               for_each_set_bit(i, &basic, BITS_PER_LONG) {
-                       int hw = sband->bitrates[i].hw_value;
-                       if (hw >= IWL_FIRST_OFDM_RATE) {
-                               ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE);
-                               if (lowest_present_ofdm > hw)
-                                       lowest_present_ofdm = hw;
-                       } else {
-                               BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
-
-                               cck |= BIT(hw);
-                               if (lowest_present_cck > hw)
-                                       lowest_present_cck = hw;
-                       }
-               }
-       }
-
-       /*
-        * Now we've got the basic rates as bitmaps in the ofdm and cck
-        * variables. This isn't sufficient though, as there might not
-        * be all the right rates in the bitmap. E.g. if the only basic
-        * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
-        * and 6 Mbps because the 802.11-2007 standard says in 9.6:
-        *
-        *    [...] a STA responding to a received frame shall transmit
-        *    its Control Response frame [...] at the highest rate in the
-        *    BSSBasicRateSet parameter that is less than or equal to the
-        *    rate of the immediately previous frame in the frame exchange
-        *    sequence ([...]) and that is of the same modulation class
-        *    ([...]) as the received frame. If no rate contained in the
-        *    BSSBasicRateSet parameter meets these conditions, then the
-        *    control frame sent in response to a received frame shall be
-        *    transmitted at the highest mandatory rate of the PHY that is
-        *    less than or equal to the rate of the received frame, and
-        *    that is of the same modulation class as the received frame.
-        *
-        * As a consequence, we need to add all mandatory rates that are
-        * lower than all of the basic rates to these bitmaps.
-        */
-
-       if (IWL_RATE_24M_INDEX < lowest_present_ofdm)
-               ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE;
-       if (IWL_RATE_12M_INDEX < lowest_present_ofdm)
-               ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE;
-       /* 6M already there or needed so always add */
-       ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE;
-
-       /*
-        * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
-        * Note, however:
-        *  - if no CCK rates are basic, it must be ERP since there must
-        *    be some basic rates at all, so they're OFDM => ERP PHY
-        *    (or we're in 5 GHz, and the cck bitmap will never be used)
-        *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
-        *  - if 5.5M is basic, 1M and 2M are mandatory
-        *  - if 2M is basic, 1M is mandatory
-        *  - if 1M is basic, that's the only valid ACK rate.
-        * As a consequence, it's not as complicated as it sounds, just add
-        * any lower rates to the ACK rate bitmap.
-        */
-       if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
-               ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
-       if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
-               ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
-       if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
-               ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
-       /* 1M already there or needed so always add */
-       cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
-
-       IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n",
-                      cck, ofdm);
-
-       /* "basic_rates" is a misnomer here -- should be called ACK rates */
-       ctx->staging.cck_basic_rates = cck;
-       ctx->staging.ofdm_basic_rates = ofdm;
-}
-
-/**
- * iwlagn_commit_rxon - commit staging_rxon to hardware
- *
- * The RXON command in staging_rxon is committed to the hardware and
- * the active_rxon structure is updated with the new data.  This
- * function correctly transitions out of the RXON_ASSOC_MSK state if
- * a HW tune is required based on the RXON structure changes.
- *
- * The connect/disconnect flow should be as the following:
- *
- * 1. make sure send RXON command with association bit unset if not connect
- *     this should include the channel and the band for the candidate
- *     to be connected to
- * 2. Add Station before RXON association with the AP
- * 3. RXON_timing has to send before RXON for connection
- * 4. full RXON command - associated bit set
- * 5. use RXON_ASSOC command to update any flags changes
- */
-int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       /* cast away the const for active_rxon in this function */
-       struct iwl_rxon_cmd *active = (void *)&ctx->active;
-       bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (!iwl_is_alive(priv))
-               return -EBUSY;
-
-       /* This function hardcodes a bunch of dual-mode assumptions */
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       if (!ctx->is_active)
-               return 0;
-
-       /* always get timestamp with Rx frame */
-       ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
-
-       /* recalculate basic rates */
-       iwl_calc_basic_rates(priv, ctx);
-
-       /*
-        * force CTS-to-self frames protection if RTS-CTS is not preferred
-        * one aggregation protection method
-        */
-       if (!priv->hw_params.use_rts_for_aggregation)
-               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
-
-       if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
-           !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
-               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
-       else
-               ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-       iwl_print_rx_config_cmd(priv, ctx->ctxid);
-       ret = iwl_check_rxon_cmd(priv, ctx);
-       if (ret) {
-               IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
-               return -EINVAL;
-       }
-
-       /*
-        * receive commit_rxon request
-        * abort any previous channel switch if still in process
-        */
-       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
-           (priv->switch_channel != ctx->staging.channel)) {
-               IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
-                             le16_to_cpu(priv->switch_channel));
-               iwl_chswitch_done(priv, false);
-       }
-
-       /*
-        * If we don't need to send a full RXON, we can use
-        * iwl_rxon_assoc_cmd which is used to reconfigure filter
-        * and other flags for the current radio configuration.
-        */
-       if (!iwl_full_rxon_required(priv, ctx)) {
-               ret = iwlagn_send_rxon_assoc(priv, ctx);
-               if (ret) {
-                       IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
-                       return ret;
-               }
-
-               memcpy(active, &ctx->staging, sizeof(*active));
-               /*
-                * We do not commit tx power settings while channel changing,
-                * do it now if after settings changed.
-                */
-               iwl_set_tx_power(priv, priv->tx_power_next, false);
-
-               /* make sure we are in the right PS state */
-               iwl_power_update_mode(priv, true);
-
-               return 0;
-       }
-
-       iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto);
-
-       IWL_DEBUG_INFO(priv,
-                      "Going to commit RXON\n"
-                      "  * with%s RXON_FILTER_ASSOC_MSK\n"
-                      "  * channel = %d\n"
-                      "  * bssid = %pM\n",
-                      (new_assoc ? "" : "out"),
-                      le16_to_cpu(ctx->staging.channel),
-                      ctx->staging.bssid_addr);
-
-       /*
-        * Always clear associated first, but with the correct config.
-        * This is required as for example station addition for the
-        * AP station must be done after the BSSID is set to correctly
-        * set up filters in the device.
-        */
-       ret = iwlagn_rxon_disconn(priv, ctx);
-       if (ret)
-               return ret;
-
-       ret = iwlagn_set_pan_params(priv);
-       if (ret)
-               return ret;
-
-       if (new_assoc)
-               return iwlagn_rxon_connect(priv, ctx);
-
-       return 0;
-}
-
-void iwlagn_config_ht40(struct ieee80211_conf *conf,
-       struct iwl_rxon_context *ctx)
-{
-       if (conf_is_ht40_minus(conf)) {
-               ctx->ht.extension_chan_offset =
-                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-               ctx->ht.is_40mhz = true;
-       } else if (conf_is_ht40_plus(conf)) {
-               ctx->ht.extension_chan_offset =
-                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-               ctx->ht.is_40mhz = true;
-       } else {
-               ctx->ht.extension_chan_offset =
-                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
-               ctx->ht.is_40mhz = false;
-       }
-}
-
-int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_channel *channel = conf->channel;
-       const struct iwl_channel_info *ch_info;
-       int ret = 0;
-
-       IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
-
-       mutex_lock(&priv->mutex);
-
-       if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
-               IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
-               goto out;
-       }
-
-       if (!iwl_is_ready(priv)) {
-               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
-               goto out;
-       }
-
-       if (changed & (IEEE80211_CONF_CHANGE_SMPS |
-                      IEEE80211_CONF_CHANGE_CHANNEL)) {
-               /* mac80211 uses static for non-HT which is what we want */
-               priv->current_ht_config.smps = conf->smps_mode;
-
-               /*
-                * Recalculate chain counts.
-                *
-                * If monitor mode is enabled then mac80211 will
-                * set up the SM PS mode to OFF if an HT channel is
-                * configured.
-                */
-               for_each_context(priv, ctx)
-                       iwlagn_set_rxon_chain(priv, ctx);
-       }
-
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ch_info = iwl_get_channel_info(priv, channel->band,
-                                              channel->hw_value);
-               if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               for_each_context(priv, ctx) {
-                       /* Configure HT40 channels */
-                       if (ctx->ht.enabled != conf_is_ht(conf))
-                               ctx->ht.enabled = conf_is_ht(conf);
-
-                       if (ctx->ht.enabled) {
-                               /* if HT40 is used, it should not change
-                                * after associated except channel switch */
-                               if (!ctx->ht.is_40mhz ||
-                                               !iwl_is_associated_ctx(ctx))
-                                       iwlagn_config_ht40(conf, ctx);
-                       } else
-                               ctx->ht.is_40mhz = false;
-
-                       /*
-                        * Default to no protection. Protection mode will
-                        * later be set from BSS config in iwl_ht_conf
-                        */
-                       ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
-
-                       /* if we are switching from ht to 2.4 clear flags
-                        * from any ht related info since 2.4 does not
-                        * support ht */
-                       if (le16_to_cpu(ctx->staging.channel) !=
-                           channel->hw_value)
-                               ctx->staging.flags = 0;
-
-                       iwl_set_rxon_channel(priv, channel, ctx);
-                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
-
-                       iwl_set_flags_for_band(priv, ctx, channel->band,
-                                              ctx->vif);
-               }
-
-               iwl_update_bcast_stations(priv);
-       }
-
-       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");
-       }
-
-       if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n",
-                       priv->tx_power_user_lmt, conf->power_level);
-
-               iwl_set_tx_power(priv, conf->power_level, false);
-       }
-
-       for_each_context(priv, ctx) {
-               if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-                       continue;
-               iwlagn_commit_rxon(priv, ctx);
-       }
- out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-void iwlagn_check_needed_chains(struct iwl_priv *priv,
-                               struct iwl_rxon_context *ctx,
-                               struct ieee80211_bss_conf *bss_conf)
-{
-       struct ieee80211_vif *vif = ctx->vif;
-       struct iwl_rxon_context *tmp;
-       struct ieee80211_sta *sta;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-       struct ieee80211_sta_ht_cap *ht_cap;
-       bool need_multiple;
-
-       lockdep_assert_held(&priv->mutex);
-
-       switch (vif->type) {
-       case NL80211_IFTYPE_STATION:
-               rcu_read_lock();
-               sta = ieee80211_find_sta(vif, bss_conf->bssid);
-               if (!sta) {
-                       /*
-                        * 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.
-                        */
-                       need_multiple = false;
-                       rcu_read_unlock();
-                       break;
-               }
-
-               ht_cap = &sta->ht_cap;
-
-               need_multiple = true;
-
-               /*
-                * If the peer advertises no support for receiving 2 and 3
-                * stream MCS rates, it can't be transmitting them either.
-                */
-               if (ht_cap->mcs.rx_mask[1] == 0 &&
-                   ht_cap->mcs.rx_mask[2] == 0) {
-                       need_multiple = false;
-               } else if (!(ht_cap->mcs.tx_params &
-                                               IEEE80211_HT_MCS_TX_DEFINED)) {
-                       /* If it can't TX MCS at all ... */
-                       need_multiple = false;
-               } else if (ht_cap->mcs.tx_params &
-                                               IEEE80211_HT_MCS_TX_RX_DIFF) {
-                       int maxstreams;
-
-                       /*
-                        * But if it can receive them, it might still not
-                        * be able to transmit them, which is what we need
-                        * to check here -- so check the number of streams
-                        * it advertises for TX (if different from RX).
-                        */
-
-                       maxstreams = (ht_cap->mcs.tx_params &
-                                IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK);
-                       maxstreams >>=
-                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
-                       maxstreams += 1;
-
-                       if (maxstreams <= 1)
-                               need_multiple = false;
-               }
-
-               rcu_read_unlock();
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               /* currently */
-               need_multiple = false;
-               break;
-       default:
-               /* only AP really */
-               need_multiple = true;
-               break;
-       }
-
-       ctx->ht_need_multiple_chains = need_multiple;
-
-       if (!need_multiple) {
-               /* check all contexts */
-               for_each_context(priv, tmp) {
-                       if (!tmp->vif)
-                               continue;
-                       if (tmp->ht_need_multiple_chains) {
-                               need_multiple = true;
-                               break;
-                       }
-               }
-       }
-
-       ht_conf->single_chain_sufficient = !need_multiple;
-}
-
-void iwlagn_chain_noise_reset(struct iwl_priv *priv)
-{
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-       int ret;
-
-       if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
-               return;
-
-       if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-           iwl_is_any_associated(priv)) {
-               struct iwl_calib_chain_noise_reset_cmd cmd;
-
-               /* clear data for chain noise calibration algorithm */
-               data->chain_noise_a = 0;
-               data->chain_noise_b = 0;
-               data->chain_noise_c = 0;
-               data->chain_signal_a = 0;
-               data->chain_signal_b = 0;
-               data->chain_signal_c = 0;
-               data->beacon_count = 0;
-
-               memset(&cmd, 0, sizeof(cmd));
-               iwl_set_calib_hdr(&cmd.hdr,
-                       priv->phy_calib_chain_noise_reset_cmd);
-               ret = iwl_dvm_send_cmd_pdu(priv,
-                                       REPLY_PHY_CALIBRATION_CMD,
-                                       CMD_SYNC, sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv,
-                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
-               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
-       }
-}
-
-void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_bss_conf *bss_conf,
-                            u32 changes)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       int ret;
-       bool force = false;
-
-       mutex_lock(&priv->mutex);
-
-       if (unlikely(!iwl_is_ready(priv))) {
-               IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
-               mutex_unlock(&priv->mutex);
-               return;
-        }
-
-       if (unlikely(!ctx->vif)) {
-               IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n");
-               mutex_unlock(&priv->mutex);
-               return;
-       }
-
-       if (changes & BSS_CHANGED_BEACON_INT)
-               force = true;
-
-       if (changes & BSS_CHANGED_QOS) {
-               ctx->qos_data.qos_active = bss_conf->qos;
-               iwlagn_update_qos(priv, ctx);
-       }
-
-       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
-       if (vif->bss_conf.use_short_preamble)
-               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-       else
-               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-
-       if (changes & BSS_CHANGED_ASSOC) {
-               if (bss_conf->assoc) {
-                       priv->timestamp = bss_conf->last_tsf;
-                       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               } else {
-                       /*
-                        * If we disassociate while there are pending
-                        * frames, just wake up the queues and let the
-                        * frames "escape" ... This shouldn't really
-                        * be happening to start with, but we should
-                        * not get stuck in this case either since it
-                        * can happen if userspace gets confused.
-                        */
-                       iwlagn_lift_passive_no_rx(priv);
-
-                       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-                       if (ctx->ctxid == IWL_RXON_CTX_BSS)
-                               priv->have_rekey_data = false;
-               }
-
-               iwlagn_bt_coex_rssi_monitor(priv);
-       }
-
-       if (ctx->ht.enabled) {
-               ctx->ht.protection = bss_conf->ht_operation_mode &
-                                       IEEE80211_HT_OP_MODE_PROTECTION;
-               ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode &
-                                       IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-               iwlagn_check_needed_chains(priv, ctx, bss_conf);
-               iwl_set_rxon_ht(priv, &priv->current_ht_config);
-       }
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
-               ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
-       else
-               ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
-
-       if (bss_conf->use_cts_prot)
-               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
-       else
-               ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
-
-       memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
-
-       if (vif->type == NL80211_IFTYPE_AP ||
-           vif->type == NL80211_IFTYPE_ADHOC) {
-               if (vif->bss_conf.enable_beacon) {
-                       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-                       priv->beacon_ctx = ctx;
-               } else {
-                       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-                       priv->beacon_ctx = NULL;
-               }
-       }
-
-       /*
-        * If the ucode decides to do beacon filtering before
-        * association, it will lose beacons that are needed
-        * before sending frames out on passive channels. This
-        * causes association failures on those channels. Enable
-        * receiving beacons in such cases.
-        */
-
-       if (vif->type == NL80211_IFTYPE_STATION) {
-               if (!bss_conf->assoc)
-                       ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
-               else
-                       ctx->staging.filter_flags &=
-                                                   ~RXON_FILTER_BCON_AWARE_MSK;
-       }
-
-       if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-               iwlagn_commit_rxon(priv, ctx);
-
-       if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
-               /*
-                * The chain noise calibration will enable PM upon
-                * completion. If calibration has already been run
-                * then we need to enable power management here.
-                */
-               if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
-                       iwl_power_update_mode(priv, false);
-
-               /* Enable RX differential gain and sensitivity calibrations */
-               iwlagn_chain_noise_reset(priv);
-               priv->start_calib = 1;
-       }
-
-       if (changes & BSS_CHANGED_IBSS) {
-               ret = iwlagn_manage_ibss_station(priv, vif,
-                                                bss_conf->ibss_joined);
-               if (ret)
-                       IWL_ERR(priv, "failed to %s IBSS station %pM\n",
-                               bss_conf->ibss_joined ? "add" : "remove",
-                               bss_conf->bssid);
-       }
-
-       if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC &&
-           priv->beacon_ctx) {
-               if (iwlagn_update_beacon(priv, vif))
-                       IWL_ERR(priv, "Error sending IBSS beacon\n");
-       }
-
-       mutex_unlock(&priv->mutex);
-}
-
-void iwlagn_post_scan(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-
-       /*
-        * We do not commit power settings while scan is pending,
-        * do it now if the settings changed.
-        */
-       iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
-       iwl_set_tx_power(priv, priv->tx_power_next, false);
-
-       /*
-        * Since setting the RXON may have been deferred while
-        * performing the scan, fire one off if needed
-        */
-       for_each_context(priv, ctx)
-               if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
-                       iwlagn_commit_rxon(priv, ctx);
-
-       iwlagn_set_pan_params(priv);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
deleted file mode 100644 (file)
index eb6a8ea..0000000
+++ /dev/null
@@ -1,1501 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
-{
-       lockdep_assert_held(&priv->sta_lock);
-
-       if (sta_id >= IWLAGN_STATION_COUNT) {
-               IWL_ERR(priv, "invalid sta_id %u", sta_id);
-               return -EINVAL;
-       }
-       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
-               IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u "
-                       "addr %pM\n",
-                       sta_id, priv->stations[sta_id].sta.sta.addr);
-
-       if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
-               IWL_DEBUG_ASSOC(priv,
-                               "STA id %u addr %pM already present in uCode "
-                               "(according to driver)\n",
-                               sta_id, priv->stations[sta_id].sta.sta.addr);
-       } else {
-               priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
-               IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
-                               sta_id, priv->stations[sta_id].sta.sta.addr);
-       }
-       return 0;
-}
-
-static int iwl_process_add_sta_resp(struct iwl_priv *priv,
-                                   struct iwl_addsta_cmd *addsta,
-                                   struct iwl_rx_packet *pkt)
-{
-       struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data;
-       u8 sta_id = addsta->sta.sta_id;
-       int ret = -EIO;
-
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
-                       pkt->hdr.flags);
-               return ret;
-       }
-
-       IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
-                      sta_id);
-
-       spin_lock(&priv->sta_lock);
-
-       switch (add_sta_resp->status) {
-       case ADD_STA_SUCCESS_MSK:
-               IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
-               ret = iwl_sta_ucode_activate(priv, sta_id);
-               break;
-       case ADD_STA_NO_ROOM_IN_TABLE:
-               IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
-                       sta_id);
-               break;
-       case ADD_STA_NO_BLOCK_ACK_RESOURCE:
-               IWL_ERR(priv, "Adding station %d failed, no block ack "
-                       "resource.\n", sta_id);
-               break;
-       case ADD_STA_MODIFY_NON_EXIST_STA:
-               IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
-                       sta_id);
-               break;
-       default:
-               IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
-                               add_sta_resp->status);
-               break;
-       }
-
-       IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
-                      priv->stations[sta_id].sta.mode ==
-                      STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added",
-                      sta_id, priv->stations[sta_id].sta.sta.addr);
-
-       /*
-        * XXX: The MAC address in the command buffer is often changed from
-        * the original sent to the device. That is, the MAC address
-        * written to the command buffer often is not the same MAC address
-        * read from the command buffer when the command returns. This
-        * issue has not yet been resolved and this debugging is left to
-        * observe the problem.
-        */
-       IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
-                      priv->stations[sta_id].sta.mode ==
-                      STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
-                      addsta->sta.addr);
-       spin_unlock(&priv->sta_lock);
-
-       return ret;
-}
-
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_addsta_cmd *addsta =
-               (struct iwl_addsta_cmd *) cmd->payload;
-
-       return iwl_process_add_sta_resp(priv, addsta, pkt);
-}
-
-int iwl_send_add_sta(struct iwl_priv *priv,
-                    struct iwl_addsta_cmd *sta, u8 flags)
-{
-       int ret = 0;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_ADD_STA,
-               .flags = flags,
-               .data = { sta, },
-               .len = { sizeof(*sta), },
-       };
-       u8 sta_id __maybe_unused = sta->sta.sta_id;
-
-       IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
-                      sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
-
-       if (!(flags & CMD_ASYNC)) {
-               cmd.flags |= CMD_WANT_SKB;
-               might_sleep();
-       }
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-
-       if (ret || (flags & CMD_ASYNC))
-               return ret;
-       /*else the command was successfully sent in SYNC mode, need to free
-        * the reply page */
-
-       iwl_free_resp(&cmd);
-
-       if (cmd.handler_status)
-               IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
-                       cmd.handler_status);
-
-       return cmd.handler_status;
-}
-
-static bool iwl_is_channel_extension(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    u16 channel, u8 extension_chan_offset)
-{
-       const struct iwl_channel_info *ch_info;
-
-       ch_info = iwl_get_channel_info(priv, band, channel);
-       if (!is_channel_valid(ch_info))
-               return false;
-
-       if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
-               return !(ch_info->ht40_extension_channel &
-                                       IEEE80211_CHAN_NO_HT40PLUS);
-       else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
-               return !(ch_info->ht40_extension_channel &
-                                       IEEE80211_CHAN_NO_HT40MINUS);
-
-       return false;
-}
-
-bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           struct ieee80211_sta_ht_cap *ht_cap)
-{
-       if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
-               return false;
-
-       /*
-        * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
-        * the bit will not set if it is pure 40MHz case
-        */
-       if (ht_cap && !ht_cap->ht_supported)
-               return false;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       if (priv->disable_ht40)
-               return false;
-#endif
-
-       return iwl_is_channel_extension(priv, priv->band,
-                       le16_to_cpu(ctx->staging.channel),
-                       ctx->ht.extension_chan_offset);
-}
-
-static void iwl_sta_calc_ht_flags(struct iwl_priv *priv,
-                                 struct ieee80211_sta *sta,
-                                 struct iwl_rxon_context *ctx,
-                                 __le32 *flags, __le32 *mask)
-{
-       struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
-       u8 mimo_ps_mode;
-
-       *mask = STA_FLG_RTS_MIMO_PROT_MSK |
-               STA_FLG_MIMO_DIS_MSK |
-               STA_FLG_HT40_EN_MSK |
-               STA_FLG_MAX_AGG_SIZE_MSK |
-               STA_FLG_AGG_MPDU_DENSITY_MSK;
-       *flags = 0;
-
-       if (!sta || !sta_ht_inf->ht_supported)
-               return;
-
-       mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
-
-       IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n",
-                       (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ?
-                       "static" :
-                       (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ?
-                       "dynamic" : "disabled");
-
-       switch (mimo_ps_mode) {
-       case WLAN_HT_CAP_SM_PS_STATIC:
-               *flags |= STA_FLG_MIMO_DIS_MSK;
-               break;
-       case WLAN_HT_CAP_SM_PS_DYNAMIC:
-               *flags |= STA_FLG_RTS_MIMO_PROT_MSK;
-               break;
-       case WLAN_HT_CAP_SM_PS_DISABLED:
-               break;
-       default:
-               IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
-               break;
-       }
-
-       *flags |= cpu_to_le32(
-               (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
-
-       *flags |= cpu_to_le32(
-               (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
-
-       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
-               *flags |= STA_FLG_HT40_EN_MSK;
-}
-
-int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                     struct ieee80211_sta *sta)
-{
-       u8 sta_id = iwl_sta_id(sta);
-       __le32 flags, mask;
-       struct iwl_addsta_cmd cmd;
-
-       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
-               return -EINVAL;
-
-       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].sta.station_flags &= ~mask;
-       priv->stations[sta_id].sta.station_flags |= flags;
-       spin_unlock_bh(&priv->sta_lock);
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.mode = STA_CONTROL_MODIFY_MSK;
-       cmd.station_flags_msk = mask;
-       cmd.station_flags = flags;
-       cmd.sta.sta_id = sta_id;
-
-       return iwl_send_add_sta(priv, &cmd, CMD_SYNC);
-}
-
-static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                                  struct ieee80211_sta *sta,
-                                  struct iwl_rxon_context *ctx)
-{
-       __le32 flags, mask;
-
-       iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask);
-
-       lockdep_assert_held(&priv->sta_lock);
-       priv->stations[index].sta.station_flags &= ~mask;
-       priv->stations[index].sta.station_flags |= flags;
-}
-
-/**
- * iwl_prep_station - Prepare station information for addition
- *
- * should be called with sta_lock held
- */
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                   const u8 *addr, bool is_ap, struct ieee80211_sta *sta)
-{
-       struct iwl_station_entry *station;
-       int i;
-       u8 sta_id = IWL_INVALID_STATION;
-
-       if (is_ap)
-               sta_id = ctx->ap_sta_id;
-       else if (is_broadcast_ether_addr(addr))
-               sta_id = ctx->bcast_sta_id;
-       else
-               for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) {
-                       if (ether_addr_equal(priv->stations[i].sta.sta.addr,
-                                            addr)) {
-                               sta_id = i;
-                               break;
-                       }
-
-                       if (!priv->stations[i].used &&
-                           sta_id == IWL_INVALID_STATION)
-                               sta_id = i;
-               }
-
-       /*
-        * These two conditions have the same outcome, but keep them
-        * separate
-        */
-       if (unlikely(sta_id == IWL_INVALID_STATION))
-               return sta_id;
-
-       /*
-        * uCode is not able to deal with multiple requests to add a
-        * station. Keep track if one is in progress so that we do not send
-        * another.
-        */
-       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
-               IWL_DEBUG_INFO(priv, "STA %d already in process of being "
-                              "added.\n", sta_id);
-               return sta_id;
-       }
-
-       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
-           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
-           ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) {
-               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
-                               "adding again.\n", sta_id, addr);
-               return sta_id;
-       }
-
-       station = &priv->stations[sta_id];
-       station->used = IWL_STA_DRIVER_ACTIVE;
-       IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
-                       sta_id, addr);
-       priv->num_stations++;
-
-       /* Set up the REPLY_ADD_STA command to send to device */
-       memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
-       memcpy(station->sta.sta.addr, addr, ETH_ALEN);
-       station->sta.mode = 0;
-       station->sta.sta.sta_id = sta_id;
-       station->sta.station_flags = ctx->station_flags;
-       station->ctxid = ctx->ctxid;
-
-       if (sta) {
-               struct iwl_station_priv *sta_priv;
-
-               sta_priv = (void *)sta->drv_priv;
-               sta_priv->ctx = ctx;
-       }
-
-       /*
-        * OK to call unconditionally, since local stations (IBSS BSSID
-        * STA and broadcast STA) pass in a NULL sta, and mac80211
-        * doesn't allow HT IBSS.
-        */
-       iwl_set_ht_add_station(priv, sta_id, sta, ctx);
-
-       return sta_id;
-
-}
-
-#define STA_WAIT_TIMEOUT (HZ/2)
-
-/**
- * iwl_add_station_common -
- */
-int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                          const u8 *addr, bool is_ap,
-                          struct ieee80211_sta *sta, u8 *sta_id_r)
-{
-       int ret = 0;
-       u8 sta_id;
-       struct iwl_addsta_cmd sta_cmd;
-
-       *sta_id_r = 0;
-       spin_lock_bh(&priv->sta_lock);
-       sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
-                       addr);
-               spin_unlock_bh(&priv->sta_lock);
-               return -EINVAL;
-       }
-
-       /*
-        * uCode is not able to deal with multiple requests to add a
-        * station. Keep track if one is in progress so that we do not send
-        * another.
-        */
-       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
-               IWL_DEBUG_INFO(priv, "STA %d already in process of being "
-                              "added.\n", sta_id);
-               spin_unlock_bh(&priv->sta_lock);
-               return -EEXIST;
-       }
-
-       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
-           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not "
-                               "adding again.\n", sta_id, addr);
-               spin_unlock_bh(&priv->sta_lock);
-               return -EEXIST;
-       }
-
-       priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta,
-              sizeof(struct iwl_addsta_cmd));
-       spin_unlock_bh(&priv->sta_lock);
-
-       /* Add station to device's station table */
-       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-       if (ret) {
-               spin_lock_bh(&priv->sta_lock);
-               IWL_ERR(priv, "Adding station %pM failed.\n",
-                       priv->stations[sta_id].sta.sta.addr);
-               priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-               priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
-               spin_unlock_bh(&priv->sta_lock);
-       }
-       *sta_id_r = sta_id;
-       return ret;
-}
-
-/**
- * iwl_sta_ucode_deactivate - deactivate ucode status for a station
- */
-static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
-{
-       lockdep_assert_held(&priv->sta_lock);
-
-       /* Ucode must be active and driver must be non active */
-       if ((priv->stations[sta_id].used &
-            (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) !=
-             IWL_STA_UCODE_ACTIVE)
-               IWL_ERR(priv, "removed non active STA %u\n", sta_id);
-
-       priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
-
-       memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
-       IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
-}
-
-static int iwl_send_remove_station(struct iwl_priv *priv,
-                                  const u8 *addr, int sta_id,
-                                  bool temporary)
-{
-       struct iwl_rx_packet *pkt;
-       int ret;
-       struct iwl_rem_sta_cmd rm_sta_cmd;
-
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_REMOVE_STA,
-               .len = { sizeof(struct iwl_rem_sta_cmd), },
-               .flags = CMD_SYNC,
-               .data = { &rm_sta_cmd, },
-       };
-
-       memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
-       rm_sta_cmd.num_sta = 1;
-       memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
-
-       cmd.flags |= CMD_WANT_SKB;
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-
-       if (ret)
-               return ret;
-
-       pkt = cmd.resp_pkt;
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
-                         pkt->hdr.flags);
-               ret = -EIO;
-       }
-
-       if (!ret) {
-               struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data;
-               switch (rem_sta_resp->status) {
-               case REM_STA_SUCCESS_MSK:
-                       if (!temporary) {
-                               spin_lock_bh(&priv->sta_lock);
-                               iwl_sta_ucode_deactivate(priv, sta_id);
-                               spin_unlock_bh(&priv->sta_lock);
-                       }
-                       IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
-                       break;
-               default:
-                       ret = -EIO;
-                       IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
-                       break;
-               }
-       }
-       iwl_free_resp(&cmd);
-
-       return ret;
-}
-
-/**
- * iwl_remove_station - Remove driver's knowledge of station.
- */
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
-                      const u8 *addr)
-{
-       u8 tid;
-
-       if (!iwl_is_ready(priv)) {
-               IWL_DEBUG_INFO(priv,
-                       "Unable to remove station %pM, device not ready.\n",
-                       addr);
-               /*
-                * It is typical for stations to be removed when we are
-                * going down. Return success since device will be down
-                * soon anyway
-                */
-               return 0;
-       }
-
-       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
-                       sta_id, addr);
-
-       if (WARN_ON(sta_id == IWL_INVALID_STATION))
-               return -EINVAL;
-
-       spin_lock_bh(&priv->sta_lock);
-
-       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-               IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
-                               addr);
-               goto out_err;
-       }
-
-       if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-               IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
-                               addr);
-               goto out_err;
-       }
-
-       if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
-               kfree(priv->stations[sta_id].lq);
-               priv->stations[sta_id].lq = NULL;
-       }
-
-       for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
-               memset(&priv->tid_data[sta_id][tid], 0,
-                       sizeof(priv->tid_data[sta_id][tid]));
-
-       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-
-       priv->num_stations--;
-
-       if (WARN_ON(priv->num_stations < 0))
-               priv->num_stations = 0;
-
-       spin_unlock_bh(&priv->sta_lock);
-
-       return iwl_send_remove_station(priv, addr, sta_id, false);
-out_err:
-       spin_unlock_bh(&priv->sta_lock);
-       return -EINVAL;
-}
-
-void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
-                           const u8 *addr)
-{
-       u8 tid;
-
-       if (!iwl_is_ready(priv)) {
-               IWL_DEBUG_INFO(priv,
-                       "Unable to remove station %pM, device not ready.\n",
-                       addr);
-               return;
-       }
-
-       IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
-
-       if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
-               return;
-
-       spin_lock_bh(&priv->sta_lock);
-
-       WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
-
-       for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
-               memset(&priv->tid_data[sta_id][tid], 0,
-                       sizeof(priv->tid_data[sta_id][tid]));
-
-       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
-
-       priv->num_stations--;
-
-       if (WARN_ON_ONCE(priv->num_stations < 0))
-               priv->num_stations = 0;
-
-       spin_unlock_bh(&priv->sta_lock);
-}
-
-static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                           u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
-{
-       int i, r;
-       u32 rate_flags = 0;
-       __le32 rate_n_flags;
-
-       lockdep_assert_held(&priv->mutex);
-
-       memset(link_cmd, 0, sizeof(*link_cmd));
-
-       /* Set up the rate scaling to start at selected rate, fall back
-        * all the way down to 1M in IEEE order, and then spin on 1M */
-       if (priv->band == IEEE80211_BAND_5GHZ)
-               r = IWL_RATE_6M_INDEX;
-       else if (ctx && ctx->vif && ctx->vif->p2p)
-               r = IWL_RATE_6M_INDEX;
-       else
-               r = IWL_RATE_1M_INDEX;
-
-       if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-       rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
-                               RATE_MCS_ANT_POS;
-       rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
-               link_cmd->rs_table[i].rate_n_flags = rate_n_flags;
-
-       link_cmd->general_params.single_stream_ant_msk =
-                       first_antenna(priv->hw_params.valid_tx_ant);
-
-       link_cmd->general_params.dual_stream_ant_msk =
-               priv->hw_params.valid_tx_ant &
-               ~first_antenna(priv->hw_params.valid_tx_ant);
-       if (!link_cmd->general_params.dual_stream_ant_msk) {
-               link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
-       } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
-               link_cmd->general_params.dual_stream_ant_msk =
-                       priv->hw_params.valid_tx_ant;
-       }
-
-       link_cmd->agg_params.agg_dis_start_th =
-               LINK_QUAL_AGG_DISABLE_START_DEF;
-       link_cmd->agg_params.agg_time_limit =
-               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-
-       link_cmd->sta_id = sta_id;
-}
-
-/**
- * iwl_clear_ucode_stations - clear ucode station table bits
- *
- * This function clears all the bits in the driver indicating
- * which stations are active in the ucode. Call when something
- * other than explicit station management would cause this in
- * the ucode, e.g. unassociated RXON.
- */
-void iwl_clear_ucode_stations(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx)
-{
-       int i;
-       bool cleared = false;
-
-       IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
-
-       spin_lock_bh(&priv->sta_lock);
-       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-               if (ctx && ctx->ctxid != priv->stations[i].ctxid)
-                       continue;
-
-               if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
-                       IWL_DEBUG_INFO(priv,
-                               "Clearing ucode active for station %d\n", i);
-                       priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
-                       cleared = true;
-               }
-       }
-       spin_unlock_bh(&priv->sta_lock);
-
-       if (!cleared)
-               IWL_DEBUG_INFO(priv,
-                              "No active stations found to be cleared\n");
-}
-
-/**
- * iwl_restore_stations() - Restore driver known stations to device
- *
- * All stations considered active by driver, but not present in ucode, is
- * restored.
- *
- * Function sleeps.
- */
-void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       struct iwl_addsta_cmd sta_cmd;
-       struct iwl_link_quality_cmd lq;
-       int i;
-       bool found = false;
-       int ret;
-       bool send_lq;
-
-       if (!iwl_is_ready(priv)) {
-               IWL_DEBUG_INFO(priv,
-                              "Not ready yet, not restoring any stations.\n");
-               return;
-       }
-
-       IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
-       spin_lock_bh(&priv->sta_lock);
-       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-               if (ctx->ctxid != priv->stations[i].ctxid)
-                       continue;
-               if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
-                           !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
-                       IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
-                                       priv->stations[i].sta.sta.addr);
-                       priv->stations[i].sta.mode = 0;
-                       priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
-                       found = true;
-               }
-       }
-
-       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-               if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
-                       memcpy(&sta_cmd, &priv->stations[i].sta,
-                              sizeof(struct iwl_addsta_cmd));
-                       send_lq = false;
-                       if (priv->stations[i].lq) {
-                               if (priv->wowlan)
-                                       iwl_sta_fill_lq(priv, ctx, i, &lq);
-                               else
-                                       memcpy(&lq, priv->stations[i].lq,
-                                              sizeof(struct iwl_link_quality_cmd));
-                               send_lq = true;
-                       }
-                       spin_unlock_bh(&priv->sta_lock);
-                       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-                       if (ret) {
-                               spin_lock_bh(&priv->sta_lock);
-                               IWL_ERR(priv, "Adding station %pM failed.\n",
-                                       priv->stations[i].sta.sta.addr);
-                               priv->stations[i].used &=
-                                               ~IWL_STA_DRIVER_ACTIVE;
-                               priv->stations[i].used &=
-                                               ~IWL_STA_UCODE_INPROGRESS;
-                               continue;
-                       }
-                       /*
-                        * Rate scaling has already been initialized, send
-                        * current LQ command
-                        */
-                       if (send_lq)
-                               iwl_send_lq_cmd(priv, ctx, &lq,
-                                               CMD_SYNC, true);
-                       spin_lock_bh(&priv->sta_lock);
-                       priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
-               }
-       }
-
-       spin_unlock_bh(&priv->sta_lock);
-       if (!found)
-               IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
-                       "no stations to be restored.\n");
-       else
-               IWL_DEBUG_INFO(priv, "Restoring all known stations .... "
-                       "complete.\n");
-}
-
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->sta_key_max_num; i++)
-               if (!test_and_set_bit(i, &priv->ucode_key_table))
-                       return i;
-
-       return WEP_INVALID_OFFSET;
-}
-
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
-{
-       int i;
-
-       spin_lock_bh(&priv->sta_lock);
-       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-               if (!(priv->stations[i].used & IWL_STA_BCAST))
-                       continue;
-
-               priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
-               priv->num_stations--;
-               if (WARN_ON(priv->num_stations < 0))
-                       priv->num_stations = 0;
-               kfree(priv->stations[i].lq);
-               priv->stations[i].lq = NULL;
-       }
-       spin_unlock_bh(&priv->sta_lock);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl_dump_lq_cmd(struct iwl_priv *priv,
-                          struct iwl_link_quality_cmd *lq)
-{
-       int i;
-       IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
-       IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
-                      lq->general_params.single_stream_ant_msk,
-                      lq->general_params.dual_stream_ant_msk);
-
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
-               IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
-                              i, lq->rs_table[i].rate_n_flags);
-}
-#else
-static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
-                                  struct iwl_link_quality_cmd *lq)
-{
-}
-#endif
-
-/**
- * is_lq_table_valid() - Test one aspect of LQ cmd for validity
- *
- * It sometimes happens when a HT rate has been in use and we
- * loose connectivity with AP then mac80211 will first tell us that the
- * current channel is not HT anymore before removing the station. In such a
- * scenario the RXON flags will be updated to indicate we are not
- * communicating HT anymore, but the LQ command may still contain HT rates.
- * Test for this to prevent driver from sending LQ command between the time
- * RXON flags are updated and when LQ command is updated.
- */
-static bool is_lq_table_valid(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                             struct iwl_link_quality_cmd *lq)
-{
-       int i;
-
-       if (ctx->ht.enabled)
-               return true;
-
-       IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
-                      ctx->active.channel);
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               if (le32_to_cpu(lq->rs_table[i].rate_n_flags) &
-                   RATE_MCS_HT_MSK) {
-                       IWL_DEBUG_INFO(priv,
-                                      "index %d of LQ expects HT channel\n",
-                                      i);
-                       return false;
-               }
-       }
-       return true;
-}
-
-/**
- * iwl_send_lq_cmd() - Send link quality command
- * @init: This command is sent as part of station initialization right
- *        after station has been added.
- *
- * The link quality command is sent as the last step of station creation.
- * This is the special case in which init is set and we call a callback in
- * this case to clear the state indicating that station creation is in
- * progress.
- */
-int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                   struct iwl_link_quality_cmd *lq, u8 flags, bool init)
-{
-       int ret = 0;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_TX_LINK_QUALITY_CMD,
-               .len = { sizeof(struct iwl_link_quality_cmd), },
-               .flags = flags,
-               .data = { lq, },
-       };
-
-       if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
-               return -EINVAL;
-
-
-       spin_lock_bh(&priv->sta_lock);
-       if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-               spin_unlock_bh(&priv->sta_lock);
-               return -EINVAL;
-       }
-       spin_unlock_bh(&priv->sta_lock);
-
-       iwl_dump_lq_cmd(priv, lq);
-       if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
-               return -EINVAL;
-
-       if (is_lq_table_valid(priv, ctx, lq))
-               ret = iwl_dvm_send_cmd(priv, &cmd);
-       else
-               ret = -EINVAL;
-
-       if (cmd.flags & CMD_ASYNC)
-               return ret;
-
-       if (init) {
-               IWL_DEBUG_INFO(priv, "init LQ command complete, "
-                              "clearing sta addition status for sta %d\n",
-                              lq->sta_id);
-               spin_lock_bh(&priv->sta_lock);
-               priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
-               spin_unlock_bh(&priv->sta_lock);
-       }
-       return ret;
-}
-
-
-static struct iwl_link_quality_cmd *
-iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                u8 sta_id)
-{
-       struct iwl_link_quality_cmd *link_cmd;
-
-       link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
-       if (!link_cmd) {
-               IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
-               return NULL;
-       }
-
-       iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd);
-
-       return link_cmd;
-}
-
-/*
- * iwlagn_add_bssid_station - Add the special IBSS BSSID station
- *
- * Function sleeps.
- */
-int iwlagn_add_bssid_station(struct iwl_priv *priv,
-                            struct iwl_rxon_context *ctx,
-                            const u8 *addr, u8 *sta_id_r)
-{
-       int ret;
-       u8 sta_id;
-       struct iwl_link_quality_cmd *link_cmd;
-
-       if (sta_id_r)
-               *sta_id_r = IWL_INVALID_STATION;
-
-       ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
-       if (ret) {
-               IWL_ERR(priv, "Unable to add station %pM\n", addr);
-               return ret;
-       }
-
-       if (sta_id_r)
-               *sta_id_r = sta_id;
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].used |= IWL_STA_LOCAL;
-       spin_unlock_bh(&priv->sta_lock);
-
-       /* Set up default rate scaling table in device's station table */
-       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-       if (!link_cmd) {
-               IWL_ERR(priv,
-                       "Unable to initialize rate scaling for station %pM.\n",
-                       addr);
-               return -ENOMEM;
-       }
-
-       ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
-       if (ret)
-               IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_bh(&priv->sta_lock);
-
-       return 0;
-}
-
-/*
- * static WEP keys
- *
- * For each context, the device has a table of 4 static WEP keys
- * (one for each key index) that is updated with the following
- * commands.
- */
-
-static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
-                                     struct iwl_rxon_context *ctx,
-                                     bool send_if_empty)
-{
-       int i, not_empty = 0;
-       u8 buff[sizeof(struct iwl_wep_cmd) +
-               sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
-       struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
-       size_t cmd_size  = sizeof(struct iwl_wep_cmd);
-       struct iwl_host_cmd cmd = {
-               .id = ctx->wep_key_cmd,
-               .data = { wep_cmd, },
-               .flags = CMD_SYNC,
-       };
-
-       might_sleep();
-
-       memset(wep_cmd, 0, cmd_size +
-                       (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
-
-       for (i = 0; i < WEP_KEYS_MAX ; i++) {
-               wep_cmd->key[i].key_index = i;
-               if (ctx->wep_keys[i].key_size) {
-                       wep_cmd->key[i].key_offset = i;
-                       not_empty = 1;
-               } else {
-                       wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
-               }
-
-               wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
-               memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
-                               ctx->wep_keys[i].key_size);
-       }
-
-       wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
-       wep_cmd->num_keys = WEP_KEYS_MAX;
-
-       cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
-
-       cmd.len[0] = cmd_size;
-
-       if (not_empty || send_if_empty)
-               return iwl_dvm_send_cmd(priv, &cmd);
-       else
-               return 0;
-}
-
-int iwl_restore_default_wep_keys(struct iwl_priv *priv,
-                                struct iwl_rxon_context *ctx)
-{
-       lockdep_assert_held(&priv->mutex);
-
-       return iwl_send_static_wepkey_cmd(priv, ctx, false);
-}
-
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx,
-                              struct ieee80211_key_conf *keyconf)
-{
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
-                     keyconf->keyidx);
-
-       memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_WEP(priv,
-                       "Not sending REPLY_WEPKEY command due to RFKILL.\n");
-               /* but keys in device are clear anyway so return success */
-               return 0;
-       }
-       ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
-       IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
-                     keyconf->keyidx, ret);
-
-       return ret;
-}
-
-int iwl_set_default_wep_key(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           struct ieee80211_key_conf *keyconf)
-{
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (keyconf->keylen != WEP_KEY_LEN_128 &&
-           keyconf->keylen != WEP_KEY_LEN_64) {
-               IWL_DEBUG_WEP(priv,
-                             "Bad WEP key length %d\n", keyconf->keylen);
-               return -EINVAL;
-       }
-
-       keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT;
-
-       ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
-       memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
-                                                       keyconf->keylen);
-
-       ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
-       IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
-               keyconf->keylen, keyconf->keyidx, ret);
-
-       return ret;
-}
-
-/*
- * dynamic (per-station) keys
- *
- * The dynamic keys are a little more complicated. The device has
- * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys.
- * These are linked to stations by a table that contains an index
- * into the key table for each station/key index/{mcast,unicast},
- * i.e. it's basically an array of pointers like this:
- *     key_offset_t key_mapping[NUM_STATIONS][4][2];
- * (it really works differently, but you can think of it as such)
- *
- * The key uploading and linking happens in the same command, the
- * add station command with STA_MODIFY_KEY_MASK.
- */
-
-static u8 iwlagn_key_sta_id(struct iwl_priv *priv,
-                           struct ieee80211_vif *vif,
-                           struct ieee80211_sta *sta)
-{
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-       if (sta)
-               return iwl_sta_id(sta);
-
-       /*
-        * The device expects GTKs for station interfaces to be
-        * installed as GTKs for the AP station. If we have no
-        * station ID, then use the ap_sta_id in that case.
-        */
-       if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx)
-               return vif_priv->ctx->ap_sta_id;
-
-       return IWL_INVALID_STATION;
-}
-
-static int iwlagn_send_sta_key(struct iwl_priv *priv,
-                              struct ieee80211_key_conf *keyconf,
-                              u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k,
-                              u32 cmd_flags)
-{
-       __le16 key_flags;
-       struct iwl_addsta_cmd sta_cmd;
-       int i;
-
-       spin_lock_bh(&priv->sta_lock);
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-       spin_unlock_bh(&priv->sta_lock);
-
-       key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-       key_flags |= STA_KEY_FLG_MAP_KEY_MSK;
-
-       switch (keyconf->cipher) {
-       case WLAN_CIPHER_SUITE_CCMP:
-               key_flags |= STA_KEY_FLG_CCMP;
-               memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
-               break;
-       case WLAN_CIPHER_SUITE_TKIP:
-               key_flags |= STA_KEY_FLG_TKIP;
-               sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
-               for (i = 0; i < 5; i++)
-                       sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
-               memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen);
-               break;
-       case WLAN_CIPHER_SUITE_WEP104:
-               key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
-               /* fall through */
-       case WLAN_CIPHER_SUITE_WEP40:
-               key_flags |= STA_KEY_FLG_WEP;
-               memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen);
-               break;
-       default:
-               WARN_ON(1);
-               return -EINVAL;
-       }
-
-       if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-               key_flags |= STA_KEY_MULTICAST_MSK;
-
-       /* key pointer (offset) */
-       sta_cmd.key.key_offset = keyconf->hw_key_idx;
-
-       sta_cmd.key.key_flags = key_flags;
-       sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
-       sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
-
-       return iwl_send_add_sta(priv, &sta_cmd, cmd_flags);
-}
-
-void iwl_update_tkip_key(struct iwl_priv *priv,
-                        struct ieee80211_vif *vif,
-                        struct ieee80211_key_conf *keyconf,
-                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
-{
-       u8 sta_id = iwlagn_key_sta_id(priv, vif, sta);
-
-       if (sta_id == IWL_INVALID_STATION)
-               return;
-
-       if (iwl_scan_cancel(priv)) {
-               /* cancel scan failed, just live w/ bad key and rely
-                  briefly on SW decryption */
-               return;
-       }
-
-       iwlagn_send_sta_key(priv, keyconf, sta_id,
-                           iv32, phase1key, CMD_ASYNC);
-}
-
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
-                          struct iwl_rxon_context *ctx,
-                          struct ieee80211_key_conf *keyconf,
-                          struct ieee80211_sta *sta)
-{
-       struct iwl_addsta_cmd sta_cmd;
-       u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
-       __le16 key_flags;
-
-       /* if station isn't there, neither is the key */
-       if (sta_id == IWL_INVALID_STATION)
-               return -ENOENT;
-
-       spin_lock_bh(&priv->sta_lock);
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
-       if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE))
-               sta_id = IWL_INVALID_STATION;
-       spin_unlock_bh(&priv->sta_lock);
-
-       if (sta_id == IWL_INVALID_STATION)
-               return 0;
-
-       lockdep_assert_held(&priv->mutex);
-
-       ctx->key_mapping_keys--;
-
-       IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
-                     keyconf->keyidx, sta_id);
-
-       if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table))
-               IWL_ERR(priv, "offset %d not used in uCode key table.\n",
-                       keyconf->hw_key_idx);
-
-       key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-       key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC |
-                    STA_KEY_FLG_INVALID;
-
-       if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-               key_flags |= STA_KEY_MULTICAST_MSK;
-
-       sta_cmd.key.key_flags = key_flags;
-       sta_cmd.key.key_offset = keyconf->hw_key_idx;
-       sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK;
-       sta_cmd.mode = STA_CONTROL_MODIFY_MSK;
-
-       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_set_dynamic_key(struct iwl_priv *priv,
-                       struct iwl_rxon_context *ctx,
-                       struct ieee80211_key_conf *keyconf,
-                       struct ieee80211_sta *sta)
-{
-       struct ieee80211_key_seq seq;
-       u16 p1k[5];
-       int ret;
-       u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta);
-       const u8 *addr;
-
-       if (sta_id == IWL_INVALID_STATION)
-               return -EINVAL;
-
-       lockdep_assert_held(&priv->mutex);
-
-       keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv);
-       if (keyconf->hw_key_idx == WEP_INVALID_OFFSET)
-               return -ENOSPC;
-
-       ctx->key_mapping_keys++;
-
-       switch (keyconf->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               if (sta)
-                       addr = sta->addr;
-               else /* station mode case only */
-                       addr = ctx->active.bssid_addr;
-
-               /* pre-fill phase 1 key into device cache */
-               ieee80211_get_key_rx_seq(keyconf, 0, &seq);
-               ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
-               ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
-                                         seq.tkip.iv32, p1k, CMD_SYNC);
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-       case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
-                                         0, NULL, CMD_SYNC);
-               break;
-       default:
-               IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher);
-               ret = -EINVAL;
-       }
-
-       if (ret) {
-               ctx->key_mapping_keys--;
-               clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table);
-       }
-
-       IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
-                     keyconf->cipher, keyconf->keylen, keyconf->keyidx,
-                     sta ? sta->addr : NULL, ret);
-
-       return ret;
-}
-
-/**
- * iwlagn_alloc_bcast_station - add broadcast station into driver's station table.
- *
- * This adds the broadcast station into the driver's station table
- * and marks it driver active, so that it will be restored to the
- * device at the next best time.
- */
-int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       struct iwl_link_quality_cmd *link_cmd;
-       u8 sta_id;
-
-       spin_lock_bh(&priv->sta_lock);
-       sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Unable to prepare broadcast station\n");
-               spin_unlock_bh(&priv->sta_lock);
-
-               return -EINVAL;
-       }
-
-       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
-       priv->stations[sta_id].used |= IWL_STA_BCAST;
-       spin_unlock_bh(&priv->sta_lock);
-
-       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-       if (!link_cmd) {
-               IWL_ERR(priv,
-                       "Unable to initialize rate scaling for bcast station.\n");
-               return -ENOMEM;
-       }
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_bh(&priv->sta_lock);
-
-       return 0;
-}
-
-/**
- * iwl_update_bcast_station - update broadcast station's LQ command
- *
- * Only used by iwlagn. Placed here to have all bcast station management
- * code together.
- */
-int iwl_update_bcast_station(struct iwl_priv *priv,
-                            struct iwl_rxon_context *ctx)
-{
-       struct iwl_link_quality_cmd *link_cmd;
-       u8 sta_id = ctx->bcast_sta_id;
-
-       link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id);
-       if (!link_cmd) {
-               IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");
-               return -ENOMEM;
-       }
-
-       spin_lock_bh(&priv->sta_lock);
-       if (priv->stations[sta_id].lq)
-               kfree(priv->stations[sta_id].lq);
-       else
-               IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");
-       priv->stations[sta_id].lq = link_cmd;
-       spin_unlock_bh(&priv->sta_lock);
-
-       return 0;
-}
-
-int iwl_update_bcast_stations(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       int ret = 0;
-
-       for_each_context(priv, ctx) {
-               ret = iwl_update_bcast_station(priv, ctx);
-               if (ret)
-                       break;
-       }
-
-       return ret;
-}
-
-/**
- * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
- */
-int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
-{
-       struct iwl_addsta_cmd sta_cmd;
-
-       lockdep_assert_held(&priv->mutex);
-
-       /* Remove "disable" flag, to enable Tx for this TID */
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
-       priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_bh(&priv->sta_lock);
-
-       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
-                        int tid, u16 ssn)
-{
-       int sta_id;
-       struct iwl_addsta_cmd sta_cmd;
-
-       lockdep_assert_held(&priv->mutex);
-
-       sta_id = iwl_sta_id(sta);
-       if (sta_id == IWL_INVALID_STATION)
-               return -ENXIO;
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].sta.station_flags_msk = 0;
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
-       priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
-       priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_bh(&priv->sta_lock);
-
-       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
-                       int tid)
-{
-       int sta_id;
-       struct iwl_addsta_cmd sta_cmd;
-
-       lockdep_assert_held(&priv->mutex);
-
-       sta_id = iwl_sta_id(sta);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-               return -ENXIO;
-       }
-
-       spin_lock_bh(&priv->sta_lock);
-       priv->stations[sta_id].sta.station_flags_msk = 0;
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
-       priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
-       spin_unlock_bh(&priv->sta_lock);
-
-       return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
-}
-
-
-
-void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
-{
-       struct iwl_addsta_cmd cmd = {
-               .mode = STA_CONTROL_MODIFY_MSK,
-               .station_flags = STA_FLG_PWR_SAVE_MSK,
-               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
-               .sta.sta_id = sta_id,
-               .sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK,
-               .sleep_tx_count = cpu_to_le16(cnt),
-       };
-
-       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
deleted file mode 100644 (file)
index a5cfe0a..0000000
+++ /dev/null
@@ -1,696 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-agn.h"
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-commands.h"
-#include "iwl-debug.h"
-#include "iwl-agn-tt.h"
-#include "iwl-modparams.h"
-
-/* default Thermal Throttling transaction table
- * Current state   |         Throttling Down               |  Throttling Up
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     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 - 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 - 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, 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},
-       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
-       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
-};
-
-/* Advance Thermal Throttling default restriction table */
-static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
-       {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
-       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
-       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
-       {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
-};
-
-bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (tt->state >= IWL_TI_1)
-               return true;
-       return false;
-}
-
-u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       return tt->tt_power_mode;
-}
-
-bool iwl_ht_enabled(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return true;
-       restriction = tt->restriction + tt->state;
-       return restriction->is_ht;
-}
-
-static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
-{
-       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-       bool within_margin = false;
-
-       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;
-}
-
-bool iwl_check_for_ct_kill(struct iwl_priv *priv)
-{
-       bool is_ct_kill = false;
-
-       if (iwl_within_ct_kill_margin(priv)) {
-               iwl_tt_enter_ct_kill(priv);
-               is_ct_kill = true;
-       }
-       return is_ct_kill;
-}
-
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return IWL_ANT_OK_MULTI;
-       restriction = tt->restriction + tt->state;
-       return restriction->tx_stream;
-}
-
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return IWL_ANT_OK_MULTI;
-       restriction = tt->restriction + tt->state;
-       return restriction->rx_stream;
-}
-
-#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
- * if the temperature is below CT, uCode will stay awake and send card
- * state notification with CT_KILL bit clear to inform Thermal Throttling
- * Management to change state. Otherwise, uCode will go back to sleep
- * without doing anything, driver should continue the 5 seconds timer
- * to wake up uCode for temperature check until temperature drop below CT
- */
-static void iwl_tt_check_exit_ct_kill(unsigned long data)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       unsigned long flags;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (tt->state == IWL_TI_CT_KILL) {
-               if (priv->thermal_throttle.ct_kill_toggle) {
-                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-                       priv->thermal_throttle.ct_kill_toggle = false;
-               } else {
-                       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
-                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-                       priv->thermal_throttle.ct_kill_toggle = true;
-               }
-               iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
-               spin_lock_irqsave(&priv->trans->reg_lock, flags);
-               if (likely(iwl_grab_nic_access(priv->trans)))
-                       iwl_release_nic_access(priv->trans);
-               spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
-
-               /* Reschedule the ct_kill timer to occur in
-                * CT_KILL_EXIT_DURATION seconds to ensure we get a
-                * thermal update */
-               IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
-               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
-                         jiffies + CT_KILL_EXIT_DURATION * HZ);
-       }
-}
-
-static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
-                          bool stop)
-{
-       if (stop) {
-               IWL_DEBUG_TEMP(priv, "Stop all queues\n");
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-               IWL_DEBUG_TEMP(priv,
-                               "Schedule 5 seconds CT_KILL Timer\n");
-               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
-                         jiffies + CT_KILL_EXIT_DURATION * HZ);
-       } else {
-               IWL_DEBUG_TEMP(priv, "Wake all queues\n");
-               if (priv->mac80211_registered)
-                       ieee80211_wake_queues(priv->hw);
-       }
-}
-
-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_TEMP(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_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
-       /* make request to retrieve statistics information */
-       iwl_send_statistics_request(priv, CMD_SYNC, false);
-       /* 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)
-
-/*
- * Legacy thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *     Chip will identify dangerously high temperatures that can
- *     harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *     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, bool force)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       enum iwl_tt_state old_state;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if ((tt->tt_previous_temp) &&
-           (temp > tt->tt_previous_temp) &&
-           ((temp - tt->tt_previous_temp) >
-           IWL_TT_INCREASE_MARGIN)) {
-               IWL_DEBUG_TEMP(priv,
-                       "Temperature increase %d degree Celsius\n",
-                       (temp - tt->tt_previous_temp));
-       }
-#endif
-       old_state = tt->state;
-       /* in Celsius */
-       if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
-               tt->state = IWL_TI_CT_KILL;
-       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
-               tt->state = IWL_TI_2;
-       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
-               tt->state = IWL_TI_1;
-       else
-               tt->state = IWL_TI_0;
-
-#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:
-                       /*
-                        * When the system is ready to go back to IWL_TI_0
-                        * we only have to call iwl_power_update_mode() to
-                        * do so.
-                        */
-                       break;
-               case IWL_TI_1:
-                       tt->tt_power_mode = IWL_POWER_INDEX_3;
-                       break;
-               case IWL_TI_2:
-                       tt->tt_power_mode = IWL_POWER_INDEX_4;
-                       break;
-               default:
-                       tt->tt_power_mode = IWL_POWER_INDEX_5;
-                       break;
-               }
-               mutex_lock(&priv->mutex);
-               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) {
-                               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_TEMP(priv, "Temperature state changed %u\n",
-                                       tt->state);
-                       IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
-                                       tt->tt_power_mode);
-               }
-               mutex_unlock(&priv->mutex);
-       }
-}
-
-/*
- * Advance thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *     Chip will identify dangerously high temperatures that can
- *     harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *     Throttle early enough to lower the power consumption before
- *     drastic steps are needed
- *     Actions include relaxing the power down sleep thresholds and
- *     decreasing the number of TX streams
- * 3) Avoid throughput performance impact as much as possible
- *
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     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, bool force)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       int i;
-       bool changed = false;
-       enum iwl_tt_state old_state;
-       struct iwl_tt_trans *transaction;
-
-       old_state = tt->state;
-       for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
-               /* based on the current TT state,
-                * find the curresponding transaction table
-                * each table has (IWL_TI_STATE_MAX - 1) entries
-                * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
-                * will advance to the correct table.
-                * then based on the current temperature
-                * find the next state need to transaction to
-                * go through all the possible (IWL_TI_STATE_MAX - 1) entries
-                * in the current table to see if transaction is needed
-                */
-               transaction = tt->transaction +
-                       ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
-               if (temp >= transaction->tt_low &&
-                   temp <= transaction->tt_high) {
-#ifdef CONFIG_IWLWIFI_DEBUG
-                       if ((tt->tt_previous_temp) &&
-                           (temp > tt->tt_previous_temp) &&
-                           ((temp - tt->tt_previous_temp) >
-                           IWL_TT_INCREASE_MARGIN)) {
-                               IWL_DEBUG_TEMP(priv,
-                                       "Temperature increase %d "
-                                       "degree Celsius\n",
-                                       (temp - tt->tt_previous_temp));
-                       }
-                       tt->tt_previous_temp = temp;
-#endif
-                       if (old_state !=
-                           transaction->next_state) {
-                               changed = true;
-                               tt->state =
-                                       transaction->next_state;
-                       }
-                       break;
-               }
-       }
-       /* stop ct_kill_waiting_tm timer */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-       if (changed) {
-               if (tt->state >= IWL_TI_1) {
-                       /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
-                       tt->tt_power_mode = IWL_POWER_INDEX_5;
-
-                       if (!iwl_ht_enabled(priv)) {
-                               struct iwl_rxon_context *ctx;
-
-                               for_each_context(priv, ctx) {
-                                       struct iwl_rxon_cmd *rxon;
-
-                                       rxon = &ctx->staging;
-
-                                       /* disable HT */
-                                       rxon->flags &= ~(
-                                               RXON_FLG_CHANNEL_MODE_MSK |
-                                               RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-                                               RXON_FLG_HT40_PROT_MSK |
-                                               RXON_FLG_HT_PROT_MSK);
-                               }
-                       } else {
-                               /* check HT capability and set
-                                * according to the system HT capability
-                                * in case get disabled before */
-                               iwl_set_rxon_ht(priv, &priv->current_ht_config);
-                       }
-
-               } else {
-                       /*
-                        * restore system power setting -- it will be
-                        * recalculated automatically.
-                        */
-
-                       /* check HT capability and set
-                        * according to the system HT capability
-                        * in case get disabled before */
-                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
-               }
-               mutex_lock(&priv->mutex);
-               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_TEMP(priv,
-                                       "Thermal Throttling to new state: %u\n",
-                                       tt->state);
-                       if (old_state != IWL_TI_CT_KILL &&
-                           tt->state == IWL_TI_CT_KILL) {
-                               if (force) {
-                                       IWL_DEBUG_TEMP(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_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
-                               iwl_perform_ct_kill_task(priv, false);
-                       }
-               }
-               mutex_unlock(&priv->mutex);
-       }
-}
-
-/* Card State Notification indicated reach critical temperature
- * if PSP not enable, no Thermal Throttling function will be performed
- * just set the GP1 bit to acknowledge the event
- * otherwise, go into IWL_TI_CT_KILL state
- * since Card State Notification will not provide any temperature reading
- * for Legacy mode
- * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
- * for advance mode
- * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
- */
-static void iwl_bg_ct_enter(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (!iwl_is_ready(priv))
-               return;
-
-       if (tt->state != IWL_TI_CT_KILL) {
-               IWL_ERR(priv, "Device reached critical temperature "
-                             "- ucode going to sleep!\n");
-               if (!priv->thermal_throttle.advanced_tt)
-                       iwl_legacy_tt_handler(priv,
-                                             IWL_MINIMAL_POWER_THRESHOLD,
-                                             true);
-               else
-                       iwl_advance_tt_handler(priv,
-                                              CT_KILL_THRESHOLD + 1, true);
-       }
-}
-
-/* Card State Notification indicated out of critical temperature
- * since Card State Notification will not provide any temperature reading
- * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
- * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
- */
-static void iwl_bg_ct_exit(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (!iwl_is_ready(priv))
-               return;
-
-       /* stop ct_kill_exit_tm timer */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-
-       if (tt->state == IWL_TI_CT_KILL) {
-               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,
-                                     true);
-               else
-                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
-                                              true);
-       }
-}
-
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
-       queue_work(priv->workqueue, &priv->ct_enter);
-}
-
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
-       queue_work(priv->workqueue, &priv->ct_exit);
-}
-
-static void iwl_bg_tt_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
-       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               iwl_legacy_tt_handler(priv, temp, false);
-       else
-               iwl_advance_tt_handler(priv, temp, false);
-}
-
-void iwl_tt_handler(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
-       queue_work(priv->workqueue, &priv->tt_work);
-}
-
-/* Thermal throttling initialization
- * For advance thermal throttling:
- *     Initialize Thermal Index and temperature threshold table
- *     Initialize thermal throttling restriction table
- */
-void iwl_tt_initialize(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
-       struct iwl_tt_trans *transaction;
-
-       IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
-
-       memset(tt, 0, sizeof(struct iwl_tt_mgmt));
-
-       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;
-       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);
-
-       if (priv->cfg->base_params->adv_thermal_throttle) {
-               IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
-               tt->restriction = kcalloc(IWL_TI_STATE_MAX,
-                                         sizeof(struct iwl_tt_restriction),
-                                         GFP_KERNEL);
-               tt->transaction = kcalloc(IWL_TI_STATE_MAX *
-                                         (IWL_TI_STATE_MAX - 1),
-                                         sizeof(struct iwl_tt_trans),
-                                         GFP_KERNEL);
-               if (!tt->restriction || !tt->transaction) {
-                       IWL_ERR(priv, "Fallback to Legacy Throttling\n");
-                       priv->thermal_throttle.advanced_tt = false;
-                       kfree(tt->restriction);
-                       tt->restriction = NULL;
-                       kfree(tt->transaction);
-                       tt->transaction = NULL;
-               } else {
-                       transaction = tt->transaction +
-                               (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_0[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_1[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_2[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_3[0], size);
-                       size = sizeof(struct iwl_tt_restriction) *
-                               IWL_TI_STATE_MAX;
-                       memcpy(tt->restriction,
-                               &restriction_range[0], size);
-                       priv->thermal_throttle.advanced_tt = true;
-               }
-       } else {
-               IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
-               priv->thermal_throttle.advanced_tt = false;
-       }
-}
-
-/* cleanup thermal throttling management related memory and timer */
-void iwl_tt_exit(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       /* 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);
-
-       if (priv->thermal_throttle.advanced_tt) {
-               /* free advance thermal throttling memory */
-               kfree(tt->restriction);
-               tt->restriction = NULL;
-               kfree(tt->transaction);
-               tt->transaction = NULL;
-       }
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
deleted file mode 100644 (file)
index 86bbf47..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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_tt_setting_h__
-#define __iwl_tt_setting_h__
-
-#include "iwl-commands.h"
-
-#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,
-       IWL_ANT_OK_SINGLE,
-       IWL_ANT_OK_MULTI,
-};
-
-/* Thermal Throttling State Machine states */
-enum  iwl_tt_state {
-       IWL_TI_0,       /* normal temperature, system power state */
-       IWL_TI_1,       /* high temperature detect, low power state */
-       IWL_TI_2,       /* higher temperature detected, lower power state */
-       IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
-       IWL_TI_STATE_MAX
-};
-
-/**
- * struct iwl_tt_restriction - Thermal Throttling restriction table
- * @tx_stream: number of tx stream allowed
- * @is_ht: ht enable/disable
- * @rx_stream: number of rx stream allowed
- *
- * This table is used by advance thermal throttling management
- * based on the current thermal throttling state, and determines
- * the number of tx/rx streams and the status of HT operation.
- */
-struct iwl_tt_restriction {
-       enum iwl_antenna_ok tx_stream;
-       enum iwl_antenna_ok rx_stream;
-       bool is_ht;
-};
-
-/**
- * struct iwl_tt_trans - Thermal Throttling transaction table
- * @next_state:  next thermal throttling mode
- * @tt_low: low temperature threshold to change state
- * @tt_high: high temperature threshold to change state
- *
- * This is used by the advanced thermal throttling algorithm
- * to determine the next thermal state to go based on the
- * current temperature.
- */
-struct iwl_tt_trans {
-       enum iwl_tt_state next_state;
-       u32 tt_low;
-       u32 tt_high;
-};
-
-/**
- * struct iwl_tt_mgnt - Thermal Throttling Management structure
- * @advanced_tt:    advanced thermal throttle required
- * @state:          current Thermal Throttling state
- * @tt_power_mode:  Thermal Throttling power mode index
- *                 being used to set power level when
- *                 when thermal throttling state != IWL_TI_0
- *                 the tt_power_mode should set to different
- *                 power mode based on the current tt state
- * @tt_previous_temperature: last measured temperature
- * @iwl_tt_restriction: ptr to restriction tbl, used by advance
- *                 thermal throttling to determine how many tx/rx streams
- *                 should be used in tt state; and can HT be enabled or not
- * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
- *                 state transaction
- * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
- * @ct_kill_exit_tm: timer to exit thermal kill
- */
-struct iwl_tt_mgmt {
-       enum iwl_tt_state state;
-       bool advanced_tt;
-       u8 tt_power_mode;
-       bool ct_kill_toggle;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       s32 tt_previous_temp;
-#endif
-       struct iwl_tt_restriction *restriction;
-       struct iwl_tt_trans *transaction;
-       struct timer_list ct_kill_exit_tm;
-       struct timer_list ct_kill_waiting_tm;
-};
-
-u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
-bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
-bool iwl_ht_enabled(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);
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_tt_initialize(struct iwl_priv *priv);
-void iwl_tt_exit(struct iwl_priv *priv);
-
-#endif  /* __iwl_tt_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
deleted file mode 100644 (file)
index 3366e2e..0000000
+++ /dev/null
@@ -1,1368 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * 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/sched.h>
-#include <linux/ieee80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-static const u8 tid_to_ac[] = {
-       IEEE80211_AC_BE,
-       IEEE80211_AC_BK,
-       IEEE80211_AC_BK,
-       IEEE80211_AC_BE,
-       IEEE80211_AC_VI,
-       IEEE80211_AC_VI,
-       IEEE80211_AC_VO,
-       IEEE80211_AC_VO,
-};
-
-static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
-                                    struct ieee80211_tx_info *info,
-                                    __le16 fc, __le32 *tx_flags)
-{
-       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
-           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
-           info->flags & IEEE80211_TX_CTL_AMPDU)
-               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-}
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
-                                     struct sk_buff *skb,
-                                     struct iwl_tx_cmd *tx_cmd,
-                                     struct ieee80211_tx_info *info,
-                                     struct ieee80211_hdr *hdr, u8 sta_id)
-{
-       __le16 fc = hdr->frame_control;
-       __le32 tx_flags = tx_cmd->tx_flags;
-
-       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;
-       else
-               tx_flags &= ~TX_CMD_FLG_ACK_MSK;
-
-       if (ieee80211_is_probe_resp(fc))
-               tx_flags |= TX_CMD_FLG_TSF_MSK;
-       else if (ieee80211_is_back_req(fc))
-               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
-       else if (info->band == IEEE80211_BAND_2GHZ &&
-                priv->cfg->bt_params &&
-                priv->cfg->bt_params->advanced_bt_coexist &&
-                (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
-                ieee80211_is_reassoc_req(fc) ||
-                skb->protocol == cpu_to_be16(ETH_P_PAE)))
-               tx_flags |= TX_CMD_FLG_IGNORE_BT;
-
-
-       tx_cmd->sta_id = sta_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_cmd->tid_tspec = qc[0] & 0xf;
-               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       } else {
-               tx_cmd->tid_tspec = IWL_TID_NON_QOS;
-               if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
-                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-               else
-                       tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
-
-       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_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
-               else
-                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
-       } else {
-               tx_cmd->timeout.pm_frame_timeout = 0;
-       }
-
-       tx_cmd->driver_txop = 0;
-       tx_cmd->tx_flags = tx_flags;
-       tx_cmd->next_frame_len = 0;
-}
-
-static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
-                                    struct iwl_tx_cmd *tx_cmd,
-                                    struct ieee80211_tx_info *info,
-                                    __le16 fc)
-{
-       u32 rate_flags;
-       int rate_idx;
-       u8 rts_retry_limit;
-       u8 data_retry_limit;
-       u8 rate_plcp;
-
-       if (priv->wowlan) {
-               rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
-               data_retry_limit = IWLAGN_LOW_RETRY_LIMIT;
-       } else {
-               /* Set retry limit on RTS packets */
-               rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT;
-
-               /* Set retry limit on DATA packets and Probe Responses*/
-               if (ieee80211_is_probe_resp(fc)) {
-                       data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT;
-                       rts_retry_limit =
-                               min(data_retry_limit, rts_retry_limit);
-               } else if (ieee80211_is_back_req(fc))
-                       data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT;
-               else
-                       data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
-       }
-
-       tx_cmd->data_retry_limit = data_retry_limit;
-       tx_cmd->rts_retry_limit = rts_retry_limit;
-
-       /* DATA packets will use the uCode station table for rate/antenna
-        * selection */
-       if (ieee80211_is_data(fc)) {
-               tx_cmd->initial_rate_index = 0;
-               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-               if (priv->tm_fixed_rate) {
-                       /*
-                        * rate overwrite by testmode
-                        * we not only send lq command to change rate
-                        * we also re-enforce per data pkt base.
-                        */
-                       tx_cmd->tx_flags &= ~TX_CMD_FLG_STA_RATE_MSK;
-                       memcpy(&tx_cmd->rate_n_flags, &priv->tm_fixed_rate,
-                              sizeof(tx_cmd->rate_n_flags));
-               }
-#endif
-               return;
-       } else if (ieee80211_is_back_req(fc))
-               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-
-       /**
-        * If the current TX rate stored in mac80211 has the MCS bit set, it's
-        * not really a TX rate.  Thus, we use the lowest supported rate for
-        * this band.  Also use the lowest supported rate if the stored rate
-        * index is invalid.
-        */
-       rate_idx = info->control.rates[0].idx;
-       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
-                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
-               rate_idx = rate_lowest_index(&priv->bands[info->band],
-                               info->control.sta);
-       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate_idx += IWL_FIRST_OFDM_RATE;
-       /* Get PLCP rate for tx_cmd->rate_n_flags */
-       rate_plcp = iwl_rates[rate_idx].plcp;
-       /* Zero out flags for this packet */
-       rate_flags = 0;
-
-       /* Set CCK flag as needed */
-       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-       /* Set up antennas */
-        if (priv->cfg->bt_params &&
-            priv->cfg->bt_params->advanced_bt_coexist &&
-            priv->bt_full_concurrent) {
-               /* operated as 1x1 in full concurrency mode */
-               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
-                               first_antenna(priv->hw_params.valid_tx_ant));
-       } else
-               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
-                                               priv->hw_params.valid_tx_ant);
-       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
-
-       /* Set the rate in the TX cmd */
-       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
-                                        struct ieee80211_tx_info *info,
-                                        struct iwl_tx_cmd *tx_cmd,
-                                        struct sk_buff *skb_frag)
-{
-       struct ieee80211_key_conf *keyconf = info->control.hw_key;
-
-       switch (keyconf->cipher) {
-       case WLAN_CIPHER_SUITE_CCMP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
-               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
-               break;
-
-       case WLAN_CIPHER_SUITE_TKIP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
-               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
-               break;
-
-       case WLAN_CIPHER_SUITE_WEP104:
-               tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-               /* fall through */
-       case WLAN_CIPHER_SUITE_WEP40:
-               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
-                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
-
-               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
-
-               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
-                            "with key %d\n", keyconf->keyidx);
-               break;
-
-       default:
-               IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
-               break;
-       }
-}
-
-/**
- * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
- * @context: the current context
- * @sta: mac80211 station
- *
- * In certain circumstances mac80211 passes a station pointer
- * that may be %NULL, for example during TX or key setup. In
- * that case, we need to use the broadcast station, so this
- * inline wraps that pattern.
- */
-static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
-                                  struct ieee80211_sta *sta)
-{
-       int sta_id;
-
-       if (!sta)
-               return context->bcast_sta_id;
-
-       sta_id = iwl_sta_id(sta);
-
-       /*
-        * mac80211 should not be passing a partially
-        * initialised station!
-        */
-       WARN_ON(sta_id == IWL_INVALID_STATION);
-
-       return sta_id;
-}
-
-/*
- * start REPLY_TX command process
- */
-int iwlagn_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 iwl_station_priv *sta_priv = NULL;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_device_cmd *dev_cmd = NULL;
-       struct iwl_tx_cmd *tx_cmd;
-       __le16 fc;
-       u8 hdr_len;
-       u16 len, seq_number = 0;
-       u8 sta_id, tid = IWL_MAX_TID_COUNT;
-       bool is_agg = false;
-       int txq_id;
-
-       if (info->control.vif)
-               ctx = iwl_rxon_ctx_from_vif(info->control.vif);
-
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
-               goto drop_unlock_priv;
-       }
-
-       fc = hdr->frame_control;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (ieee80211_is_auth(fc))
-               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
-       else if (ieee80211_is_assoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
-       else if (ieee80211_is_reassoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
-#endif
-
-       if (unlikely(ieee80211_is_probe_resp(fc))) {
-               struct iwl_wipan_noa_data *noa_data =
-                       rcu_dereference(priv->noa_data);
-
-               if (noa_data &&
-                   pskb_expand_head(skb, 0, noa_data->length,
-                                    GFP_ATOMIC) == 0) {
-                       memcpy(skb_put(skb, noa_data->length),
-                              noa_data->data, noa_data->length);
-                       hdr = (struct ieee80211_hdr *)skb->data;
-               }
-       }
-
-       hdr_len = ieee80211_hdrlen(fc);
-
-       /* For management frames use broadcast id to do not break aggregation */
-       if (!ieee80211_is_data(fc))
-               sta_id = ctx->bcast_sta_id;
-       else {
-               /* Find index into station table for destination station */
-               sta_id = iwl_sta_id_or_broadcast(ctx, info->control.sta);
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-                                      hdr->addr1);
-                       goto drop_unlock_priv;
-               }
-       }
-
-       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
-       if (info->control.sta)
-               sta_priv = (void *)info->control.sta->drv_priv;
-
-       if (sta_priv && sta_priv->asleep &&
-           (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)) {
-               /*
-                * This sends an asynchronous command to the device,
-                * but we can rely on it being processed before the
-                * next frame is processed -- and the next frame to
-                * this station is the one that will consume this
-                * counter.
-                * For now set the counter to just 1 since we do not
-                * support uAPSD yet.
-                *
-                * FIXME: If we get two non-bufferable frames one
-                * after the other, we might only send out one of
-                * them because this is racy.
-                */
-               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
-       }
-
-       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-               is_agg = true;
-
-       dev_cmd = kmem_cache_alloc(iwl_tx_cmd_pool, GFP_ATOMIC);
-
-       if (unlikely(!dev_cmd))
-               goto drop_unlock_priv;
-
-       memset(dev_cmd, 0, sizeof(*dev_cmd));
-       tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
-
-       /* Total # bytes to be transmitted */
-       len = (u16)skb->len;
-       tx_cmd->len = cpu_to_le16(len);
-
-       if (info->control.hw_key)
-               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb);
-
-       /* TODO need this for burst mode later on */
-       iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
-
-       iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
-
-       memset(&info->status, 0, sizeof(info->status));
-
-       info->driver_data[0] = ctx;
-       info->driver_data[1] = dev_cmd;
-
-       spin_lock(&priv->sta_lock);
-
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-               u8 *qc = NULL;
-               struct iwl_tid_data *tid_data;
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
-                       goto drop_unlock_sta;
-               tid_data = &priv->tid_data[sta_id][tid];
-
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
-                   tid_data->agg.state != IWL_AGG_ON) {
-                       IWL_ERR(priv, "TX_CTL_AMPDU while not in AGG:"
-                               " Tx flags = 0x%08x, agg.state = %d",
-                               info->flags, tid_data->agg.state);
-                       IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
-                               sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
-                       goto drop_unlock_sta;
-               }
-
-               /* We can receive packets from the stack in IWL_AGG_{ON,OFF}
-                * only. Check this here.
-                */
-               if (WARN_ONCE(tid_data->agg.state != IWL_AGG_ON &&
-                   tid_data->agg.state != IWL_AGG_OFF,
-                   "Tx while agg.state = %d", tid_data->agg.state))
-                       goto drop_unlock_sta;
-
-               seq_number = tid_data->seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               seq_number += 0x10;
-       }
-
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
-
-       if (is_agg)
-               txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
-       else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-               /*
-                * Send this frame after DTIM -- there's a special queue
-                * reserved for this for contexts that support AP mode.
-                */
-               txq_id = ctx->mcast_queue;
-
-               /*
-                * The microcode will clear the more data
-                * bit in the last frame it transmits.
-                */
-               hdr->frame_control |=
-                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-               txq_id = IWL_AUX_QUEUE;
-       else
-               txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
-
-       WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue);
-       WARN_ON_ONCE(is_agg &&
-                    priv->queue_to_mac80211[txq_id] != info->hw_queue);
-
-       if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id))
-               goto drop_unlock_sta;
-
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
-           !ieee80211_has_morefrags(fc))
-               priv->tid_data[sta_id][tid].seq_number = seq_number;
-
-       spin_unlock(&priv->sta_lock);
-
-       /*
-        * Avoid atomic ops if it isn't an associated client.
-        * Also, if this is a packet for aggregation, don't
-        * increase the counter because the ucode will stop
-        * aggregation queues when their respective station
-        * goes to sleep.
-        */
-       if (sta_priv && sta_priv->client && !is_agg)
-               atomic_inc(&sta_priv->pending_frames);
-
-       return 0;
-
-drop_unlock_sta:
-       if (dev_cmd)
-               kmem_cache_free(iwl_tx_cmd_pool, dev_cmd);
-       spin_unlock(&priv->sta_lock);
-drop_unlock_priv:
-       return -1;
-}
-
-static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int mq)
-{
-       int q;
-
-       for (q = IWLAGN_FIRST_AMPDU_QUEUE;
-            q < priv->cfg->base_params->num_of_queues; q++) {
-               if (!test_and_set_bit(q, priv->agg_q_alloc)) {
-                       priv->queue_to_mac80211[q] = mq;
-                       return q;
-               }
-       }
-
-       return -ENOSPC;
-}
-
-static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q)
-{
-       clear_bit(q, priv->agg_q_alloc);
-       priv->queue_to_mac80211[q] = IWL_INVALID_MAC80211_QUEUE;
-}
-
-int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid)
-{
-       struct iwl_tid_data *tid_data;
-       int sta_id, txq_id;
-       enum iwl_agg_state agg_state;
-
-       sta_id = iwl_sta_id(sta);
-
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-               return -ENXIO;
-       }
-
-       spin_lock_bh(&priv->sta_lock);
-
-       tid_data = &priv->tid_data[sta_id][tid];
-       txq_id = priv->tid_data[sta_id][tid].agg.txq_id;
-
-       switch (priv->tid_data[sta_id][tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /*
-               * This can happen if the peer stops aggregation
-               * again before we've had a chance to drain the
-               * queue we selected previously, i.e. before the
-               * session was really started completely.
-               */
-               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               goto turn_off;
-       case IWL_AGG_STARTING:
-               /*
-                * This can happen when the session is stopped before
-                * we receive ADDBA response
-                */
-               IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n");
-               goto turn_off;
-       case IWL_AGG_ON:
-               break;
-       default:
-               IWL_WARN(priv, "Stopping AGG while state not ON "
-                        "or starting for %d on %d (%d)\n", sta_id, tid,
-                        priv->tid_data[sta_id][tid].agg.state);
-               spin_unlock_bh(&priv->sta_lock);
-               return 0;
-       }
-
-       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
-
-       /* There are still packets for this RA / TID in the HW */
-       if (!test_bit(txq_id, priv->agg_q_alloc)) {
-               IWL_DEBUG_TX_QUEUES(priv,
-                       "stopping AGG on STA/TID %d/%d but hwq %d not used\n",
-                       sta_id, tid, txq_id);
-       } else if (tid_data->agg.ssn != tid_data->next_reclaimed) {
-               IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-                                   "next_recl = %d\n",
-                                   tid_data->agg.ssn,
-                                   tid_data->next_reclaimed);
-               priv->tid_data[sta_id][tid].agg.state =
-                       IWL_EMPTYING_HW_QUEUE_DELBA;
-               spin_unlock_bh(&priv->sta_lock);
-               return 0;
-       }
-
-       IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
-                           tid_data->agg.ssn);
-turn_off:
-       agg_state = priv->tid_data[sta_id][tid].agg.state;
-       priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
-
-       spin_unlock_bh(&priv->sta_lock);
-
-       if (test_bit(txq_id, priv->agg_q_alloc)) {
-               /*
-                * If the transport didn't know that we wanted to start
-                * agreggation, don't tell it that we want to stop them.
-                * This can happen when we don't get the addBA response on
-                * time, or we hadn't time to drain the AC queues.
-                */
-               if (agg_state == IWL_AGG_ON)
-                       iwl_trans_tx_agg_disable(priv->trans, txq_id);
-               else
-                       IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
-                                           agg_state);
-               iwlagn_dealloc_agg_txq(priv, txq_id);
-       }
-
-       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-
-       return 0;
-}
-
-int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
-{
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       struct iwl_tid_data *tid_data;
-       int sta_id, txq_id, ret;
-
-       IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
-                    sta->addr, tid);
-
-       sta_id = iwl_sta_id(sta);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Start AGG on invalid station\n");
-               return -ENXIO;
-       }
-       if (unlikely(tid >= IWL_MAX_TID_COUNT))
-               return -EINVAL;
-
-       if (priv->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) {
-               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
-               return -ENXIO;
-       }
-
-       txq_id = iwlagn_alloc_agg_txq(priv, ctx->ac_to_queue[tid_to_ac[tid]]);
-       if (txq_id < 0) {
-               IWL_DEBUG_TX_QUEUES(priv,
-                       "No free aggregation queue for %pM/%d\n",
-                       sta->addr, tid);
-               return txq_id;
-       }
-
-       ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-       if (ret)
-               return ret;
-
-       spin_lock_bh(&priv->sta_lock);
-       tid_data = &priv->tid_data[sta_id][tid];
-       tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
-       tid_data->agg.txq_id = txq_id;
-
-       *ssn = tid_data->agg.ssn;
-
-       if (*ssn == tid_data->next_reclaimed) {
-               IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n",
-                                   tid_data->agg.ssn);
-               tid_data->agg.state = IWL_AGG_STARTING;
-               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-       } else {
-               IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, "
-                                   "next_reclaimed = %d\n",
-                                   tid_data->agg.ssn,
-                                   tid_data->next_reclaimed);
-               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
-       }
-       spin_unlock_bh(&priv->sta_lock);
-
-       return ret;
-}
-
-int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid, u8 buf_size)
-{
-       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       int q, fifo;
-       u16 ssn;
-
-       buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
-
-       spin_lock_bh(&priv->sta_lock);
-       ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn;
-       q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id;
-       priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON;
-       spin_unlock_bh(&priv->sta_lock);
-
-       fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
-
-       iwl_trans_tx_agg_setup(priv->trans, q, fifo,
-                              sta_priv->sta_id, tid,
-                              buf_size, ssn);
-
-       /*
-        * If the limit is 0, then it wasn't initialised yet,
-        * use the default. We can do that since we take the
-        * minimum below, and we don't want to go above our
-        * default due to hardware restrictions.
-        */
-       if (sta_priv->max_agg_bufsize == 0)
-               sta_priv->max_agg_bufsize =
-                       LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-
-       /*
-        * Even though in theory the peer could have different
-        * aggregation reorder buffer sizes for different sessions,
-        * our ucode doesn't allow for that and has a global limit
-        * for each station. Therefore, use the minimum of all the
-        * aggregation sessions and our default value.
-        */
-       sta_priv->max_agg_bufsize =
-               min(sta_priv->max_agg_bufsize, buf_size);
-
-       if (priv->hw_params.use_rts_for_aggregation) {
-               /*
-                * switch to RTS/CTS if it is the prefer protection
-                * method for HT traffic
-                */
-
-               sta_priv->lq_sta.lq.general_params.flags |=
-                       LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-       }
-       priv->agg_tids_count++;
-       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                    priv->agg_tids_count);
-
-       sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
-               sta_priv->max_agg_bufsize;
-
-       IWL_DEBUG_HT(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
-                sta->addr, tid);
-
-       return iwl_send_lq_cmd(priv, ctx,
-                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-}
-
-static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
-{
-       struct iwl_tid_data *tid_data = &priv->tid_data[sta_id][tid];
-       enum iwl_rxon_context_id ctx;
-       struct ieee80211_vif *vif;
-       u8 *addr;
-
-       lockdep_assert_held(&priv->sta_lock);
-
-       addr = priv->stations[sta_id].sta.sta.addr;
-       ctx = priv->stations[sta_id].ctxid;
-       vif = priv->contexts[ctx].vif;
-
-       switch (priv->tid_data[sta_id][tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* There are no packets for this RA / TID in the HW any more */
-               if (tid_data->agg.ssn == tid_data->next_reclaimed) {
-                       IWL_DEBUG_TX_QUEUES(priv,
-                               "Can continue DELBA flow ssn = next_recl ="
-                               " %d", tid_data->next_reclaimed);
-                       iwl_trans_tx_agg_disable(priv->trans,
-                                                tid_data->agg.txq_id);
-                       iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* There are no packets for this RA / TID in the HW any more */
-               if (tid_data->agg.ssn == tid_data->next_reclaimed) {
-                       IWL_DEBUG_TX_QUEUES(priv,
-                               "Can continue ADDBA flow ssn = next_recl ="
-                               " %d", tid_data->next_reclaimed);
-                       tid_data->agg.state = IWL_AGG_STARTING;
-                       ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
-                                    struct iwl_rxon_context *ctx,
-                                    const u8 *addr1)
-{
-       struct ieee80211_sta *sta;
-       struct iwl_station_priv *sta_priv;
-
-       rcu_read_lock();
-       sta = ieee80211_find_sta(ctx->vif, addr1);
-       if (sta) {
-               sta_priv = (void *)sta->drv_priv;
-               /* avoid atomic ops if this isn't a client */
-               if (sta_priv->client &&
-                   atomic_dec_return(&sta_priv->pending_frames) == 0)
-                       ieee80211_sta_block_awake(priv->hw, sta, false);
-       }
-       rcu_read_unlock();
-}
-
-/**
- * translate ucode response to mac80211 tx status control values
- */
-static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                                 struct ieee80211_tx_info *info)
-{
-       struct ieee80211_tx_rate *r = &info->status.rates[0];
-
-       info->status.antenna =
-               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               r->flags |= IEEE80211_TX_RC_MCS;
-       if (rate_n_flags & RATE_MCS_GF_MSK)
-               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-       if (rate_n_flags & RATE_MCS_DUP_MSK)
-               r->flags |= IEEE80211_TX_RC_DUP_DATA;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               r->flags |= IEEE80211_TX_RC_SHORT_GI;
-       r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status)
-{
-#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
-#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
-
-       switch (status & TX_STATUS_MSK) {
-       case TX_STATUS_SUCCESS:
-               return "SUCCESS";
-       TX_STATUS_POSTPONE(DELAY);
-       TX_STATUS_POSTPONE(FEW_BYTES);
-       TX_STATUS_POSTPONE(BT_PRIO);
-       TX_STATUS_POSTPONE(QUIET_PERIOD);
-       TX_STATUS_POSTPONE(CALC_TTAK);
-       TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
-       TX_STATUS_FAIL(SHORT_LIMIT);
-       TX_STATUS_FAIL(LONG_LIMIT);
-       TX_STATUS_FAIL(FIFO_UNDERRUN);
-       TX_STATUS_FAIL(DRAIN_FLOW);
-       TX_STATUS_FAIL(RFKILL_FLUSH);
-       TX_STATUS_FAIL(LIFE_EXPIRE);
-       TX_STATUS_FAIL(DEST_PS);
-       TX_STATUS_FAIL(HOST_ABORTED);
-       TX_STATUS_FAIL(BT_RETRY);
-       TX_STATUS_FAIL(STA_INVALID);
-       TX_STATUS_FAIL(FRAG_DROPPED);
-       TX_STATUS_FAIL(TID_DISABLE);
-       TX_STATUS_FAIL(FIFO_FLUSHED);
-       TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
-       TX_STATUS_FAIL(PASSIVE_NO_RX);
-       TX_STATUS_FAIL(NO_BEACON_ON_RADAR);
-       }
-
-       return "UNKNOWN";
-
-#undef TX_STATUS_FAIL
-#undef TX_STATUS_POSTPONE
-}
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
-{
-       status &= AGG_TX_STATUS_MSK;
-
-       switch (status) {
-       case AGG_TX_STATE_UNDERRUN_MSK:
-               priv->reply_agg_tx_stats.underrun++;
-               break;
-       case AGG_TX_STATE_BT_PRIO_MSK:
-               priv->reply_agg_tx_stats.bt_prio++;
-               break;
-       case AGG_TX_STATE_FEW_BYTES_MSK:
-               priv->reply_agg_tx_stats.few_bytes++;
-               break;
-       case AGG_TX_STATE_ABORT_MSK:
-               priv->reply_agg_tx_stats.abort++;
-               break;
-       case AGG_TX_STATE_LAST_SENT_TTL_MSK:
-               priv->reply_agg_tx_stats.last_sent_ttl++;
-               break;
-       case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK:
-               priv->reply_agg_tx_stats.last_sent_try++;
-               break;
-       case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK:
-               priv->reply_agg_tx_stats.last_sent_bt_kill++;
-               break;
-       case AGG_TX_STATE_SCD_QUERY_MSK:
-               priv->reply_agg_tx_stats.scd_query++;
-               break;
-       case AGG_TX_STATE_TEST_BAD_CRC32_MSK:
-               priv->reply_agg_tx_stats.bad_crc32++;
-               break;
-       case AGG_TX_STATE_RESPONSE_MSK:
-               priv->reply_agg_tx_stats.response++;
-               break;
-       case AGG_TX_STATE_DUMP_TX_MSK:
-               priv->reply_agg_tx_stats.dump_tx++;
-               break;
-       case AGG_TX_STATE_DELAY_TX_MSK:
-               priv->reply_agg_tx_stats.delay_tx++;
-               break;
-       default:
-               priv->reply_agg_tx_stats.unknown++;
-               break;
-       }
-}
-
-static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
-                               struct iwlagn_tx_resp *tx_resp)
-{
-       struct agg_tx_status *frame_status = &tx_resp->status;
-       int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
-               IWLAGN_TX_RES_TID_POS;
-       int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
-               IWLAGN_TX_RES_RA_POS;
-       struct iwl_ht_agg *agg = &priv->tid_data[sta_id][tid].agg;
-       u32 status = le16_to_cpu(tx_resp->status.status);
-       int i;
-
-       WARN_ON(tid == IWL_TID_NON_QOS);
-
-       if (agg->wait_for_ba)
-               IWL_DEBUG_TX_REPLY(priv,
-                       "got tx response w/o block-ack\n");
-
-       agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-       agg->wait_for_ba = (tx_resp->frame_count > 1);
-
-       /*
-        * If the BT kill count is non-zero, we'll get this
-        * notification again.
-        */
-       if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
-           priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
-       }
-
-       if (tx_resp->frame_count == 1)
-               return;
-
-       /* Construct bit-map of pending frames within Tx window */
-       for (i = 0; i < tx_resp->frame_count; i++) {
-               u16 fstatus = le16_to_cpu(frame_status[i].status);
-
-               if (status & AGG_TX_STATUS_MSK)
-                       iwlagn_count_agg_tx_err_status(priv, fstatus);
-
-               if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
-                             AGG_TX_STATE_ABORT_MSK))
-                       continue;
-
-               IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), "
-                                  "try-count (0x%08x)\n",
-                                  iwl_get_agg_tx_fail_reason(fstatus),
-                                  fstatus & AGG_TX_STATUS_MSK,
-                                  fstatus & AGG_TX_TRY_MSK);
-       }
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x
-
-const char *iwl_get_agg_tx_fail_reason(u16 status)
-{
-       status &= AGG_TX_STATUS_MSK;
-       switch (status) {
-       case AGG_TX_STATE_TRANSMITTED:
-               return "SUCCESS";
-               AGG_TX_STATE_FAIL(UNDERRUN_MSK);
-               AGG_TX_STATE_FAIL(BT_PRIO_MSK);
-               AGG_TX_STATE_FAIL(FEW_BYTES_MSK);
-               AGG_TX_STATE_FAIL(ABORT_MSK);
-               AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK);
-               AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK);
-               AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK);
-               AGG_TX_STATE_FAIL(SCD_QUERY_MSK);
-               AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK);
-               AGG_TX_STATE_FAIL(RESPONSE_MSK);
-               AGG_TX_STATE_FAIL(DUMP_TX_MSK);
-               AGG_TX_STATE_FAIL(DELAY_TX_MSK);
-       }
-
-       return "UNKNOWN";
-}
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
-{
-       return le32_to_cpup((__le32 *)&tx_resp->status +
-                           tx_resp->frame_count) & MAX_SN;
-}
-
-static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
-{
-       status &= TX_STATUS_MSK;
-
-       switch (status) {
-       case TX_STATUS_POSTPONE_DELAY:
-               priv->reply_tx_stats.pp_delay++;
-               break;
-       case TX_STATUS_POSTPONE_FEW_BYTES:
-               priv->reply_tx_stats.pp_few_bytes++;
-               break;
-       case TX_STATUS_POSTPONE_BT_PRIO:
-               priv->reply_tx_stats.pp_bt_prio++;
-               break;
-       case TX_STATUS_POSTPONE_QUIET_PERIOD:
-               priv->reply_tx_stats.pp_quiet_period++;
-               break;
-       case TX_STATUS_POSTPONE_CALC_TTAK:
-               priv->reply_tx_stats.pp_calc_ttak++;
-               break;
-       case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY:
-               priv->reply_tx_stats.int_crossed_retry++;
-               break;
-       case TX_STATUS_FAIL_SHORT_LIMIT:
-               priv->reply_tx_stats.short_limit++;
-               break;
-       case TX_STATUS_FAIL_LONG_LIMIT:
-               priv->reply_tx_stats.long_limit++;
-               break;
-       case TX_STATUS_FAIL_FIFO_UNDERRUN:
-               priv->reply_tx_stats.fifo_underrun++;
-               break;
-       case TX_STATUS_FAIL_DRAIN_FLOW:
-               priv->reply_tx_stats.drain_flow++;
-               break;
-       case TX_STATUS_FAIL_RFKILL_FLUSH:
-               priv->reply_tx_stats.rfkill_flush++;
-               break;
-       case TX_STATUS_FAIL_LIFE_EXPIRE:
-               priv->reply_tx_stats.life_expire++;
-               break;
-       case TX_STATUS_FAIL_DEST_PS:
-               priv->reply_tx_stats.dest_ps++;
-               break;
-       case TX_STATUS_FAIL_HOST_ABORTED:
-               priv->reply_tx_stats.host_abort++;
-               break;
-       case TX_STATUS_FAIL_BT_RETRY:
-               priv->reply_tx_stats.bt_retry++;
-               break;
-       case TX_STATUS_FAIL_STA_INVALID:
-               priv->reply_tx_stats.sta_invalid++;
-               break;
-       case TX_STATUS_FAIL_FRAG_DROPPED:
-               priv->reply_tx_stats.frag_drop++;
-               break;
-       case TX_STATUS_FAIL_TID_DISABLE:
-               priv->reply_tx_stats.tid_disable++;
-               break;
-       case TX_STATUS_FAIL_FIFO_FLUSHED:
-               priv->reply_tx_stats.fifo_flush++;
-               break;
-       case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL:
-               priv->reply_tx_stats.insuff_cf_poll++;
-               break;
-       case TX_STATUS_FAIL_PASSIVE_NO_RX:
-               priv->reply_tx_stats.fail_hw_drop++;
-               break;
-       case TX_STATUS_FAIL_NO_BEACON_ON_RADAR:
-               priv->reply_tx_stats.sta_color_mismatch++;
-               break;
-       default:
-               priv->reply_tx_stats.unknown++;
-               break;
-       }
-}
-
-static void iwlagn_set_tx_status(struct iwl_priv *priv,
-                                struct ieee80211_tx_info *info,
-                                struct iwlagn_tx_resp *tx_resp,
-                                bool is_agg)
-{
-       u16  status = le16_to_cpu(tx_resp->status.status);
-
-       info->status.rates[0].count = tx_resp->failure_frame + 1;
-       if (is_agg)
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-       info->flags |= iwl_tx_status_to_mac80211(status);
-       iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
-                                   info);
-       if (!iwl_is_tx_success(status))
-               iwlagn_count_tx_err_status(priv, status);
-}
-
-static void iwl_check_abort_status(struct iwl_priv *priv,
-                           u8 frame_count, u32 status)
-{
-       if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
-               IWL_ERR(priv, "Tx flush command to flush out all frames\n");
-               if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
-                       queue_work(priv->workqueue, &priv->tx_flush);
-       }
-}
-
-static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid,
-                      int txq_id, int ssn, struct sk_buff_head *skbs)
-{
-       if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
-                    tid != IWL_TID_NON_QOS &&
-                    txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) {
-               /*
-                * FIXME: this is a uCode bug which need to be addressed,
-                * log the information and return for now.
-                * Since it is can possibly happen very often and in order
-                * not to fill the syslog, don't use IWL_ERR or IWL_WARN
-                */
-               IWL_DEBUG_TX_QUEUES(priv,
-                       "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n",
-                       txq_id, sta_id, tid,
-                       priv->tid_data[sta_id][tid].agg.txq_id);
-               return 1;
-       }
-
-       iwl_trans_reclaim(priv->trans, txq_id, ssn, skbs);
-       return 0;
-}
-
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence);
-       struct iwlagn_tx_resp *tx_resp = (void *)pkt->data;
-       struct ieee80211_hdr *hdr;
-       u32 status = le16_to_cpu(tx_resp->status.status);
-       u16 ssn = iwlagn_get_scd_ssn(tx_resp);
-       int tid;
-       int sta_id;
-       int freed;
-       struct ieee80211_tx_info *info;
-       struct sk_buff_head skbs;
-       struct sk_buff *skb;
-       struct iwl_rxon_context *ctx;
-       bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
-
-       tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
-               IWLAGN_TX_RES_TID_POS;
-       sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >>
-               IWLAGN_TX_RES_RA_POS;
-
-       spin_lock(&priv->sta_lock);
-
-       if (is_agg)
-               iwl_rx_reply_tx_agg(priv, tx_resp);
-
-       __skb_queue_head_init(&skbs);
-
-       if (tx_resp->frame_count == 1) {
-               u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
-               next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
-
-               if (is_agg) {
-                       /* If this is an aggregation queue, we can rely on the
-                        * ssn since the wifi sequence number corresponds to
-                        * the index in the TFD ring (%256).
-                        * The seq_ctl is the sequence control of the packet
-                        * to which this Tx response relates. But if there is a
-                        * hole in the bitmap of the BA we received, this Tx
-                        * response may allow to reclaim the hole and all the
-                        * subsequent packets that were already acked.
-                        * In that case, seq_ctl != ssn, and the next packet
-                        * to be reclaimed will be ssn and not seq_ctl.
-                        */
-                       next_reclaimed = ssn;
-               }
-
-               if (tid != IWL_TID_NON_QOS) {
-                       priv->tid_data[sta_id][tid].next_reclaimed =
-                               next_reclaimed;
-                       IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n",
-                                                 next_reclaimed);
-               }
-
-               /*we can free until ssn % q.n_bd not inclusive */
-               WARN_ON(iwl_reclaim(priv, sta_id, tid, txq_id, ssn, &skbs));
-               iwlagn_check_ratid_empty(priv, sta_id, tid);
-               freed = 0;
-
-               /* process frames */
-               skb_queue_walk(&skbs, skb) {
-                       hdr = (struct ieee80211_hdr *)skb->data;
-
-                       if (!ieee80211_is_data_qos(hdr->frame_control))
-                               priv->last_seq_ctl = tx_resp->seq_ctl;
-
-                       info = IEEE80211_SKB_CB(skb);
-                       ctx = info->driver_data[0];
-                       kmem_cache_free(iwl_tx_cmd_pool,
-                                       (info->driver_data[1]));
-
-                       memset(&info->status, 0, sizeof(info->status));
-
-                       if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
-                           iwl_is_associated_ctx(ctx) && ctx->vif &&
-                           ctx->vif->type == NL80211_IFTYPE_STATION) {
-                               /* block and stop all queues */
-                               priv->passive_no_rx = true;
-                               IWL_DEBUG_TX_QUEUES(priv, "stop all queues: "
-                                                   "passive channel");
-                               ieee80211_stop_queues(priv->hw);
-
-                               IWL_DEBUG_TX_REPLY(priv,
-                                          "TXQ %d status %s (0x%08x) "
-                                          "rate_n_flags 0x%x retries %d\n",
-                                          txq_id,
-                                          iwl_get_tx_fail_reason(status),
-                                          status,
-                                          le32_to_cpu(tx_resp->rate_n_flags),
-                                          tx_resp->failure_frame);
-
-                               IWL_DEBUG_TX_REPLY(priv,
-                                          "FrameCnt = %d, idx=%d\n",
-                                          tx_resp->frame_count, cmd_index);
-                       }
-
-                       /* check if BAR is needed */
-                       if (is_agg && !iwl_is_tx_success(status))
-                               info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-                       iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
-                                    tx_resp, is_agg);
-                       if (!is_agg)
-                               iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
-
-                       freed++;
-               }
-
-               WARN_ON(!is_agg && freed != 1);
-       }
-
-       iwl_check_abort_status(priv, tx_resp->frame_count, status);
-       spin_unlock(&priv->sta_lock);
-
-       while (!skb_queue_empty(&skbs)) {
-               skb = __skb_dequeue(&skbs);
-               ieee80211_tx_status(priv->hw, skb);
-       }
-
-       return 0;
-}
-
-/**
- * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
- *
- * Handles block-acknowledge notification from device, which reports success
- * of frames sent via aggregation.
- */
-int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                  struct iwl_rx_cmd_buffer *rxb,
-                                  struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data;
-       struct iwl_ht_agg *agg;
-       struct sk_buff_head reclaimed_skbs;
-       struct ieee80211_tx_info *info;
-       struct ieee80211_hdr *hdr;
-       struct sk_buff *skb;
-       int sta_id;
-       int tid;
-       int freed;
-
-       /* "flow" corresponds to Tx queue */
-       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-
-       /* "ssn" is start of block-ack Tx window, corresponds to index
-        * (in Tx queue's circular buffer) of first TFD/frame in window */
-       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
-
-       if (scd_flow >= priv->cfg->base_params->num_of_queues) {
-               IWL_ERR(priv,
-                       "BUG_ON scd_flow is bigger than number of queues\n");
-               return 0;
-       }
-
-       sta_id = ba_resp->sta_id;
-       tid = ba_resp->tid;
-       agg = &priv->tid_data[sta_id][tid].agg;
-
-       spin_lock(&priv->sta_lock);
-
-       if (unlikely(!agg->wait_for_ba)) {
-               if (unlikely(ba_resp->bitmap))
-                       IWL_ERR(priv, "Received BA when not expected\n");
-               spin_unlock(&priv->sta_lock);
-               return 0;
-       }
-
-       __skb_queue_head_init(&reclaimed_skbs);
-
-       /* Release all TFDs before the SSN, i.e. all TFDs in front of
-        * block-ack window (we assume that they've been successfully
-        * transmitted ... if not, it's too late anyway). */
-       if (iwl_reclaim(priv, sta_id, tid, scd_flow,
-                       ba_resp_scd_ssn, &reclaimed_skbs)) {
-               spin_unlock(&priv->sta_lock);
-               return 0;
-       }
-
-       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
-                          "sta_id = %d\n",
-                          agg->wait_for_ba,
-                          (u8 *) &ba_resp->sta_addr_lo32,
-                          ba_resp->sta_id);
-       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
-                          "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
-                          ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
-                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
-                          scd_flow, ba_resp_scd_ssn, ba_resp->txed,
-                          ba_resp->txed_2_done);
-
-       /* Mark that the expected block-ack response arrived */
-       agg->wait_for_ba = false;
-
-       /* Sanity check values reported by uCode */
-       if (ba_resp->txed_2_done > ba_resp->txed) {
-               IWL_DEBUG_TX_REPLY(priv,
-                       "bogus sent(%d) and ack(%d) count\n",
-                       ba_resp->txed, ba_resp->txed_2_done);
-               /*
-                * set txed_2_done = txed,
-                * so it won't impact rate scale
-                */
-               ba_resp->txed = ba_resp->txed_2_done;
-       }
-
-       priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
-
-       iwlagn_check_ratid_empty(priv, sta_id, tid);
-       freed = 0;
-
-       skb_queue_walk(&reclaimed_skbs, skb) {
-               hdr = (struct ieee80211_hdr *)skb->data;
-
-               if (ieee80211_is_data_qos(hdr->frame_control))
-                       freed++;
-               else
-                       WARN_ON_ONCE(1);
-
-               info = IEEE80211_SKB_CB(skb);
-               kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
-
-               if (freed == 1) {
-                       /* this is the first skb we deliver in this batch */
-                       /* put the rate scaling data there */
-                       info = IEEE80211_SKB_CB(skb);
-                       memset(&info->status, 0, sizeof(info->status));
-                       info->flags |= IEEE80211_TX_STAT_ACK;
-                       info->flags |= IEEE80211_TX_STAT_AMPDU;
-                       info->status.ampdu_ack_len = ba_resp->txed_2_done;
-                       info->status.ampdu_len = ba_resp->txed;
-                       iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags,
-                                                   info);
-               }
-       }
-
-       spin_unlock(&priv->sta_lock);
-
-       while (!skb_queue_empty(&reclaimed_skbs)) {
-               skb = __skb_dequeue(&reclaimed_skbs);
-               ieee80211_tx_status(priv->hw, skb);
-       }
-
-       return 0;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
deleted file mode 100644 (file)
index ec36e2b..0000000
+++ /dev/null
@@ -1,2367 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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
- *
- *****************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-
-#include <net/mac80211.h>
-
-#include <asm/div64.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-drv.h"
-#include "iwl-modparams.h"
-
-/******************************************************************************
- *
- * module boiler plate
- *
- ******************************************************************************/
-
-/*
- * module name, copyright, version, etc.
- */
-#define DRV_DESCRIPTION        "Intel(R) Wireless WiFi Link AGN driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION     IWLWIFI_VERSION VD
-
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("iwlagn");
-
-void iwl_update_chain_flags(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-
-       for_each_context(priv, ctx) {
-               iwlagn_set_rxon_chain(priv, ctx);
-               if (ctx->active.rx_chain != ctx->staging.rx_chain)
-                       iwlagn_commit_rxon(priv, ctx);
-       }
-}
-
-/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
-static void iwl_set_beacon_tim(struct iwl_priv *priv,
-                              struct iwl_tx_beacon_cmd *tx_beacon_cmd,
-                              u8 *beacon, u32 frame_size)
-{
-       u16 tim_idx;
-       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
-
-       /*
-        * The index is relative to frame start but we start looking at the
-        * variable-length part of the beacon.
-        */
-       tim_idx = mgmt->u.beacon.variable - beacon;
-
-       /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
-       while ((tim_idx < (frame_size - 2)) &&
-                       (beacon[tim_idx] != WLAN_EID_TIM))
-               tim_idx += beacon[tim_idx+1] + 2;
-
-       /* If TIM field was found, set variables */
-       if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
-               tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
-               tx_beacon_cmd->tim_size = beacon[tim_idx+1];
-       } else
-               IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
-}
-
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
-{
-       struct iwl_tx_beacon_cmd *tx_beacon_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_TX_BEACON,
-               .flags = CMD_SYNC,
-       };
-       struct ieee80211_tx_info *info;
-       u32 frame_size;
-       u32 rate_flags;
-       u32 rate;
-
-       /*
-        * We have to set up the TX command, the TX Beacon command, and the
-        * beacon contents.
-        */
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (!priv->beacon_ctx) {
-               IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
-               return 0;
-       }
-
-       if (WARN_ON(!priv->beacon_skb))
-               return -EINVAL;
-
-       /* Allocate beacon command */
-       if (!priv->beacon_cmd)
-               priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
-       tx_beacon_cmd = priv->beacon_cmd;
-       if (!tx_beacon_cmd)
-               return -ENOMEM;
-
-       frame_size = priv->beacon_skb->len;
-
-       /* Set up TX command fields */
-       tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
-       tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
-       tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-       tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
-               TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
-
-       /* Set up TX beacon command fields */
-       iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
-                          frame_size);
-
-       /* Set up packet rate and flags */
-       info = IEEE80211_SKB_CB(priv->beacon_skb);
-
-       /*
-        * Let's set up the rate at least somewhat correctly;
-        * it will currently not actually be used by the uCode,
-        * it uses the broadcast station's rate instead.
-        */
-       if (info->control.rates[0].idx < 0 ||
-           info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
-               rate = 0;
-       else
-               rate = info->control.rates[0].idx;
-
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
-                                             priv->hw_params.valid_tx_ant);
-       rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
-
-       /* In mac80211, rates for 5 GHz start at 0 */
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate += IWL_FIRST_OFDM_RATE;
-       else if (rate >= IWL_FIRST_CCK_RATE && rate <= IWL_LAST_CCK_RATE)
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-       tx_beacon_cmd->tx.rate_n_flags =
-                       iwl_hw_set_rate_n_flags(rate, rate_flags);
-
-       /* Submit command */
-       cmd.len[0] = sizeof(*tx_beacon_cmd);
-       cmd.data[0] = tx_beacon_cmd;
-       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-       cmd.len[1] = frame_size;
-       cmd.data[1] = priv->beacon_skb->data;
-       cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-static void iwl_bg_beacon_update(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, beacon_update);
-       struct sk_buff *beacon;
-
-       mutex_lock(&priv->mutex);
-       if (!priv->beacon_ctx) {
-               IWL_ERR(priv, "updating beacon w/o beacon context!\n");
-               goto out;
-       }
-
-       if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
-               /*
-                * The ucode will send beacon notifications even in
-                * IBSS mode, but we don't want to process them. But
-                * we need to defer the type check to here due to
-                * requiring locking around the beacon_ctx access.
-                */
-               goto out;
-       }
-
-       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
-       if (!beacon) {
-               IWL_ERR(priv, "update beacon failed -- keeping old\n");
-               goto out;
-       }
-
-       /* new beacon skb is allocated every time; dispose previous.*/
-       dev_kfree_skb(priv->beacon_skb);
-
-       priv->beacon_skb = beacon;
-
-       iwlagn_send_beacon_cmd(priv);
- out:
-       mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_bt_runtime_config(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, bt_runtime_config);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv))
-               return;
-       iwlagn_send_advance_bt_config(priv);
-}
-
-static void iwl_bg_bt_full_concurrency(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, bt_full_concurrency);
-       struct iwl_rxon_context *ctx;
-
-       mutex_lock(&priv->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               goto out;
-
-       /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv))
-               goto out;
-
-       IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
-                      priv->bt_full_concurrent ?
-                      "full concurrency" : "3-wire");
-
-       /*
-        * LQ & RXON updated cmds must be sent before BT Config cmd
-        * to avoid 3-wire collisions
-        */
-       for_each_context(priv, ctx) {
-               iwlagn_set_rxon_chain(priv, ctx);
-               iwlagn_commit_rxon(priv, ctx);
-       }
-
-       iwlagn_send_advance_bt_config(priv);
-out:
-       mutex_unlock(&priv->mutex);
-}
-
-int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
-{
-       struct iwl_statistics_cmd statistics_cmd = {
-               .configuration_flags =
-                       clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
-       };
-
-       if (flags & CMD_ASYNC)
-               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
-                                       CMD_ASYNC,
-                                       sizeof(struct iwl_statistics_cmd),
-                                       &statistics_cmd);
-       else
-               return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
-                                       CMD_SYNC,
-                                       sizeof(struct iwl_statistics_cmd),
-                                       &statistics_cmd);
-}
-
-/**
- * iwl_bg_statistics_periodic - Timer callback to queue statistics
- *
- * This callback is provided in order to send a statistics request.
- *
- * This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
- * was received.  We need to ensure we receive the statistics in order
- * to update the temperature used for calibrating the TXPOWER.
- */
-static void iwl_bg_statistics_periodic(unsigned long data)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       /* dont send host command if rf-kill is on */
-       if (!iwl_is_ready_rf(priv))
-               return;
-
-       iwl_send_statistics_request(priv, CMD_ASYNC, false);
-}
-
-
-static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
-                                       u32 start_idx, u32 num_events,
-                                       u32 capacity, u32 mode)
-{
-       u32 i;
-       u32 ptr;        /* SRAM byte address of log data */
-       u32 ev, time, data; /* event log data */
-       unsigned long reg_flags;
-
-       if (mode == 0)
-               ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
-       else
-               ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
-
-       /* Make sure device is powered up for SRAM reads */
-       spin_lock_irqsave(&priv->trans->reg_lock, reg_flags);
-       if (unlikely(!iwl_grab_nic_access(priv->trans))) {
-               spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
-               return;
-       }
-
-       /* Set starting address; reads will auto-increment */
-       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr);
-
-       /*
-        * Refuse to read more than would have fit into the log from
-        * the current start_idx. This used to happen due to the race
-        * described below, but now WARN because the code below should
-        * prevent it from happening here.
-        */
-       if (WARN_ON(num_events > capacity - start_idx))
-               num_events = capacity - start_idx;
-
-       /*
-        * "time" is actually "data" for mode 0 (no timestamp).
-        * place event id # at far right for easier visual parsing.
-        */
-       for (i = 0; i < num_events; i++) {
-               ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               if (mode == 0) {
-                       trace_iwlwifi_dev_ucode_cont_event(
-                                       priv->trans->dev, 0, time, ev);
-               } else {
-                       data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-                       trace_iwlwifi_dev_ucode_cont_event(
-                                       priv->trans->dev, time, data, ev);
-               }
-       }
-       /* Allow device to power down */
-       iwl_release_nic_access(priv->trans);
-       spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags);
-}
-
-static void iwl_continuous_event_trace(struct iwl_priv *priv)
-{
-       u32 capacity;   /* event log capacity in # entries */
-       struct {
-               u32 capacity;
-               u32 mode;
-               u32 wrap_counter;
-               u32 write_counter;
-       } __packed read;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-       u32 num_wraps;  /* # times uCode wrapped to top of log */
-       u32 next_entry; /* index of next entry to be written by uCode */
-
-       base = priv->device_pointers.log_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               iwl_read_targ_mem_words(priv->trans, base, &read, sizeof(read));
-               capacity = read.capacity;
-               mode = read.mode;
-               num_wraps = read.wrap_counter;
-               next_entry = read.write_counter;
-       } else
-               return;
-
-       /*
-        * Unfortunately, the uCode doesn't use temporary variables.
-        * Therefore, it can happen that we read next_entry == capacity,
-        * which really means next_entry == 0.
-        */
-       if (unlikely(next_entry == capacity))
-               next_entry = 0;
-       /*
-        * Additionally, the uCode increases the write pointer before
-        * the wraps counter, so if the write pointer is smaller than
-        * the old write pointer (wrap occurred) but we read that no
-        * wrap occurred, we actually read between the next_entry and
-        * num_wraps update (this does happen in practice!!) -- take
-        * that into account by increasing num_wraps.
-        */
-       if (unlikely(next_entry < priv->event_log.next_entry &&
-                    num_wraps == priv->event_log.num_wraps))
-               num_wraps++;
-
-       if (num_wraps == priv->event_log.num_wraps) {
-               iwl_print_cont_event_trace(
-                       priv, base, priv->event_log.next_entry,
-                       next_entry - priv->event_log.next_entry,
-                       capacity, mode);
-
-               priv->event_log.non_wraps_count++;
-       } else {
-               if (num_wraps - priv->event_log.num_wraps > 1)
-                       priv->event_log.wraps_more_count++;
-               else
-                       priv->event_log.wraps_once_count++;
-
-               trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev,
-                               num_wraps - priv->event_log.num_wraps,
-                               next_entry, priv->event_log.next_entry);
-
-               if (next_entry < priv->event_log.next_entry) {
-                       iwl_print_cont_event_trace(
-                               priv, base, priv->event_log.next_entry,
-                               capacity - priv->event_log.next_entry,
-                               capacity, mode);
-
-                       iwl_print_cont_event_trace(
-                               priv, base, 0, next_entry, capacity, mode);
-               } else {
-                       iwl_print_cont_event_trace(
-                               priv, base, next_entry,
-                               capacity - next_entry,
-                               capacity, mode);
-
-                       iwl_print_cont_event_trace(
-                               priv, base, 0, next_entry, capacity, mode);
-               }
-       }
-
-       priv->event_log.num_wraps = num_wraps;
-       priv->event_log.next_entry = next_entry;
-}
-
-/**
- * iwl_bg_ucode_trace - Timer callback to log ucode event
- *
- * The timer is continually set to execute every
- * UCODE_TRACE_PERIOD milliseconds after the last timer expired
- * this function is to perform continuous uCode event logging operation
- * if enabled
- */
-static void iwl_bg_ucode_trace(unsigned long data)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (priv->event_log.ucode_trace) {
-               iwl_continuous_event_trace(priv);
-               /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
-               mod_timer(&priv->ucode_trace,
-                        jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
-       }
-}
-
-static void iwl_bg_tx_flush(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, tx_flush);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       /* do nothing if rf-kill is on */
-       if (!iwl_is_ready_rf(priv))
-               return;
-
-       IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
-       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
-}
-
-/*
- * queue/FIFO/AC mapping definitions
- */
-
-#define IWL_TX_FIFO_BK         0       /* shared */
-#define IWL_TX_FIFO_BE         1
-#define IWL_TX_FIFO_VI         2       /* shared */
-#define IWL_TX_FIFO_VO         3
-#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
-#define IWL_TX_FIFO_BE_IPAN    4
-#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
-#define IWL_TX_FIFO_VO_IPAN    5
-/* re-uses the VO FIFO, uCode will properly flush/schedule */
-#define IWL_TX_FIFO_AUX                5
-#define IWL_TX_FIFO_UNUSED     -1
-
-#define IWLAGN_CMD_FIFO_NUM    7
-
-/*
- * This queue number is required for proper operation
- * because the ucode will stop/start the scheduler as
- * required.
- */
-#define IWL_IPAN_MCAST_QUEUE   8
-
-static const u8 iwlagn_default_queue_to_tx_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-       IWLAGN_CMD_FIFO_NUM,
-};
-
-static const u8 iwlagn_ipan_queue_to_tx_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-       IWL_TX_FIFO_BK_IPAN,
-       IWL_TX_FIFO_BE_IPAN,
-       IWL_TX_FIFO_VI_IPAN,
-       IWL_TX_FIFO_VO_IPAN,
-       IWL_TX_FIFO_BE_IPAN,
-       IWLAGN_CMD_FIFO_NUM,
-       IWL_TX_FIFO_AUX,
-};
-
-static const u8 iwlagn_bss_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-
-static const u8 iwlagn_bss_ac_to_queue[] = {
-       0, 1, 2, 3,
-};
-
-static const u8 iwlagn_pan_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO_IPAN,
-       IWL_TX_FIFO_VI_IPAN,
-       IWL_TX_FIFO_BE_IPAN,
-       IWL_TX_FIFO_BK_IPAN,
-};
-
-static const u8 iwlagn_pan_ac_to_queue[] = {
-       7, 6, 5, 4,
-};
-
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
-{
-       int i;
-
-       /*
-        * The default context is always valid,
-        * the PAN context depends on uCode.
-        */
-       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
-       if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN)
-               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
-
-       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
-               priv->contexts[i].ctxid = i;
-
-       priv->contexts[IWL_RXON_CTX_BSS].always_active = true;
-       priv->contexts[IWL_RXON_CTX_BSS].is_active = true;
-       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
-       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
-       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
-       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
-       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
-       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
-       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
-       priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
-               BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
-       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
-               BIT(NL80211_IFTYPE_STATION);
-       priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
-       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
-       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
-       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
-       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue,
-              iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue));
-       memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo,
-              iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo));
-
-       priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
-       priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd =
-               REPLY_WIPAN_RXON_TIMING;
-       priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd =
-               REPLY_WIPAN_RXON_ASSOC;
-       priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
-       priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
-       priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
-       priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
-       priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
-       priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
-               BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
-
-       if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P)
-               priv->contexts[IWL_RXON_CTX_PAN].interface_modes |=
-                       BIT(NL80211_IFTYPE_P2P_CLIENT) |
-                       BIT(NL80211_IFTYPE_P2P_GO);
-
-       priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
-       priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
-       priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
-       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue,
-              iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue));
-       memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo,
-              iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo));
-       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-}
-
-void iwl_rf_kill_ct_config(struct iwl_priv *priv)
-{
-       struct iwl_ct_kill_config cmd;
-       struct iwl_ct_kill_throttling_config adv_cmd;
-       int ret = 0;
-
-       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-
-       priv->thermal_throttle.ct_kill_toggle = false;
-
-       if (priv->cfg->base_params->support_ct_kill_exit) {
-               adv_cmd.critical_temperature_enter =
-                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
-               adv_cmd.critical_temperature_exit =
-                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
-
-               ret = iwl_dvm_send_cmd_pdu(priv,
-                                      REPLY_CT_KILL_CONFIG_CMD,
-                                      CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
-               if (ret)
-                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-               else
-                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-                               "succeeded, critical temperature enter is %d,"
-                               "exit is %d\n",
-                               priv->hw_params.ct_kill_threshold,
-                               priv->hw_params.ct_kill_exit_threshold);
-       } else {
-               cmd.critical_temperature_R =
-                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
-               ret = iwl_dvm_send_cmd_pdu(priv,
-                                      REPLY_CT_KILL_CONFIG_CMD,
-                                      CMD_SYNC, sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-               else
-                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-                               "succeeded, "
-                               "critical temperature is %d\n",
-                               priv->hw_params.ct_kill_threshold);
-       }
-}
-
-static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
-{
-       struct iwl_calib_cfg_cmd calib_cfg_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = CALIBRATION_CFG_CMD,
-               .len = { sizeof(struct iwl_calib_cfg_cmd), },
-               .data = { &calib_cfg_cmd, },
-       };
-
-       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-
-static int iwlagn_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->fw->ucode_ver) > 1) {
-               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-               return iwl_dvm_send_cmd_pdu(priv,
-                                       TX_ANT_CONFIGURATION_CMD,
-                                       CMD_SYNC,
-                                       sizeof(struct iwl_tx_ant_config_cmd),
-                                       &tx_ant_cmd);
-       } else {
-               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
-               return -EOPNOTSUPP;
-       }
-}
-
-void iwl_send_bt_config(struct iwl_priv *priv)
-{
-       struct iwl_bt_cmd bt_cmd = {
-               .lead_time = BT_LEAD_TIME_DEF,
-               .max_kill = BT_MAX_KILL_DEF,
-               .kill_ack_mask = 0,
-               .kill_cts_mask = 0,
-       };
-
-       if (!iwlwifi_mod_params.bt_coex_active)
-               bt_cmd.flags = BT_COEX_DISABLE;
-       else
-               bt_cmd.flags = BT_COEX_ENABLE;
-
-       priv->bt_enable_flag = bt_cmd.flags;
-       IWL_DEBUG_INFO(priv, "BT coex %s\n",
-               (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
-
-       if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                            CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
-               IWL_ERR(priv, "failed to send BT Coex Config\n");
-}
-
-/**
- * iwl_alive_start - called after REPLY_ALIVE notification received
- *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl_init_alive_start()).
- */
-int iwl_alive_start(struct iwl_priv *priv)
-{
-       int ret = 0;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-       IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-
-       /* After the ALIVE response, we can send host commands to the uCode */
-       set_bit(STATUS_ALIVE, &priv->status);
-
-       if (iwl_is_rfkill(priv))
-               return -ERFKILL;
-
-       if (priv->event_log.ucode_trace) {
-               /* start collecting data now */
-               mod_timer(&priv->ucode_trace, jiffies);
-       }
-
-       /* download priority table before any calibration request */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               /* Configure Bluetooth device coexistence support */
-               if (priv->cfg->bt_params->bt_sco_disable)
-                       priv->bt_enable_pspoll = false;
-               else
-                       priv->bt_enable_pspoll = true;
-
-               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-               iwlagn_send_advance_bt_config(priv);
-               priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
-               priv->cur_rssi_ctx = NULL;
-
-               iwl_send_prio_tbl(priv);
-
-               /* FIXME: w/a to force change uCode BT state machine */
-               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
-                                        BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-               if (ret)
-                       return ret;
-               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
-                                        BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-               if (ret)
-                       return ret;
-       } else {
-               /*
-                * default is 2-wire BT coexexistence support
-                */
-               iwl_send_bt_config(priv);
-       }
-
-       /*
-        * Perform runtime calibrations, including DC calibration.
-        */
-       iwlagn_send_calib_cfg_rt(priv, IWL_CALIB_CFG_DC_IDX);
-
-       ieee80211_wake_queues(priv->hw);
-
-       /* Configure Tx antenna selection based on H/W config */
-       iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant);
-
-       if (iwl_is_associated_ctx(ctx) && !priv->wowlan) {
-               struct iwl_rxon_cmd *active_rxon =
-                               (struct iwl_rxon_cmd *)&ctx->active;
-               /* apply any changes in staging */
-               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       } else {
-               struct iwl_rxon_context *tmp;
-               /* Initialize our rx_config data */
-               for_each_context(priv, tmp)
-                       iwl_connection_init_rx_config(priv, tmp);
-
-               iwlagn_set_rxon_chain(priv, ctx);
-       }
-
-       if (!priv->wowlan) {
-               /* WoWLAN ucode will not reply in the same way, skip it */
-               iwl_reset_run_time_calib(priv);
-       }
-
-       set_bit(STATUS_READY, &priv->status);
-
-       /* Configure the adapter for unassociated operation */
-       ret = iwlagn_commit_rxon(priv, ctx);
-       if (ret)
-               return ret;
-
-       /* At this point, the NIC is initialized and operational */
-       iwl_rf_kill_ct_config(priv);
-
-       IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-
-       return iwl_power_update_mode(priv, true);
-}
-
-/**
- * iwl_clear_driver_stations - clear knowledge of all stations from driver
- * @priv: iwl priv struct
- *
- * This is called during iwl_down() to make sure that in the case
- * we're coming there from a hardware restart mac80211 will be
- * able to reconfigure stations -- if we're getting there in the
- * normal down flow then the stations will already be cleared.
- */
-static void iwl_clear_driver_stations(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-
-       spin_lock_bh(&priv->sta_lock);
-       memset(priv->stations, 0, sizeof(priv->stations));
-       priv->num_stations = 0;
-
-       priv->ucode_key_table = 0;
-
-       for_each_context(priv, ctx) {
-               /*
-                * Remove all key information that is not stored as part
-                * of station information since mac80211 may not have had
-                * a chance to remove all the keys. When device is
-                * reconfigured by mac80211 after an error all keys will
-                * be reconfigured.
-                */
-               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
-               ctx->key_mapping_keys = 0;
-       }
-
-       spin_unlock_bh(&priv->sta_lock);
-}
-
-void iwl_down(struct iwl_priv *priv)
-{
-       int exit_pending;
-
-       IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
-
-       lockdep_assert_held(&priv->mutex);
-
-       iwl_scan_cancel_timeout(priv, 200);
-
-       /*
-        * If active, scanning won't cancel it, so say it expired.
-        * No race since we hold the mutex here and a new one
-        * can't come in at this time.
-        */
-       ieee80211_remain_on_channel_expired(priv->hw);
-
-       exit_pending =
-               test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);
-
-       iwl_clear_ucode_stations(priv, NULL);
-       iwl_dealloc_bcast_stations(priv);
-       iwl_clear_driver_stations(priv);
-
-       /* reset BT coex data */
-       priv->bt_status = 0;
-       priv->cur_rssi_ctx = NULL;
-       priv->bt_is_sco = 0;
-       if (priv->cfg->bt_params)
-               priv->bt_traffic_load =
-                        priv->cfg->bt_params->bt_init_traffic_load;
-       else
-               priv->bt_traffic_load = 0;
-       priv->bt_full_concurrent = false;
-       priv->bt_ci_compliance = 0;
-
-       /* Wipe out the EXIT_PENDING status bit if we are not actually
-        * exiting the module */
-       if (!exit_pending)
-               clear_bit(STATUS_EXIT_PENDING, &priv->status);
-
-       if (priv->mac80211_registered)
-               ieee80211_stop_queues(priv->hw);
-
-       priv->ucode_loaded = false;
-       iwl_trans_stop_device(priv->trans);
-
-       /* Clear out all status bits but a few that are stable across reset */
-       priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
-                               STATUS_RF_KILL_HW |
-                       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
-                               STATUS_GEO_CONFIGURED |
-                       test_bit(STATUS_FW_ERROR, &priv->status) <<
-                               STATUS_FW_ERROR |
-                       test_bit(STATUS_EXIT_PENDING, &priv->status) <<
-                               STATUS_EXIT_PENDING;
-
-       dev_kfree_skb(priv->beacon_skb);
-       priv->beacon_skb = NULL;
-}
-
-/*****************************************************************************
- *
- * Workqueue callbacks
- *
- *****************************************************************************/
-
-static void iwl_bg_run_time_calib_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                       run_time_calib_work);
-
-       mutex_lock(&priv->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-           test_bit(STATUS_SCANNING, &priv->status)) {
-               mutex_unlock(&priv->mutex);
-               return;
-       }
-
-       if (priv->start_calib) {
-               iwl_chain_noise_calibration(priv);
-               iwl_sensitivity_calibration(priv);
-       }
-
-       mutex_unlock(&priv->mutex);
-}
-
-void iwlagn_prepare_restart(struct iwl_priv *priv)
-{
-       bool bt_full_concurrent;
-       u8 bt_ci_compliance;
-       u8 bt_load;
-       u8 bt_status;
-       bool bt_is_sco;
-       int i;
-
-       lockdep_assert_held(&priv->mutex);
-
-       priv->is_open = 0;
-
-       /*
-        * __iwl_down() will clear the BT status variables,
-        * which is correct, but when we restart we really
-        * want to keep them so restore them afterwards.
-        *
-        * The restart process will later pick them up and
-        * re-configure the hw when we reconfigure the BT
-        * command.
-        */
-       bt_full_concurrent = priv->bt_full_concurrent;
-       bt_ci_compliance = priv->bt_ci_compliance;
-       bt_load = priv->bt_traffic_load;
-       bt_status = priv->bt_status;
-       bt_is_sco = priv->bt_is_sco;
-
-       iwl_down(priv);
-
-       priv->bt_full_concurrent = bt_full_concurrent;
-       priv->bt_ci_compliance = bt_ci_compliance;
-       priv->bt_traffic_load = bt_load;
-       priv->bt_status = bt_status;
-       priv->bt_is_sco = bt_is_sco;
-
-       /* reset aggregation queues */
-       for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++)
-               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-       /* and stop counts */
-       for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
-               atomic_set(&priv->queue_stop_count[i], 0);
-
-       memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc));
-}
-
-static void iwl_bg_restart(struct work_struct *data)
-{
-       struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
-               mutex_lock(&priv->mutex);
-               iwlagn_prepare_restart(priv);
-               mutex_unlock(&priv->mutex);
-               iwl_cancel_deferred_work(priv);
-               ieee80211_restart_hw(priv->hw);
-       } else {
-               WARN_ON(1);
-       }
-}
-
-
-
-
-void iwlagn_disable_roc(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (!priv->hw_roc_setup)
-               return;
-
-       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-       priv->hw_roc_channel = NULL;
-
-       memset(ctx->staging.node_addr, 0, ETH_ALEN);
-
-       iwlagn_commit_rxon(priv, ctx);
-
-       ctx->is_active = false;
-       priv->hw_roc_setup = false;
-}
-
-static void iwlagn_disable_roc_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            hw_roc_disable_work.work);
-
-       mutex_lock(&priv->mutex);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->mutex);
-}
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-       priv->workqueue = create_singlethread_workqueue(DRV_NAME);
-
-       INIT_WORK(&priv->restart, iwl_bg_restart);
-       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
-       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
-       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
-       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
-                         iwlagn_disable_roc_work);
-
-       iwl_setup_scan_deferred_work(priv);
-
-       if (priv->cfg->bt_params)
-               iwlagn_bt_setup_deferred_work(priv);
-
-       init_timer(&priv->statistics_periodic);
-       priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
-
-       init_timer(&priv->ucode_trace);
-       priv->ucode_trace.data = (unsigned long)priv;
-       priv->ucode_trace.function = iwl_bg_ucode_trace;
-}
-
-void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-       if (priv->cfg->bt_params)
-               iwlagn_bt_cancel_deferred_work(priv);
-
-       cancel_work_sync(&priv->run_time_calib_work);
-       cancel_work_sync(&priv->beacon_update);
-
-       iwl_cancel_scan_deferred_work(priv);
-
-       cancel_work_sync(&priv->bt_full_concurrency);
-       cancel_work_sync(&priv->bt_runtime_config);
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       del_timer_sync(&priv->statistics_periodic);
-       del_timer_sync(&priv->ucode_trace);
-}
-
-static void iwl_init_hw_rates(struct ieee80211_rate *rates)
-{
-       int i;
-
-       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
-               rates[i].bitrate = iwl_rates[i].ieee * 5;
-               rates[i].hw_value = i; /* Rate scaling will work on indexes */
-               rates[i].hw_value_short = i;
-               rates[i].flags = 0;
-               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
-                       /*
-                        * If CCK != 1M then set short preamble rate flag.
-                        */
-                       rates[i].flags |=
-                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
-               }
-       }
-}
-
-#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
-#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
-static void iwl_init_ht_hw_capab(const struct iwl_priv *priv,
-                             struct ieee80211_sta_ht_cap *ht_info,
-                             enum ieee80211_band band)
-{
-       u16 max_bit_rate = 0;
-       u8 rx_chains_num = priv->hw_params.rx_chains_num;
-       u8 tx_chains_num = priv->hw_params.tx_chains_num;
-
-       ht_info->cap = 0;
-       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-
-       ht_info->ht_supported = true;
-
-       if (priv->cfg->ht_params &&
-           priv->cfg->ht_params->ht_greenfield_support)
-               ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
-       ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-       max_bit_rate = MAX_BIT_RATE_20_MHZ;
-       if (priv->hw_params.ht40_channel & BIT(band)) {
-               ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-               ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
-               ht_info->mcs.rx_mask[4] = 0x01;
-               max_bit_rate = MAX_BIT_RATE_40_MHZ;
-       }
-
-       if (iwlwifi_mod_params.amsdu_size_8K)
-               ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
-
-       ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-       ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
-
-       ht_info->mcs.rx_mask[0] = 0xFF;
-       if (rx_chains_num >= 2)
-               ht_info->mcs.rx_mask[1] = 0xFF;
-       if (rx_chains_num >= 3)
-               ht_info->mcs.rx_mask[2] = 0xFF;
-
-       /* Highest supported Rx data rate */
-       max_bit_rate *= rx_chains_num;
-       WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
-       ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
-
-       /* Tx MCS capabilities */
-       ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-       if (tx_chains_num != rx_chains_num) {
-               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
-               ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
-                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-       }
-}
-
-/**
- * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-static int iwl_init_geos(struct iwl_priv *priv)
-{
-       struct iwl_channel_info *ch;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *channels;
-       struct ieee80211_channel *geo_ch;
-       struct ieee80211_rate *rates;
-       int i = 0;
-       s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
-
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
-           priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
-               IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
-               set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-               return 0;
-       }
-
-       channels = kcalloc(priv->channel_count,
-                          sizeof(struct ieee80211_channel), GFP_KERNEL);
-       if (!channels)
-               return -ENOMEM;
-
-       rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
-                       GFP_KERNEL);
-       if (!rates) {
-               kfree(channels);
-               return -ENOMEM;
-       }
-
-       /* 5.2GHz channels start after the 2.4GHz channels */
-       sband = &priv->bands[IEEE80211_BAND_5GHZ];
-       sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
-       /* just OFDM */
-       sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
-       sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;
-
-       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-               iwl_init_ht_hw_capab(priv, &sband->ht_cap,
-                                        IEEE80211_BAND_5GHZ);
-
-       sband = &priv->bands[IEEE80211_BAND_2GHZ];
-       sband->channels = channels;
-       /* OFDM & CCK */
-       sband->bitrates = rates;
-       sband->n_bitrates = IWL_RATE_COUNT_LEGACY;
-
-       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-               iwl_init_ht_hw_capab(priv, &sband->ht_cap,
-                                        IEEE80211_BAND_2GHZ);
-
-       priv->ieee_channels = channels;
-       priv->ieee_rates = rates;
-
-       for (i = 0;  i < priv->channel_count; i++) {
-               ch = &priv->channel_info[i];
-
-               /* FIXME: might be removed if scan is OK */
-               if (!is_channel_valid(ch))
-                       continue;
-
-               sband =  &priv->bands[ch->band];
-
-               geo_ch = &sband->channels[sband->n_channels++];
-
-               geo_ch->center_freq =
-                       ieee80211_channel_to_frequency(ch->channel, ch->band);
-               geo_ch->max_power = ch->max_power_avg;
-               geo_ch->max_antenna_gain = 0xff;
-               geo_ch->hw_value = ch->channel;
-
-               if (is_channel_valid(ch)) {
-                       if (!(ch->flags & EEPROM_CHANNEL_IBSS))
-                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
-
-                       if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-
-                       if (ch->flags & EEPROM_CHANNEL_RADAR)
-                               geo_ch->flags |= IEEE80211_CHAN_RADAR;
-
-                       geo_ch->flags |= ch->ht40_extension_channel;
-
-                       if (ch->max_power_avg > max_tx_power)
-                               max_tx_power = ch->max_power_avg;
-               } else {
-                       geo_ch->flags |= IEEE80211_CHAN_DISABLED;
-               }
-
-               IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
-                               ch->channel, geo_ch->center_freq,
-                               is_channel_a_band(ch) ?  "5.2" : "2.4",
-                               geo_ch->flags & IEEE80211_CHAN_DISABLED ?
-                               "restricted" : "valid",
-                                geo_ch->flags);
-       }
-
-       priv->tx_power_device_lmt = max_tx_power;
-       priv->tx_power_user_lmt = max_tx_power;
-       priv->tx_power_next = max_tx_power;
-
-       if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
-            priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) {
-               IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
-                       "Please send your %s to maintainer.\n",
-                       priv->trans->hw_id_str);
-               priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
-       }
-
-       if (iwlwifi_mod_params.disable_5ghz)
-               priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0;
-
-       IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
-                  priv->bands[IEEE80211_BAND_2GHZ].n_channels,
-                  priv->bands[IEEE80211_BAND_5GHZ].n_channels);
-
-       set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-
-       return 0;
-}
-
-/*
- * iwl_free_geos - undo allocations in iwl_init_geos
- */
-static void iwl_free_geos(struct iwl_priv *priv)
-{
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
-       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
-}
-
-int iwl_init_drv(struct iwl_priv *priv)
-{
-       int ret;
-
-       spin_lock_init(&priv->sta_lock);
-
-       mutex_init(&priv->mutex);
-
-       INIT_LIST_HEAD(&priv->calib_results);
-
-       priv->ieee_channels = NULL;
-       priv->ieee_rates = NULL;
-       priv->band = IEEE80211_BAND_2GHZ;
-
-       priv->plcp_delta_threshold =
-               priv->cfg->base_params->plcp_delta_threshold;
-
-       priv->iw_mode = NL80211_IFTYPE_STATION;
-       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
-       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
-       priv->agg_tids_count = 0;
-
-       priv->ucode_owner = IWL_OWNERSHIP_DRIVER;
-
-       priv->rx_statistics_jiffies = jiffies;
-
-       /* Choose which receivers/antennas to use */
-       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
-
-       iwl_init_scan_params(priv);
-
-       /* init bt coex */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
-               priv->bt_duration = BT_DURATION_LIMIT_DEF;
-               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
-       }
-
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = iwl_init_geos(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
-               goto err_free_channel_map;
-       }
-       iwl_init_hw_rates(priv->ieee_rates);
-
-       return 0;
-
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
-}
-
-void iwl_uninit_drv(struct iwl_priv *priv)
-{
-       iwl_free_geos(priv);
-       iwl_free_channel_map(priv);
-       kfree(priv->scan_cmd);
-       kfree(priv->beacon_cmd);
-       kfree(rcu_dereference_raw(priv->noa_data));
-       iwl_calib_free_results(priv);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       kfree(priv->wowlan_sram);
-#endif
-}
-
-void iwl_set_hw_params(struct iwl_priv *priv)
-{
-       if (priv->cfg->ht_params)
-               priv->hw_params.use_rts_for_aggregation =
-                       priv->cfg->ht_params->use_rts_for_aggregation;
-
-       if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
-               priv->hw_params.sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
-
-       /* Device-specific setup */
-       priv->lib->set_hw_params(priv);
-}
-
-
-
-/* show what optional capabilities we have */
-void iwl_option_config(struct iwl_priv *priv)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n");
-#else
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n");
-#else
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n");
-#else
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n");
-#else
-       IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n");
-#endif
-
-#ifdef CONFIG_IWLWIFI_P2P
-       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n");
-#else
-       IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n");
-#endif
-}
-
-static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
-                                                const struct iwl_cfg *cfg,
-                                                const struct iwl_fw *fw)
-{
-       struct iwl_priv *priv;
-       struct ieee80211_hw *hw;
-       struct iwl_op_mode *op_mode;
-       u16 num_mac;
-       u32 ucode_flags;
-       struct iwl_trans_config trans_cfg;
-       static const u8 no_reclaim_cmds[] = {
-               REPLY_RX_PHY_CMD,
-               REPLY_RX,
-               REPLY_RX_MPDU_CMD,
-               REPLY_COMPRESSED_BA,
-               STATISTICS_NOTIFICATION,
-               REPLY_TX,
-       };
-       int i;
-
-       /************************
-        * 1. Allocating HW data
-        ************************/
-       hw = iwl_alloc_all();
-       if (!hw) {
-               pr_err("%s: Cannot allocate network device\n", cfg->name);
-               goto out;
-       }
-
-       op_mode = hw->priv;
-       op_mode->ops = &iwl_dvm_ops;
-       priv = IWL_OP_MODE_GET_DVM(op_mode);
-       priv->trans = trans;
-       priv->dev = trans->dev;
-       priv->cfg = cfg;
-       priv->fw = fw;
-
-       switch (priv->cfg->device_family) {
-       case IWL_DEVICE_FAMILY_1000:
-       case IWL_DEVICE_FAMILY_100:
-               priv->lib = &iwl1000_lib;
-               break;
-       case IWL_DEVICE_FAMILY_2000:
-       case IWL_DEVICE_FAMILY_105:
-               priv->lib = &iwl2000_lib;
-               break;
-       case IWL_DEVICE_FAMILY_2030:
-       case IWL_DEVICE_FAMILY_135:
-               priv->lib = &iwl2030_lib;
-               break;
-       case IWL_DEVICE_FAMILY_5000:
-               priv->lib = &iwl5000_lib;
-               break;
-       case IWL_DEVICE_FAMILY_5150:
-               priv->lib = &iwl5150_lib;
-               break;
-       case IWL_DEVICE_FAMILY_6000:
-       case IWL_DEVICE_FAMILY_6005:
-       case IWL_DEVICE_FAMILY_6000i:
-       case IWL_DEVICE_FAMILY_6050:
-       case IWL_DEVICE_FAMILY_6150:
-               priv->lib = &iwl6000_lib;
-               break;
-       case IWL_DEVICE_FAMILY_6030:
-               priv->lib = &iwl6030_lib;
-               break;
-       default:
-               break;
-       }
-
-       if (WARN_ON(!priv->lib))
-               goto out_free_hw;
-
-       /*
-        * Populate the state variables that the transport layer needs
-        * to know about.
-        */
-       trans_cfg.op_mode = op_mode;
-       trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
-       trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
-       trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
-       if (!iwlwifi_mod_params.wd_disable)
-               trans_cfg.queue_watchdog_timeout =
-                       priv->cfg->base_params->wd_timeout;
-       else
-               trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;
-       trans_cfg.command_names = iwl_dvm_cmd_strings;
-
-       ucode_flags = fw->ucode_capa.flags;
-
-#ifndef CONFIG_IWLWIFI_P2P
-       ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-#endif
-
-       if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) {
-               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
-               trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
-               trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
-               trans_cfg.n_queue_to_fifo =
-                       ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo);
-       } else {
-               priv->sta_key_max_num = STA_KEY_MAX_NUM;
-               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-               trans_cfg.n_queue_to_fifo =
-                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
-       }
-
-       /* Configure transport layer */
-       iwl_trans_configure(priv->trans, &trans_cfg);
-
-       /* At this point both hw and priv are allocated. */
-
-       SET_IEEE80211_DEV(priv->hw, priv->trans->dev);
-
-       iwl_option_config(priv);
-
-       IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
-
-       /* is antenna coupling more than 35dB ? */
-       priv->bt_ant_couple_ok =
-               (iwlwifi_mod_params.ant_coupling >
-                       IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
-                       true : false;
-
-       /* enable/disable bt channel inhibition */
-       priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce;
-       IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n",
-                      (priv->bt_ch_announce) ? "On" : "Off");
-
-       /* these spin locks will be used in apm_ops.init and EEPROM access
-        * we should init now
-        */
-       spin_lock_init(&priv->statistics.lock);
-
-       /***********************
-        * 2. Read REV register
-        ***********************/
-       IWL_INFO(priv, "Detected %s, REV=0x%X\n",
-               priv->cfg->name, priv->trans->hw_rev);
-
-       if (iwl_trans_start_hw(priv->trans))
-               goto out_free_hw;
-
-       /* Read the EEPROM */
-       if (iwl_eeprom_init(priv, priv->trans->hw_rev)) {
-               IWL_ERR(priv, "Unable to init EEPROM\n");
-               goto out_free_hw;
-       }
-       /* Reset chip to save power until we load uCode during "up". */
-       iwl_trans_stop_hw(priv->trans, false);
-
-       if (iwl_eeprom_check_version(priv))
-               goto out_free_eeprom;
-
-       if (iwl_eeprom_init_hw_params(priv))
-               goto out_free_eeprom;
-
-       /* extract MAC Address */
-       iwl_eeprom_get_mac(priv, priv->addresses[0].addr);
-       IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr);
-       priv->hw->wiphy->addresses = priv->addresses;
-       priv->hw->wiphy->n_addresses = 1;
-       num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS);
-       if (num_mac > 1) {
-               memcpy(priv->addresses[1].addr, priv->addresses[0].addr,
-                      ETH_ALEN);
-               priv->addresses[1].addr[5]++;
-               priv->hw->wiphy->n_addresses++;
-       }
-
-       /************************
-        * 4. Setup HW constants
-        ************************/
-       iwl_set_hw_params(priv);
-
-       if (!(priv->hw_params.sku & EEPROM_SKU_CAP_IPAN_ENABLE)) {
-               IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN");
-               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN;
-               /*
-                * if not PAN, then don't support P2P -- might be a uCode
-                * packaging bug or due to the eeprom check above
-                */
-               ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P;
-               priv->sta_key_max_num = STA_KEY_MAX_NUM;
-               trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-               trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-               trans_cfg.n_queue_to_fifo =
-                       ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo);
-
-               /* Configure transport layer again*/
-               iwl_trans_configure(priv->trans, &trans_cfg);
-       }
-
-       /*******************
-        * 5. Setup priv
-        *******************/
-       for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
-               priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-               if (i < IWLAGN_FIRST_AMPDU_QUEUE &&
-                   i != IWL_DEFAULT_CMD_QUEUE_NUM &&
-                   i != IWL_IPAN_CMD_QUEUE_NUM)
-                       priv->queue_to_mac80211[i] = i;
-               atomic_set(&priv->queue_stop_count[i], 0);
-       }
-
-       WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] !=
-                                               IWLAGN_CMD_FIFO_NUM);
-
-       if (iwl_init_drv(priv))
-               goto out_free_eeprom;
-
-       /* At this point both hw and priv are initialized. */
-
-       /********************
-        * 6. Setup services
-        ********************/
-       iwl_setup_deferred_work(priv);
-       iwl_setup_rx_handlers(priv);
-       iwl_testmode_init(priv);
-
-       iwl_power_initialize(priv);
-       iwl_tt_initialize(priv);
-
-       snprintf(priv->hw->wiphy->fw_version,
-                sizeof(priv->hw->wiphy->fw_version),
-                "%s", fw->fw_version);
-
-       priv->new_scan_threshold_behaviour =
-               !!(ucode_flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
-
-       priv->phy_calib_chain_noise_reset_cmd =
-               fw->ucode_capa.standard_phy_calibration_size;
-       priv->phy_calib_chain_noise_gain_cmd =
-               fw->ucode_capa.standard_phy_calibration_size + 1;
-
-       /* initialize all valid contexts */
-       iwl_init_context(priv, ucode_flags);
-
-       /**************************************************
-        * This is still part of probe() in a sense...
-        *
-        * 7. Setup and register with mac80211 and debugfs
-        **************************************************/
-       if (iwlagn_mac_setup_register(priv, &fw->ucode_capa))
-               goto out_destroy_workqueue;
-
-       if (iwl_dbgfs_register(priv, DRV_NAME))
-               IWL_ERR(priv,
-                       "failed to create debugfs files. Ignoring error\n");
-
-       return op_mode;
-
-out_destroy_workqueue:
-       destroy_workqueue(priv->workqueue);
-       priv->workqueue = NULL;
-       iwl_uninit_drv(priv);
-out_free_eeprom:
-       iwl_eeprom_free(priv);
-out_free_hw:
-       ieee80211_free_hw(priv->hw);
-out:
-       op_mode = NULL;
-       return op_mode;
-}
-
-void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
-
-       iwl_dbgfs_unregister(priv);
-
-       iwl_testmode_cleanup(priv);
-       iwlagn_mac_unregister(priv);
-
-       iwl_tt_exit(priv);
-
-       /*This will stop the queues, move the device to low power state */
-       priv->ucode_loaded = false;
-       iwl_trans_stop_device(priv->trans);
-
-       iwl_eeprom_free(priv);
-
-       /*netif_stop_queue(dev); */
-       flush_workqueue(priv->workqueue);
-
-       /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes
-        * priv->workqueue... so we can't take down the workqueue
-        * until now... */
-       destroy_workqueue(priv->workqueue);
-       priv->workqueue = NULL;
-
-       iwl_uninit_drv(priv);
-
-       dev_kfree_skb(priv->beacon_skb);
-
-       iwl_trans_stop_hw(priv->trans, true);
-       ieee80211_free_hw(priv->hw);
-}
-
-static const char * const desc_lookup_text[] = {
-       "OK",
-       "FAIL",
-       "BAD_PARAM",
-       "BAD_CHECKSUM",
-       "NMI_INTERRUPT_WDG",
-       "SYSASSERT",
-       "FATAL_ERROR",
-       "BAD_COMMAND",
-       "HW_ERROR_TUNE_LOCK",
-       "HW_ERROR_TEMPERATURE",
-       "ILLEGAL_CHAN_FREQ",
-       "VCC_NOT_STABLE",
-       "FH_ERROR",
-       "NMI_INTERRUPT_HOST",
-       "NMI_INTERRUPT_ACTION_PT",
-       "NMI_INTERRUPT_UNKNOWN",
-       "UCODE_VERSION_MISMATCH",
-       "HW_ERROR_ABS_LOCK",
-       "HW_ERROR_CAL_LOCK_FAIL",
-       "NMI_INTERRUPT_INST_ACTION_PT",
-       "NMI_INTERRUPT_DATA_ACTION_PT",
-       "NMI_TRM_HW_ER",
-       "NMI_INTERRUPT_TRM",
-       "NMI_INTERRUPT_BREAK_POINT",
-       "DEBUG_0",
-       "DEBUG_1",
-       "DEBUG_2",
-       "DEBUG_3",
-};
-
-static struct { char *name; u8 num; } advanced_lookup[] = {
-       { "NMI_INTERRUPT_WDG", 0x34 },
-       { "SYSASSERT", 0x35 },
-       { "UCODE_VERSION_MISMATCH", 0x37 },
-       { "BAD_COMMAND", 0x38 },
-       { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
-       { "FATAL_ERROR", 0x3D },
-       { "NMI_TRM_HW_ERR", 0x46 },
-       { "NMI_INTERRUPT_TRM", 0x4C },
-       { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
-       { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
-       { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
-       { "NMI_INTERRUPT_HOST", 0x66 },
-       { "NMI_INTERRUPT_ACTION_PT", 0x7C },
-       { "NMI_INTERRUPT_UNKNOWN", 0x84 },
-       { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
-       { "ADVANCED_SYSASSERT", 0 },
-};
-
-static const char *desc_lookup(u32 num)
-{
-       int i;
-       int max = ARRAY_SIZE(desc_lookup_text);
-
-       if (num < max)
-               return desc_lookup_text[num];
-
-       max = ARRAY_SIZE(advanced_lookup) - 1;
-       for (i = 0; i < max; i++) {
-               if (advanced_lookup[i].num == num)
-                       break;
-       }
-       return advanced_lookup[i].name;
-}
-
-#define ERROR_START_OFFSET  (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
-
-static void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
-       struct iwl_trans *trans = priv->trans;
-       u32 base;
-       struct iwl_error_event_table table;
-
-       base = priv->device_pointers.error_event_table;
-       if (priv->cur_ucode == IWL_UCODE_INIT) {
-               if (!base)
-                       base = priv->fw->init_errlog_ptr;
-       } else {
-               if (!base)
-                       base = priv->fw->inst_errlog_ptr;
-       }
-
-       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv,
-                       "Not valid error log pointer 0x%08X for %s uCode\n",
-                       base,
-                       (priv->cur_ucode == IWL_UCODE_INIT)
-                                       ? "Init" : "RT");
-               return;
-       }
-
-       /*TODO: Update dbgfs with ISR error stats obtained below */
-       iwl_read_targ_mem_words(trans, base, &table, sizeof(table));
-
-       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
-               IWL_ERR(trans, "Start IWL Error Log Dump:\n");
-               IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
-                       priv->status, table.valid);
-       }
-
-       trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low,
-                                     table.data1, table.data2, table.line,
-                                     table.blink1, table.blink2, table.ilink1,
-                                     table.ilink2, table.bcon_time, table.gp1,
-                                     table.gp2, table.gp3, table.ucode_ver,
-                                     table.hw_ver, table.brd_ver);
-       IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
-               desc_lookup(table.error_id));
-       IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
-       IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
-       IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
-       IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
-       IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
-       IWL_ERR(priv, "0x%08X | data1\n", table.data1);
-       IWL_ERR(priv, "0x%08X | data2\n", table.data2);
-       IWL_ERR(priv, "0x%08X | line\n", table.line);
-       IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
-       IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
-       IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
-       IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
-       IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
-       IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
-       IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
-       IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
-       IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
-       IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
-       IWL_ERR(priv, "0x%08X | isr0\n", table.isr0);
-       IWL_ERR(priv, "0x%08X | isr1\n", table.isr1);
-       IWL_ERR(priv, "0x%08X | isr2\n", table.isr2);
-       IWL_ERR(priv, "0x%08X | isr3\n", table.isr3);
-       IWL_ERR(priv, "0x%08X | isr4\n", table.isr4);
-       IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref);
-       IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event);
-       IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control);
-       IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration);
-       IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
-       IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
-       IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
-       IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp);
-       IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler);
-}
-
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                              u32 num_events, u32 mode,
-                              int pos, char **buf, size_t bufsz)
-{
-       u32 i;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
-       u32 ptr;        /* SRAM byte address of log data */
-       u32 ev, time, data; /* event log data */
-       unsigned long reg_flags;
-
-       struct iwl_trans *trans = priv->trans;
-
-       if (num_events == 0)
-               return pos;
-
-       base = priv->device_pointers.log_event_table;
-       if (priv->cur_ucode == IWL_UCODE_INIT) {
-               if (!base)
-                       base = priv->fw->init_evtlog_ptr;
-       } else {
-               if (!base)
-                       base = priv->fw->inst_evtlog_ptr;
-       }
-
-       if (mode == 0)
-               event_size = 2 * sizeof(u32);
-       else
-               event_size = 3 * sizeof(u32);
-
-       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-       /* Make sure device is powered up for SRAM reads */
-       spin_lock_irqsave(&trans->reg_lock, reg_flags);
-       if (unlikely(!iwl_grab_nic_access(trans)))
-               goto out_unlock;
-
-       /* Set starting address; reads will auto-increment */
-       iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr);
-
-       /* "time" is actually "data" for mode 0 (no timestamp).
-       * place event id # at far right for easier visual parsing. */
-       for (i = 0; i < num_events; i++) {
-               ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-               time = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-               if (mode == 0) {
-                       /* data, ev */
-                       if (bufsz) {
-                               pos += scnprintf(*buf + pos, bufsz - pos,
-                                               "EVT_LOG:0x%08x:%04u\n",
-                                               time, ev);
-                       } else {
-                               trace_iwlwifi_dev_ucode_event(trans->dev, 0,
-                                       time, ev);
-                               IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
-                                       time, ev);
-                       }
-               } else {
-                       data = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
-                       if (bufsz) {
-                               pos += scnprintf(*buf + pos, bufsz - pos,
-                                               "EVT_LOGT:%010u:0x%08x:%04u\n",
-                                                time, data, ev);
-                       } else {
-                               IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
-                                       time, data, ev);
-                               trace_iwlwifi_dev_ucode_event(trans->dev, time,
-                                       data, ev);
-                       }
-               }
-       }
-
-       /* Allow device to power down */
-       iwl_release_nic_access(trans);
-out_unlock:
-       spin_unlock_irqrestore(&trans->reg_lock, reg_flags);
-       return pos;
-}
-
-/**
- * iwl_print_last_event_logs - Dump the newest # of event log to syslog
- */
-static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
-                                   u32 num_wraps, u32 next_entry,
-                                   u32 size, u32 mode,
-                                   int pos, char **buf, size_t bufsz)
-{
-       /*
-        * display the newest DEFAULT_LOG_ENTRIES entries
-        * i.e the entries just before the next ont that uCode would fill.
-        */
-       if (num_wraps) {
-               if (next_entry < size) {
-                       pos = iwl_print_event_log(priv,
-                                               capacity - (size - next_entry),
-                                               size - next_entry, mode,
-                                               pos, buf, bufsz);
-                       pos = iwl_print_event_log(priv, 0,
-                                                 next_entry, mode,
-                                                 pos, buf, bufsz);
-               } else
-                       pos = iwl_print_event_log(priv, next_entry - size,
-                                                 size, mode, pos, buf, bufsz);
-       } else {
-               if (next_entry < size) {
-                       pos = iwl_print_event_log(priv, 0, next_entry,
-                                                 mode, pos, buf, bufsz);
-               } else {
-                       pos = iwl_print_event_log(priv, next_entry - size,
-                                                 size, mode, pos, buf, bufsz);
-               }
-       }
-       return pos;
-}
-
-#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
-
-int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
-                           char **buf, bool display)
-{
-       u32 base;       /* SRAM byte address of event log header */
-       u32 capacity;   /* event log capacity in # entries */
-       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-       u32 num_wraps;  /* # times uCode wrapped to top of log */
-       u32 next_entry; /* index of next entry to be written by uCode */
-       u32 size;       /* # entries that we'll print */
-       u32 logsize;
-       int pos = 0;
-       size_t bufsz = 0;
-       struct iwl_trans *trans = priv->trans;
-
-       base = priv->device_pointers.log_event_table;
-       if (priv->cur_ucode == IWL_UCODE_INIT) {
-               logsize = priv->fw->init_evtlog_size;
-               if (!base)
-                       base = priv->fw->init_evtlog_ptr;
-       } else {
-               logsize = priv->fw->inst_evtlog_size;
-               if (!base)
-                       base = priv->fw->inst_evtlog_ptr;
-       }
-
-       if (!iwlagn_hw_valid_rtc_data_addr(base)) {
-               IWL_ERR(priv,
-                       "Invalid event log pointer 0x%08X for %s uCode\n",
-                       base,
-                       (priv->cur_ucode == IWL_UCODE_INIT)
-                                       ? "Init" : "RT");
-               return -EINVAL;
-       }
-
-       /* event log header */
-       capacity = iwl_read_targ_mem(trans, base);
-       mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32)));
-       num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32)));
-       next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32)));
-
-       if (capacity > logsize) {
-               IWL_ERR(priv, "Log capacity %d is bogus, limit to %d "
-                       "entries\n", capacity, logsize);
-               capacity = logsize;
-       }
-
-       if (next_entry > logsize) {
-               IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, logsize);
-               next_entry = logsize;
-       }
-
-       size = num_wraps ? capacity : next_entry;
-
-       /* bail out if nothing in log */
-       if (size == 0) {
-               IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n");
-               return pos;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log)
-               size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
-                       ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#else
-       size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
-               ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
-#endif
-       IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
-               size);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (display) {
-               if (full_log)
-                       bufsz = capacity * 48;
-               else
-                       bufsz = size * 48;
-               *buf = kmalloc(bufsz, GFP_KERNEL);
-               if (!*buf)
-                       return -ENOMEM;
-       }
-       if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) {
-               /*
-                * if uCode has wrapped back to top of log,
-                * start at the oldest entry,
-                * i.e the next one that uCode would fill.
-                */
-               if (num_wraps)
-                       pos = iwl_print_event_log(priv, next_entry,
-                                               capacity - next_entry, mode,
-                                               pos, buf, bufsz);
-               /* (then/else) start at top of log */
-               pos = iwl_print_event_log(priv, 0,
-                                         next_entry, mode, pos, buf, bufsz);
-       } else
-               pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
-                                               next_entry, size, mode,
-                                               pos, buf, bufsz);
-#else
-       pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode,
-                                       pos, buf, bufsz);
-#endif
-       return pos;
-}
-
-static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
-{
-       unsigned int reload_msec;
-       unsigned long reload_jiffies;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
-               iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
-#endif
-
-       /* uCode is no longer loaded. */
-       priv->ucode_loaded = false;
-
-       /* Set the FW error flag -- cleared on iwl_down */
-       set_bit(STATUS_FW_ERROR, &priv->status);
-
-       iwl_abort_notification_waits(&priv->notif_wait);
-
-       /* Keep the restart process from trying to send host
-        * commands by clearing the ready bit */
-       clear_bit(STATUS_READY, &priv->status);
-
-       wake_up(&priv->trans->wait_command_queue);
-
-       if (!ondemand) {
-               /*
-                * If firmware keep reloading, then it indicate something
-                * serious wrong and firmware having problem to recover
-                * from it. Instead of keep trying which will fill the syslog
-                * and hang the system, let's just stop it
-                */
-               reload_jiffies = jiffies;
-               reload_msec = jiffies_to_msecs((long) reload_jiffies -
-                                       (long) priv->reload_jiffies);
-               priv->reload_jiffies = reload_jiffies;
-               if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
-                       priv->reload_count++;
-                       if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
-                               IWL_ERR(priv, "BUG_ON, Stop restarting\n");
-                               return;
-                       }
-               } else
-                       priv->reload_count = 0;
-       }
-
-       if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               if (iwlwifi_mod_params.restart_fw) {
-                       IWL_DEBUG_FW_ERRORS(priv,
-                                 "Restarting adapter due to uCode error.\n");
-                       queue_work(priv->workqueue, &priv->restart);
-               } else
-                       IWL_DEBUG_FW_ERRORS(priv,
-                                 "Detected FW error, but not restarting\n");
-       }
-}
-
-void iwl_nic_error(struct iwl_op_mode *op_mode)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       IWL_ERR(priv, "Loaded firmware version: %s\n",
-               priv->fw->fw_version);
-
-       iwl_dump_nic_error_log(priv);
-       iwl_dump_nic_event_log(priv, false, NULL, false);
-
-       iwlagn_fw_error(priv, false);
-}
-
-void iwl_cmd_queue_full(struct iwl_op_mode *op_mode)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       if (!iwl_check_for_ct_kill(priv)) {
-               IWL_ERR(priv, "Restarting adapter queue is full\n");
-               iwlagn_fw_error(priv, false);
-       }
-}
-
-void iwl_nic_config(struct iwl_op_mode *op_mode)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       priv->lib->nic_config(priv);
-}
-
-static void iwl_wimax_active(struct iwl_op_mode *op_mode)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       clear_bit(STATUS_READY, &priv->status);
-       IWL_ERR(priv, "RF is used by WiMAX\n");
-}
-
-void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-       int mq = priv->queue_to_mac80211[queue];
-
-       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
-               return;
-
-       if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) {
-               IWL_DEBUG_TX_QUEUES(priv,
-                       "queue %d (mac80211 %d) already stopped\n",
-                       queue, mq);
-               return;
-       }
-
-       set_bit(mq, &priv->transport_queue_stop);
-       ieee80211_stop_queue(priv->hw, mq);
-}
-
-void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-       int mq = priv->queue_to_mac80211[queue];
-
-       if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
-               return;
-
-       if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) {
-               IWL_DEBUG_TX_QUEUES(priv,
-                       "queue %d (mac80211 %d) already awake\n",
-                       queue, mq);
-               return;
-       }
-
-       clear_bit(mq, &priv->transport_queue_stop);
-
-       if (!priv->passive_no_rx)
-               ieee80211_wake_queue(priv->hw, mq);
-}
-
-void iwlagn_lift_passive_no_rx(struct iwl_priv *priv)
-{
-       int mq;
-
-       if (!priv->passive_no_rx)
-               return;
-
-       for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) {
-               if (!test_bit(mq, &priv->transport_queue_stop)) {
-                       IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq);
-                       ieee80211_wake_queue(priv->hw, mq);
-               } else {
-                       IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq);
-               }
-       }
-
-       priv->passive_no_rx = false;
-}
-
-void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *info;
-
-       info = IEEE80211_SKB_CB(skb);
-       kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1]));
-       dev_kfree_skb_any(skb);
-}
-
-void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
-{
-       struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
-
-       if (state)
-               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, state);
-}
-
-const struct iwl_op_mode_ops iwl_dvm_ops = {
-       .start = iwl_op_mode_dvm_start,
-       .stop = iwl_op_mode_dvm_stop,
-       .rx = iwl_rx_dispatch,
-       .queue_full = iwl_stop_sw_queue,
-       .queue_not_full = iwl_wake_sw_queue,
-       .hw_rf_kill = iwl_set_hw_rfkill_state,
-       .free_skb = iwl_free_skb,
-       .nic_error = iwl_nic_error,
-       .cmd_queue_full = iwl_cmd_queue_full,
-       .nic_config = iwl_nic_config,
-       .wimax_active = iwl_wimax_active,
-};
-
-/*****************************************************************************
- *
- * driver and module entry point
- *
- *****************************************************************************/
-
-struct kmem_cache *iwl_tx_cmd_pool;
-
-static int __init iwl_init(void)
-{
-
-       int ret;
-       pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
-       pr_info(DRV_COPYRIGHT "\n");
-
-       iwl_tx_cmd_pool = kmem_cache_create("iwl_dev_cmd",
-                                           sizeof(struct iwl_device_cmd),
-                                           sizeof(void *), 0, NULL);
-       if (!iwl_tx_cmd_pool)
-               return -ENOMEM;
-
-       ret = iwlagn_rate_control_register();
-       if (ret) {
-               pr_err("Unable to register rate control algorithm: %d\n", ret);
-               goto error_rc_register;
-       }
-
-       ret = iwl_pci_register_driver();
-       if (ret)
-               goto error_pci_register;
-       return ret;
-
-error_pci_register:
-       iwlagn_rate_control_unregister();
-error_rc_register:
-       kmem_cache_destroy(iwl_tx_cmd_pool);
-       return ret;
-}
-
-static void __exit iwl_exit(void)
-{
-       iwl_pci_unregister_driver();
-       iwlagn_rate_control_unregister();
-       kmem_cache_destroy(iwl_tx_cmd_pool);
-}
-
-module_exit(iwl_exit);
-module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
deleted file mode 100644 (file)
index 79c0fe0..0000000
+++ /dev/null
@@ -1,602 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_agn_h__
-#define __iwl_agn_h__
-
-#include "iwl-dev.h"
-#include "iwl-config.h"
-
-/* The first 11 queues (0-10) are used otherwise */
-#define IWLAGN_FIRST_AMPDU_QUEUE       11
-
-/* AUX (TX during scan dwell) queue */
-#define IWL_AUX_QUEUE          10
-
-/* device operations */
-extern struct iwl_lib_ops iwl1000_lib;
-extern struct iwl_lib_ops iwl2000_lib;
-extern struct iwl_lib_ops iwl2030_lib;
-extern struct iwl_lib_ops iwl5000_lib;
-extern struct iwl_lib_ops iwl5150_lib;
-extern struct iwl_lib_ops iwl6000_lib;
-extern struct iwl_lib_ops iwl6030_lib;
-
-
-#define TIME_UNIT              1024
-
-/*****************************************************
-* DRIVER STATUS FUNCTIONS
-******************************************************/
-#define STATUS_RF_KILL_HW      0
-#define STATUS_CT_KILL         1
-#define STATUS_ALIVE           2
-#define STATUS_READY           3
-#define STATUS_GEO_CONFIGURED  4
-#define STATUS_EXIT_PENDING    5
-#define STATUS_STATISTICS      6
-#define STATUS_SCANNING                7
-#define STATUS_SCAN_ABORTING   8
-#define STATUS_SCAN_HW         9
-#define STATUS_FW_ERROR                10
-#define STATUS_CHANNEL_SWITCH_PENDING 11
-#define STATUS_SCAN_COMPLETE   12
-#define STATUS_POWER_PMI       13
-
-struct iwl_ucode_capabilities;
-
-extern struct ieee80211_ops iwlagn_hw_ops;
-
-static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
-{
-       hdr->op_code = cmd;
-       hdr->first_group = 0;
-       hdr->groups_num = 1;
-       hdr->data_valid = 1;
-}
-
-void iwl_down(struct iwl_priv *priv);
-void iwl_cancel_deferred_work(struct iwl_priv *priv);
-void iwlagn_prepare_restart(struct iwl_priv *priv);
-int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode,
-                                struct iwl_rx_cmd_buffer *rxb,
-                                struct iwl_device_cmd *cmd);
-
-bool iwl_check_for_ct_kill(struct iwl_priv *priv);
-
-void iwlagn_lift_passive_no_rx(struct iwl_priv *priv);
-
-/* MAC80211 */
-struct ieee80211_hw *iwl_alloc_all(void);
-int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                             const struct iwl_ucode_capabilities *capa);
-void iwlagn_mac_unregister(struct iwl_priv *priv);
-
-/* commands */
-int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id,
-                        u32 flags, u16 len, const void *data);
-
-/* RXON */
-void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct iwl_rxon_context *ctx);
-int iwlagn_set_pan_params(struct iwl_priv *priv);
-int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_bss_conf *bss_conf,
-                            u32 changes);
-void iwlagn_config_ht40(struct ieee80211_conf *conf,
-                       struct iwl_rxon_context *ctx);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
-void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
-                        struct iwl_rxon_context *ctx);
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           enum ieee80211_band band,
-                           struct ieee80211_vif *vif);
-
-/* uCode */
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
-void iwl_send_prio_tbl(struct iwl_priv *priv);
-int iwl_init_alive_start(struct iwl_priv *priv);
-int iwl_run_init_ucode(struct iwl_priv *priv);
-int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
-                             enum iwl_ucode_type ucode_type);
-int iwl_send_calib_results(struct iwl_priv *priv);
-int iwl_calib_set(struct iwl_priv *priv,
-                 const struct iwl_calib_hdr *cmd, int len);
-void iwl_calib_free_results(struct iwl_priv *priv);
-int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
-                           char **buf, bool display);
-int iwlagn_hw_valid_rtc_data_addr(u32 addr);
-
-/* lib */
-int iwlagn_send_tx_power(struct iwl_priv *priv);
-void iwlagn_temperature(struct iwl_priv *priv);
-int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
-void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
-int iwl_send_statistics_request(struct iwl_priv *priv,
-                               u8 flags, bool clear);
-
-static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
-                       struct iwl_priv *priv, enum ieee80211_band band)
-{
-       return priv->hw->wiphy->bands[band];
-}
-
-#ifdef CONFIG_PM_SLEEP
-int iwlagn_send_patterns(struct iwl_priv *priv,
-                        struct cfg80211_wowlan *wowlan);
-int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan);
-#endif
-
-/* rx */
-int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
-void iwl_setup_rx_handlers(struct iwl_priv *priv);
-void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
-
-
-/* tx */
-int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid, u8 buf_size);
-int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta, u16 tid);
-int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                  struct iwl_rx_cmd_buffer *rxb,
-                                  struct iwl_device_cmd *cmd);
-int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd);
-
-static inline u32 iwl_tx_status_to_mac80211(u32 status)
-{
-       status &= TX_STATUS_MSK;
-
-       switch (status) {
-       case TX_STATUS_SUCCESS:
-       case TX_STATUS_DIRECT_DONE:
-               return IEEE80211_TX_STAT_ACK;
-       case TX_STATUS_FAIL_DEST_PS:
-       case TX_STATUS_FAIL_PASSIVE_NO_RX:
-               return IEEE80211_TX_STAT_TX_FILTERED;
-       default:
-               return 0;
-       }
-}
-
-static inline bool iwl_is_tx_success(u32 status)
-{
-       status &= TX_STATUS_MSK;
-       return (status == TX_STATUS_SUCCESS) ||
-              (status == TX_STATUS_DIRECT_DONE);
-}
-
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
-
-/* scan */
-void iwlagn_post_scan(struct iwl_priv *priv);
-void iwlagn_disable_roc(struct iwl_priv *priv);
-int iwl_force_rf_reset(struct iwl_priv *priv, bool external);
-void iwl_init_scan_params(struct iwl_priv *priv);
-int iwl_scan_cancel(struct iwl_priv *priv);
-void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-void iwl_force_scan_end(struct iwl_priv *priv);
-void iwl_internal_short_hw_scan(struct iwl_priv *priv);
-void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
-void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
-int __must_check iwl_scan_initiate(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif,
-                                  enum iwl_scan_type scan_type,
-                                  enum ieee80211_band band);
-
-/* For faster active scanning, scan will move to the next channel if fewer than
- * PLCP_QUIET_THRESH packets are heard on this channel within
- * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
- * time if it's a quiet channel (nothing responded to our probe, and there's
- * no other traffic).
- * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
-#define IWL_ACTIVE_QUIET_TIME       cpu_to_le16(10)  /* msec */
-#define IWL_PLCP_QUIET_THRESH       cpu_to_le16(1)  /* packets */
-
-#define IWL_SCAN_CHECK_WATCHDOG                (HZ * 7)
-
-
-/* bt coex */
-void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
-int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_cmd_buffer *rxb,
-                                 struct iwl_device_cmd *cmd);
-void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
-void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
-void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
-void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
-void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
-
-static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
-{
-       return priv->cfg->bt_params &&
-              priv->cfg->bt_params->advanced_bt_coexist;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-const char *iwl_get_tx_fail_reason(u32 status);
-const char *iwl_get_agg_tx_fail_reason(u16 status);
-#else
-static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
-static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; }
-#endif
-
-
-/* station management */
-int iwlagn_manage_ibss_station(struct iwl_priv *priv,
-                              struct ieee80211_vif *vif, bool add);
-#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
-#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
-#define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
-                                           being activated */
-#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
-                               (this is for the IBSS BSSID stations) */
-#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
-
-
-void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwl_clear_ucode_stations(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx);
-void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
-int iwl_get_free_ucode_key_offset(struct iwl_priv *priv);
-int iwl_send_add_sta(struct iwl_priv *priv,
-                    struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                          const u8 *addr, bool is_ap,
-                          struct ieee80211_sta *sta, u8 *sta_id_r);
-int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
-                      const u8 *addr);
-void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
-                           const u8 *addr);
-u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                   const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
-
-int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                   struct iwl_link_quality_cmd *lq, u8 flags, bool init);
-int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
-                              struct iwl_device_cmd *cmd);
-int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                     struct ieee80211_sta *sta);
-
-bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           struct ieee80211_sta_ht_cap *ht_cap);
-
-static inline int iwl_sta_id(struct ieee80211_sta *sta)
-{
-       if (WARN_ON(!sta))
-               return IWL_INVALID_STATION;
-
-       return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
-}
-
-int iwlagn_alloc_bcast_station(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx);
-int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                            const u8 *addr, u8 *sta_id_r);
-int iwl_remove_default_wep_key(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx,
-                              struct ieee80211_key_conf *key);
-int iwl_set_default_wep_key(struct iwl_priv *priv,
-                           struct iwl_rxon_context *ctx,
-                           struct ieee80211_key_conf *key);
-int iwl_restore_default_wep_keys(struct iwl_priv *priv,
-                                struct iwl_rxon_context *ctx);
-int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                       struct ieee80211_key_conf *key,
-                       struct ieee80211_sta *sta);
-int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
-                          struct ieee80211_key_conf *key,
-                          struct ieee80211_sta *sta);
-void iwl_update_tkip_key(struct iwl_priv *priv,
-                        struct ieee80211_vif *vif,
-                        struct ieee80211_key_conf *keyconf,
-                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
-int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
-int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
-                        int tid, u16 ssn);
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
-                       int tid);
-void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
-int iwl_update_bcast_station(struct iwl_priv *priv,
-                            struct iwl_rxon_context *ctx);
-int iwl_update_bcast_stations(struct iwl_priv *priv);
-
-/* rate */
-static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
-{
-       return BIT(ant_idx) << RATE_MCS_ANT_POS;
-}
-
-static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
-{
-       return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
-}
-
-static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
-{
-       return cpu_to_le32(flags|(u32)rate);
-}
-
-extern int iwl_alive_start(struct iwl_priv *priv);
-/* svtool */
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data,
-                                  int len);
-extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw,
-                                   struct sk_buff *skb,
-                                   struct netlink_callback *cb,
-                                   void *data, int len);
-extern void iwl_testmode_init(struct iwl_priv *priv);
-extern void iwl_testmode_cleanup(struct iwl_priv *priv);
-#else
-static inline
-int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
-{
-       return -ENOSYS;
-}
-static inline
-int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     struct netlink_callback *cb,
-                     void *data, int len)
-{
-       return -ENOSYS;
-}
-static inline
-void iwl_testmode_init(struct iwl_priv *priv)
-{
-}
-static inline
-void iwl_testmode_cleanup(struct iwl_priv *priv)
-{
-}
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-                            enum iwl_rxon_context_id ctxid);
-#else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
-                                          enum iwl_rxon_context_id ctxid)
-{
-}
-#endif
-
-/* status checks */
-
-static inline int iwl_is_ready(struct iwl_priv *priv)
-{
-       /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
-        * set but EXIT_PENDING is not */
-       return test_bit(STATUS_READY, &priv->status) &&
-              test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
-              !test_bit(STATUS_EXIT_PENDING, &priv->status);
-}
-
-static inline int iwl_is_alive(struct iwl_priv *priv)
-{
-       return test_bit(STATUS_ALIVE, &priv->status);
-}
-
-static inline int iwl_is_rfkill(struct iwl_priv *priv)
-{
-       return test_bit(STATUS_RF_KILL_HW, &priv->status);
-}
-
-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)
-{
-       if (iwl_is_rfkill(priv))
-               return 0;
-
-       return iwl_is_ready(priv);
-}
-
-static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
-{
-       if (state)
-               set_bit(STATUS_POWER_PMI, &priv->status);
-       else
-               clear_bit(STATUS_POWER_PMI, &priv->status);
-       iwl_trans_set_pmi(priv->trans, state);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
-void iwl_dbgfs_unregister(struct iwl_priv *priv);
-#else
-static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
-{
-       return 0;
-}
-static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
-}
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
-do {                                                                   \
-       if (!iwl_is_rfkill((m)))                                        \
-               IWL_ERR(m, fmt, ##args);                                \
-       else                                                            \
-               __iwl_err((m)->dev, true,                               \
-                         !iwl_have_debug_level(IWL_DL_RADIO),          \
-                         fmt, ##args);                                 \
-} while (0)
-#else
-#define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...)        \
-do {                                                                   \
-       if (!iwl_is_rfkill((m)))                                        \
-               IWL_ERR(m, fmt, ##args);                                \
-       else                                                            \
-               __iwl_err((m)->dev, true, true, fmt, ##args);   \
-} while (0)
-#endif                         /* CONFIG_IWLWIFI_DEBUG */
-
-extern const char *iwl_dvm_cmd_strings[REPLY_MAX];
-
-static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
-{
-       const char *s = iwl_dvm_cmd_strings[cmd];
-       if (s)
-               return s;
-       return "UNKNOWN";
-}
-
-/* API method exported for mvm hybrid state */
-void iwl_setup_deferred_work(struct iwl_priv *priv);
-int iwl_send_wimax_coex(struct iwl_priv *priv);
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
-void iwl_option_config(struct iwl_priv *priv);
-void iwl_set_hw_params(struct iwl_priv *priv);
-void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags);
-int iwl_init_drv(struct iwl_priv *priv);
-void iwl_uninit_drv(struct iwl_priv *priv);
-void iwl_send_bt_config(struct iwl_priv *priv);
-void iwl_rf_kill_ct_config(struct iwl_priv *priv);
-int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwl_teardown_interface(struct iwl_priv *priv,
-                           struct ieee80211_vif *vif,
-                           bool mode_change);
-int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-void iwlagn_check_needed_chains(struct iwl_priv *priv,
-                               struct iwl_rxon_context *ctx,
-                               struct ieee80211_bss_conf *bss_conf);
-void iwlagn_chain_noise_reset(struct iwl_priv *priv);
-int iwlagn_update_beacon(struct iwl_priv *priv,
-                        struct ieee80211_vif *vif);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode);
-void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue);
-void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state);
-void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
-void iwl_nic_error(struct iwl_op_mode *op_mode);
-void iwl_cmd_queue_full(struct iwl_op_mode *op_mode);
-void iwl_nic_config(struct iwl_op_mode *op_mode);
-int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-                      struct ieee80211_sta *sta, bool set);
-void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-                             enum ieee80211_rssi_event rssi_event);
-int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw);
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
-void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue);
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-                              struct ieee80211_channel_switch *ch_switch);
-int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
-                        struct ieee80211_vif *vif,
-                        struct ieee80211_sta *sta,
-                        enum ieee80211_sta_state old_state,
-                        enum ieee80211_sta_state new_state);
-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-                           struct ieee80211_vif *vif,
-                           enum ieee80211_ampdu_mlme_action action,
-                           struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                           u8 buf_size);
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif,
-                      struct cfg80211_scan_request *req);
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta);
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-                            unsigned int changed_flags,
-                            unsigned int *total_flags,
-                            u64 multicast);
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif, u16 queue,
-                      const struct ieee80211_tx_queue_params *params);
-void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct cfg80211_gtk_rekey_data *data);
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_key_conf *keyconf,
-                               struct ieee80211_sta *sta,
-                               u32 iv32, u16 *phase1key);
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-                      struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta,
-                      struct ieee80211_key_conf *key);
-void iwlagn_mac_stop(struct ieee80211_hw *hw);
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
-#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-cfg.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h
deleted file mode 100644 (file)
index 8215231..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_pci_h__
-#define __iwl_pci_h__
-
-
-/*
- * This file declares the config structures for all devices.
- */
-
-extern const struct iwl_cfg iwl5300_agn_cfg;
-extern const struct iwl_cfg iwl5100_agn_cfg;
-extern const struct iwl_cfg iwl5350_agn_cfg;
-extern const struct iwl_cfg iwl5100_bgn_cfg;
-extern const struct iwl_cfg iwl5100_abg_cfg;
-extern const struct iwl_cfg iwl5150_agn_cfg;
-extern const struct iwl_cfg iwl5150_abg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_cfg;
-extern const struct iwl_cfg iwl6005_2abg_cfg;
-extern const struct iwl_cfg iwl6005_2bg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
-extern const struct iwl_cfg iwl6005_2agn_d_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
-extern const struct iwl_cfg iwl1030_bgn_cfg;
-extern const struct iwl_cfg iwl1030_bg_cfg;
-extern const struct iwl_cfg iwl6030_2agn_cfg;
-extern const struct iwl_cfg iwl6030_2abg_cfg;
-extern const struct iwl_cfg iwl6030_2bgn_cfg;
-extern const struct iwl_cfg iwl6030_2bg_cfg;
-extern const struct iwl_cfg iwl6000i_2agn_cfg;
-extern const struct iwl_cfg iwl6000i_2abg_cfg;
-extern const struct iwl_cfg iwl6000i_2bg_cfg;
-extern const struct iwl_cfg iwl6000_3agn_cfg;
-extern const struct iwl_cfg iwl6050_2agn_cfg;
-extern const struct iwl_cfg iwl6050_2abg_cfg;
-extern const struct iwl_cfg iwl6150_bgn_cfg;
-extern const struct iwl_cfg iwl6150_bg_cfg;
-extern const struct iwl_cfg iwl1000_bgn_cfg;
-extern const struct iwl_cfg iwl1000_bg_cfg;
-extern const struct iwl_cfg iwl100_bgn_cfg;
-extern const struct iwl_cfg iwl100_bg_cfg;
-extern const struct iwl_cfg iwl130_bgn_cfg;
-extern const struct iwl_cfg iwl130_bg_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
-extern const struct iwl_cfg iwl2030_2bgn_cfg;
-extern const struct iwl_cfg iwl6035_2agn_cfg;
-extern const struct iwl_cfg iwl105_bgn_cfg;
-extern const struct iwl_cfg iwl105_bgn_d_cfg;
-extern const struct iwl_cfg iwl135_bgn_cfg;
-
-#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
deleted file mode 100644 (file)
index 9af6a23..0000000
+++ /dev/null
@@ -1,3961 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2005 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-commands.h) only for uCode API definitions.
- * Please use iwl-xxxx-hw.h for hardware-related definitions.
- * Please use iwl-dev.h for driver implementation definitions.
- */
-
-#ifndef __iwl_commands_h__
-#define __iwl_commands_h__
-
-#include <linux/ieee80211.h>
-#include <linux/types.h>
-
-
-enum {
-       REPLY_ALIVE = 0x1,
-       REPLY_ERROR = 0x2,
-       REPLY_ECHO = 0x3,               /* test command */
-
-       /* RXON and QOS commands */
-       REPLY_RXON = 0x10,
-       REPLY_RXON_ASSOC = 0x11,
-       REPLY_QOS_PARAM = 0x13,
-       REPLY_RXON_TIMING = 0x14,
-
-       /* Multi-Station support */
-       REPLY_ADD_STA = 0x18,
-       REPLY_REMOVE_STA = 0x19,
-       REPLY_REMOVE_ALL_STA = 0x1a,    /* not used */
-       REPLY_TXFIFO_FLUSH = 0x1e,
-
-       /* Security */
-       REPLY_WEPKEY = 0x20,
-
-       /* RX, TX, LEDs */
-       REPLY_TX = 0x1c,
-       REPLY_LEDS_CMD = 0x48,
-       REPLY_TX_LINK_QUALITY_CMD = 0x4e,
-
-       /* WiMAX coexistence */
-       COEX_PRIORITY_TABLE_CMD = 0x5a,
-       COEX_MEDIUM_NOTIFICATION = 0x5b,
-       COEX_EVENT_CMD = 0x5c,
-
-       /* Calibration */
-       TEMPERATURE_NOTIFICATION = 0x62,
-       CALIBRATION_CFG_CMD = 0x65,
-       CALIBRATION_RES_NOTIFICATION = 0x66,
-       CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
-
-       /* 802.11h related */
-       REPLY_QUIET_CMD = 0x71,         /* not used */
-       REPLY_CHANNEL_SWITCH = 0x72,
-       CHANNEL_SWITCH_NOTIFICATION = 0x73,
-       REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
-       SPECTRUM_MEASURE_NOTIFICATION = 0x75,
-
-       /* Power Management */
-       POWER_TABLE_CMD = 0x77,
-       PM_SLEEP_NOTIFICATION = 0x7A,
-       PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
-
-       /* Scan commands and notifications */
-       REPLY_SCAN_CMD = 0x80,
-       REPLY_SCAN_ABORT_CMD = 0x81,
-       SCAN_START_NOTIFICATION = 0x82,
-       SCAN_RESULTS_NOTIFICATION = 0x83,
-       SCAN_COMPLETE_NOTIFICATION = 0x84,
-
-       /* IBSS/AP commands */
-       BEACON_NOTIFICATION = 0x90,
-       REPLY_TX_BEACON = 0x91,
-       WHO_IS_AWAKE_NOTIFICATION = 0x94,       /* not used */
-
-       /* Miscellaneous commands */
-       REPLY_TX_POWER_DBM_CMD = 0x95,
-       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,
-       MEASURE_ABORT_NOTIFICATION = 0x99,      /* not used */
-
-       /* Bluetooth device coexistence config command */
-       REPLY_BT_CONFIG = 0x9b,
-
-       /* Statistics */
-       REPLY_STATISTICS_CMD = 0x9c,
-       STATISTICS_NOTIFICATION = 0x9d,
-
-       /* RF-KILL commands and notifications */
-       REPLY_CARD_STATE_CMD = 0xa0,
-       CARD_STATE_NOTIFICATION = 0xa1,
-
-       /* Missed beacons notification */
-       MISSED_BEACONS_NOTIFICATION = 0xa2,
-
-       REPLY_CT_KILL_CONFIG_CMD = 0xa4,
-       SENSITIVITY_CMD = 0xa8,
-       REPLY_PHY_CALIBRATION_CMD = 0xb0,
-       REPLY_RX_PHY_CMD = 0xc0,
-       REPLY_RX_MPDU_CMD = 0xc1,
-       REPLY_RX = 0xc3,
-       REPLY_COMPRESSED_BA = 0xc5,
-
-       /* BT Coex */
-       REPLY_BT_COEX_PRIO_TABLE = 0xcc,
-       REPLY_BT_COEX_PROT_ENV = 0xcd,
-       REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
-
-       /* PAN commands */
-       REPLY_WIPAN_PARAMS = 0xb2,
-       REPLY_WIPAN_RXON = 0xb3,        /* use REPLY_RXON structure */
-       REPLY_WIPAN_RXON_TIMING = 0xb4, /* use REPLY_RXON_TIMING structure */
-       REPLY_WIPAN_RXON_ASSOC = 0xb6,  /* use REPLY_RXON_ASSOC structure */
-       REPLY_WIPAN_QOS_PARAM = 0xb7,   /* use REPLY_QOS_PARAM structure */
-       REPLY_WIPAN_WEPKEY = 0xb8,      /* use REPLY_WEPKEY structure */
-       REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
-       REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
-       REPLY_WIPAN_DEACTIVATION_COMPLETE = 0xbd,
-
-       REPLY_WOWLAN_PATTERNS = 0xe0,
-       REPLY_WOWLAN_WAKEUP_FILTER = 0xe1,
-       REPLY_WOWLAN_TSC_RSC_PARAMS = 0xe2,
-       REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
-       REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
-       REPLY_WOWLAN_GET_STATUS = 0xe5,
-       REPLY_D3_CONFIG = 0xd3,
-
-       REPLY_MAX = 0xff
-};
-
-/******************************************************************************
- * (0)
- * Commonly used structures and definitions:
- * Command header, rate_n_flags, txpower
- *
- *****************************************************************************/
-
-/* iwl_cmd_header flags value */
-#define IWL_CMD_FAILED_MSK 0x40
-
-/**
- * iwlagn rate_n_flags bit fields
- *
- * rate_n_flags format is used in following iwlagn commands:
- *  REPLY_RX (response only)
- *  REPLY_RX_MPDU (response only)
- *  REPLY_TX (both command and response)
- *  REPLY_TX_LINK_QUALITY_CMD
- *
- * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
- *  2-0:  0)   6 Mbps
- *        1)  12 Mbps
- *        2)  18 Mbps
- *        3)  24 Mbps
- *        4)  36 Mbps
- *        5)  48 Mbps
- *        6)  54 Mbps
- *        7)  60 Mbps
- *
- *  4-3:  0)  Single stream (SISO)
- *        1)  Dual stream (MIMO)
- *        2)  Triple stream (MIMO)
- *
- *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data
- *
- * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
- *  3-0:  0xD)   6 Mbps
- *        0xF)   9 Mbps
- *        0x5)  12 Mbps
- *        0x7)  18 Mbps
- *        0x9)  24 Mbps
- *        0xB)  36 Mbps
- *        0x1)  48 Mbps
- *        0x3)  54 Mbps
- *
- * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
- *  6-0:   10)  1 Mbps
- *         20)  2 Mbps
- *         55)  5.5 Mbps
- *        110)  11 Mbps
- */
-#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_SPATIAL_POS 3
-#define RATE_MCS_SPATIAL_MSK 0x18
-#define RATE_MCS_HT_DUP_POS 5
-#define RATE_MCS_HT_DUP_MSK 0x20
-/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
-#define RATE_MCS_RATE_MSK 0xff
-
-/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
-#define RATE_MCS_FLAGS_POS 8
-#define RATE_MCS_HT_POS 8
-#define RATE_MCS_HT_MSK 0x100
-
-/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
-#define RATE_MCS_CCK_POS 9
-#define RATE_MCS_CCK_MSK 0x200
-
-/* Bit 10: (1) Use Green Field preamble */
-#define RATE_MCS_GF_POS 10
-#define RATE_MCS_GF_MSK 0x400
-
-/* Bit 11: (1) Use 40Mhz HT40 chnl width, (0) use 20 MHz legacy chnl width */
-#define RATE_MCS_HT40_POS 11
-#define RATE_MCS_HT40_MSK 0x800
-
-/* Bit 12: (1) Duplicate data on both 20MHz chnls. HT40 (bit 11) must be set. */
-#define RATE_MCS_DUP_POS 12
-#define RATE_MCS_DUP_MSK 0x1000
-
-/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
-#define RATE_MCS_SGI_POS 13
-#define RATE_MCS_SGI_MSK 0x2000
-
-/**
- * rate_n_flags Tx antenna masks
- * 4965 has 2 transmitters
- * 5100 has 1 transmitter B
- * 5150 has 1 transmitter A
- * 5300 has 3 transmitters
- * 5350 has 3 transmitters
- * bit14:16
- */
-#define RATE_MCS_ANT_POS       14
-#define RATE_MCS_ANT_A_MSK     0x04000
-#define RATE_MCS_ANT_B_MSK     0x08000
-#define RATE_MCS_ANT_C_MSK     0x10000
-#define RATE_MCS_ANT_AB_MSK    (RATE_MCS_ANT_A_MSK | RATE_MCS_ANT_B_MSK)
-#define RATE_MCS_ANT_ABC_MSK   (RATE_MCS_ANT_AB_MSK | RATE_MCS_ANT_C_MSK)
-#define RATE_ANT_NUM 3
-
-#define POWER_TABLE_NUM_ENTRIES                        33
-#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
-
-/**
- * struct tx_power_dual_stream
- *
- * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- *
- * Same format as iwl_tx_power_dual_stream, but __le32
- */
-struct tx_power_dual_stream {
-       __le32 dw;
-} __packed;
-
-/**
- * Command REPLY_TX_POWER_DBM_CMD = 0x98
- * struct iwlagn_tx_power_dbm_cmd
- */
-#define IWLAGN_TX_POWER_AUTO 0x7f
-#define IWLAGN_TX_POWER_NO_CLOSED (0x1 << 6)
-
-struct iwlagn_tx_power_dbm_cmd {
-       s8 global_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
-       u8 flags;
-       s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
-       u8 reserved;
-} __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;
-} __packed;
-
-/******************************************************************************
- * (0a)
- * Alive and Error Commands & Responses:
- *
- *****************************************************************************/
-
-#define UCODE_VALID_OK cpu_to_le32(0x1)
-
-/**
- * REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "alive" notification once the runtime image is ready
- * to receive commands from the driver.  This is the *second* "alive"
- * notification that the driver will receive after rebooting uCode;
- * this "alive" is indicated by subtype field != 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * This response includes two pointers to structures within the device's
- * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
- *
- * 1)  log_event_table_ptr indicates base of the event log.  This traces
- *     a 256-entry history of uCode execution within a circular buffer.
- *     Its header format is:
- *
- *     __le32 log_size;     log capacity (in number of entries)
- *     __le32 type;         (1) timestamp with each entry, (0) no timestamp
- *     __le32 wraps;        # times uCode has wrapped to top of circular buffer
- *      __le32 write_index;  next circular buffer entry that uCode would fill
- *
- *     The header is followed by the circular buffer of log entries.  Entries
- *     with timestamps have the following format:
- *
- *     __le32 event_id;     range 0 - 1500
- *     __le32 timestamp;    low 32 bits of TSF (of network, if associated)
- *     __le32 data;         event_id-specific data value
- *
- *     Entries without timestamps contain only event_id and data.
- *
- *
- * 2)  error_event_table_ptr indicates base of the error log.  This contains
- *     information about any uCode error that occurs.  For agn, the format
- *     of the error log is defined by struct iwl_error_event_table.
- *
- * The Linux driver can print both logs to the system log when a uCode error
- * occurs.
- */
-
-/*
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_error_event_table {
-       u32 valid;              /* (nonzero) valid, (0) log is empty */
-       u32 error_id;           /* type of error */
-       u32 pc;                 /* program counter */
-       u32 blink1;             /* branch link */
-       u32 blink2;             /* branch link */
-       u32 ilink1;             /* interrupt link */
-       u32 ilink2;             /* interrupt link */
-       u32 data1;              /* error-specific data */
-       u32 data2;              /* error-specific data */
-       u32 line;               /* source code line of error */
-       u32 bcon_time;          /* beacon timer */
-       u32 tsf_low;            /* network timestamp function timer */
-       u32 tsf_hi;             /* network timestamp function timer */
-       u32 gp1;                /* GP1 timer register */
-       u32 gp2;                /* GP2 timer register */
-       u32 gp3;                /* GP3 timer register */
-       u32 ucode_ver;          /* uCode version */
-       u32 hw_ver;             /* HW Silicon version */
-       u32 brd_ver;            /* HW board version */
-       u32 log_pc;             /* log program counter */
-       u32 frame_ptr;          /* frame pointer */
-       u32 stack_ptr;          /* stack pointer */
-       u32 hcmd;               /* last host command header */
-       u32 isr0;               /* isr status register LMPM_NIC_ISR0:
-                                * rxtx_flag */
-       u32 isr1;               /* isr status register LMPM_NIC_ISR1:
-                                * host_flag */
-       u32 isr2;               /* isr status register LMPM_NIC_ISR2:
-                                * enc_flag */
-       u32 isr3;               /* isr status register LMPM_NIC_ISR3:
-                                * time_flag */
-       u32 isr4;               /* isr status register LMPM_NIC_ISR4:
-                                * wico interrupt */
-       u32 isr_pref;           /* isr status register LMPM_NIC_PREF_STAT */
-       u32 wait_event;         /* wait event() caller address */
-       u32 l2p_control;        /* L2pControlField */
-       u32 l2p_duration;       /* L2pDurationField */
-       u32 l2p_mhvalid;        /* L2pMhValidBits */
-       u32 l2p_addr_match;     /* L2pAddrMatchStat */
-       u32 lmpm_pmg_sel;       /* indicate which clocks are turned on
-                                * (LMPM_PMG_SEL) */
-       u32 u_timestamp;        /* indicate when the date and time of the
-                                * compilation */
-       u32 flow_handler;       /* FH read/write pointers, RX credit */
-} __packed;
-
-struct iwl_alive_resp {
-       u8 ucode_minor;
-       u8 ucode_major;
-       __le16 reserved1;
-       u8 sw_rev[8];
-       u8 ver_type;
-       u8 ver_subtype;                 /* not "9" for runtime alive */
-       __le16 reserved2;
-       __le32 log_event_table_ptr;     /* SRAM address for event log */
-       __le32 error_event_table_ptr;   /* SRAM address for error log */
-       __le32 timestamp;
-       __le32 is_valid;
-} __packed;
-
-/*
- * REPLY_ERROR = 0x2 (response only, not a command)
- */
-struct iwl_error_resp {
-       __le32 error_type;
-       u8 cmd_id;
-       u8 reserved1;
-       __le16 bad_cmd_seq_num;
-       __le32 error_info;
-       __le64 timestamp;
-} __packed;
-
-/******************************************************************************
- * (1)
- * RXON Commands & Responses:
- *
- *****************************************************************************/
-
-/*
- * Rx config defines & structure
- */
-/* rx_config device types  */
-enum {
-       RXON_DEV_TYPE_AP = 1,
-       RXON_DEV_TYPE_ESS = 3,
-       RXON_DEV_TYPE_IBSS = 4,
-       RXON_DEV_TYPE_SNIFFER = 6,
-       RXON_DEV_TYPE_CP = 7,
-       RXON_DEV_TYPE_2STA = 8,
-       RXON_DEV_TYPE_P2P = 9,
-};
-
-
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK         cpu_to_le16(0x1 << 0)
-#define RXON_RX_CHAIN_DRIVER_FORCE_POS         (0)
-#define RXON_RX_CHAIN_VALID_MSK                        cpu_to_le16(0x7 << 1)
-#define RXON_RX_CHAIN_VALID_POS                        (1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK            cpu_to_le16(0x7 << 4)
-#define RXON_RX_CHAIN_FORCE_SEL_POS            (4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK       cpu_to_le16(0x7 << 7)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS       (7)
-#define RXON_RX_CHAIN_CNT_MSK                  cpu_to_le16(0x3 << 10)
-#define RXON_RX_CHAIN_CNT_POS                  (10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK             cpu_to_le16(0x3 << 12)
-#define RXON_RX_CHAIN_MIMO_CNT_POS             (12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK           cpu_to_le16(0x1 << 14)
-#define RXON_RX_CHAIN_MIMO_FORCE_POS           (14)
-
-/* rx_config flags */
-/* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK           cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK                cpu_to_le32(1 << 1)
-/* auto detection enable */
-#define RXON_FLG_AUTO_DETECT_MSK        cpu_to_le32(1 << 2)
-/* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK        cpu_to_le32(1 << 3)
-/* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK          cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK     cpu_to_le32(1 << 5)
-/* antenna selection */
-#define RXON_FLG_DIS_DIV_MSK            cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK            cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK              cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK              cpu_to_le32(1 << 9)
-/* radar detection enable */
-#define RXON_FLG_RADAR_DETECT_MSK       cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK    cpu_to_le32(1 << 13)
-/* rx response to host with 8-byte TSF
-* (according to ON_AIR deassertion) */
-#define RXON_FLG_TSF2HOST_MSK           cpu_to_le32(1 << 15)
-
-
-/* HT flags */
-#define RXON_FLG_CTRL_CHANNEL_LOC_POS          (22)
-#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK       cpu_to_le32(0x1 << 22)
-
-#define RXON_FLG_HT_OPERATING_MODE_POS         (23)
-
-#define RXON_FLG_HT_PROT_MSK                   cpu_to_le32(0x1 << 23)
-#define RXON_FLG_HT40_PROT_MSK                 cpu_to_le32(0x2 << 23)
-
-#define RXON_FLG_CHANNEL_MODE_POS              (25)
-#define RXON_FLG_CHANNEL_MODE_MSK              cpu_to_le32(0x3 << 25)
-
-/* channel mode */
-enum {
-       CHANNEL_MODE_LEGACY = 0,
-       CHANNEL_MODE_PURE_40 = 1,
-       CHANNEL_MODE_MIXED = 2,
-       CHANNEL_MODE_RESERVED = 3,
-};
-#define RXON_FLG_CHANNEL_MODE_LEGACY   cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
-#define RXON_FLG_CHANNEL_MODE_PURE_40  cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
-#define RXON_FLG_CHANNEL_MODE_MIXED    cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
-
-/* CTS to self (if spec allows) flag */
-#define RXON_FLG_SELF_CTS_EN                   cpu_to_le32(0x1<<30)
-
-/* rx_config filter flags */
-/* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK         cpu_to_le32(1 << 0)
-/* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK        cpu_to_le32(1 << 1)
-/* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK      cpu_to_le32(1 << 2)
-/* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK     cpu_to_le32(1 << 3)
-/* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
-/* STA is associated */
-#define RXON_FILTER_ASSOC_MSK           cpu_to_le32(1 << 5)
-/* transfer to host non bssid beacons in associated state */
-#define RXON_FILTER_BCON_AWARE_MSK      cpu_to_le32(1 << 6)
-
-/**
- * REPLY_RXON = 0x10 (command, has simple generic response)
- *
- * RXON tunes the radio tuner to a service channel, and sets up a number
- * of parameters that are used primarily for Rx, but also for Tx operations.
- *
- * NOTE:  When tuning to a new channel, driver must set the
- *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
- *        info within the device, including the station tables, tx retry
- *        rate tables, and txpower tables.  Driver must build a new station
- *        table and txpower table before transmitting anything on the RXON
- *        channel.
- *
- * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
- *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
- *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
- */
-
-struct iwl_rxon_cmd {
-       u8 node_addr[6];
-       __le16 reserved1;
-       u8 bssid_addr[6];
-       __le16 reserved2;
-       u8 wlap_bssid_addr[6];
-       __le16 reserved3;
-       u8 dev_type;
-       u8 air_propagation;
-       __le16 rx_chain;
-       u8 ofdm_basic_rates;
-       u8 cck_basic_rates;
-       __le16 assoc_id;
-       __le32 flags;
-       __le32 filter_flags;
-       __le16 channel;
-       u8 ofdm_ht_single_stream_basic_rates;
-       u8 ofdm_ht_dual_stream_basic_rates;
-       u8 ofdm_ht_triple_stream_basic_rates;
-       u8 reserved5;
-       __le16 acquisition_data;
-       __le16 reserved6;
-} __packed;
-
-/*
- * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
- */
-struct iwl_rxon_assoc_cmd {
-       __le32 flags;
-       __le32 filter_flags;
-       u8 ofdm_basic_rates;
-       u8 cck_basic_rates;
-       __le16 reserved1;
-       u8 ofdm_ht_single_stream_basic_rates;
-       u8 ofdm_ht_dual_stream_basic_rates;
-       u8 ofdm_ht_triple_stream_basic_rates;
-       u8 reserved2;
-       __le16 rx_chain_select_flags;
-       __le16 acquisition_data;
-       __le32 reserved3;
-} __packed;
-
-#define IWL_CONN_MAX_LISTEN_INTERVAL   10
-#define IWL_MAX_UCODE_BEACON_INTERVAL  4 /* 4096 */
-
-/*
- * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
- */
-struct iwl_rxon_time_cmd {
-       __le64 timestamp;
-       __le16 beacon_interval;
-       __le16 atim_window;
-       __le32 beacon_init_val;
-       __le16 listen_interval;
-       u8 dtim_period;
-       u8 delta_cp_bss_tbtts;
-} __packed;
-
-/*
- * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
- */
-/**
- * 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];
-} __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];
-} __packed;
-
-/*
- * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
- */
-struct iwl_csa_notification {
-       __le16 band;
-       __le16 channel;
-       __le32 status;          /* 0 - OK, 1 - fail */
-} __packed;
-
-/******************************************************************************
- * (2)
- * Quality-of-Service (QOS) Commands & Responses:
- *
- *****************************************************************************/
-
-/**
- * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
- * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
- *
- * @cw_min: Contention window, start value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
- * @cw_max: Contention window, max value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
- * @aifsn:  Number of slots in Arbitration Interframe Space (before
- *          performing random backoff timing prior to Tx).  Device default 1.
- * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
- *
- * Device will automatically increase contention window by (2*CW) + 1 for each
- * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
- * value, to cap the CW value.
- */
-struct iwl_ac_qos {
-       __le16 cw_min;
-       __le16 cw_max;
-       u8 aifsn;
-       u8 reserved1;
-       __le16 edca_txop;
-} __packed;
-
-/* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK  cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK          cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK    cpu_to_le32(0x10)
-
-/* Number of Access Categories (AC) (EDCA), queues 0..3 */
-#define AC_NUM                4
-
-/*
- * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
- *
- * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
- * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
- */
-struct iwl_qosparam_cmd {
-       __le32 qos_flags;
-       struct iwl_ac_qos ac[AC_NUM];
-} __packed;
-
-/******************************************************************************
- * (3)
- * Add/Modify Stations Commands & Responses:
- *
- *****************************************************************************/
-/*
- * Multi station support
- */
-
-/* Special, dedicated locations within device's station table */
-#define        IWL_AP_ID               0
-#define        IWL_AP_ID_PAN           1
-#define        IWL_STA_ID              2
-#define IWLAGN_PAN_BCAST_ID    14
-#define IWLAGN_BROADCAST_ID    15
-#define        IWLAGN_STATION_COUNT    16
-
-#define        IWL_INVALID_STATION     255
-#define IWL_MAX_TID_COUNT      8
-#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT
-
-#define STA_FLG_TX_RATE_MSK            cpu_to_le32(1 << 2)
-#define STA_FLG_PWR_SAVE_MSK           cpu_to_le32(1 << 8)
-#define STA_FLG_PAN_STATION            cpu_to_le32(1 << 13)
-#define STA_FLG_RTS_MIMO_PROT_MSK      cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK       cpu_to_le32(1 << 18)
-#define STA_FLG_MAX_AGG_SIZE_POS       (19)
-#define STA_FLG_MAX_AGG_SIZE_MSK       cpu_to_le32(3 << 19)
-#define STA_FLG_HT40_EN_MSK            cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK           cpu_to_le32(1 << 22)
-#define STA_FLG_AGG_MPDU_DENSITY_POS   (23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK   cpu_to_le32(7 << 23)
-
-/* Use in mode field.  1: modify existing entry, 0: add new station entry */
-#define STA_CONTROL_MODIFY_MSK         0x01
-
-/* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK        cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC     cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP                cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP       cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP       cpu_to_le16(0x0003)
-
-#define STA_KEY_FLG_KEYID_POS  8
-#define STA_KEY_FLG_INVALID    cpu_to_le16(0x0800)
-/* wep key is either from global key (0) or from station info array (1) */
-#define STA_KEY_FLG_MAP_KEY_MSK        cpu_to_le16(0x0008)
-
-/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
-#define STA_KEY_MAX_NUM                8
-#define STA_KEY_MAX_NUM_PAN    16
-/* must not match WEP_INVALID_OFFSET */
-#define IWLAGN_HW_KEY_DEFAULT  0xfe
-
-/* Flags indicate whether to modify vs. don't change various station params */
-#define        STA_MODIFY_KEY_MASK             0x01
-#define        STA_MODIFY_TID_DISABLE_TX       0x02
-#define        STA_MODIFY_TX_RATE_MSK          0x04
-#define STA_MODIFY_ADDBA_TID_MSK       0x08
-#define STA_MODIFY_DELBA_TID_MSK       0x10
-#define STA_MODIFY_SLEEP_TX_COUNT_MSK  0x20
-
-/* Receiver address (actually, Rx station's index into station table),
- * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
-#define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
-
-/* agn */
-struct iwl_keyinfo {
-       __le16 key_flags;
-       u8 tkip_rx_tsc_byte2;   /* TSC[2] for key mix ph1 detection */
-       u8 reserved1;
-       __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
-       u8 key_offset;
-       u8 reserved2;
-       u8 key[16];             /* 16-byte unicast decryption key */
-       __le64 tx_secur_seq_cnt;
-       __le64 hw_tkip_mic_rx_key;
-       __le64 hw_tkip_mic_tx_key;
-} __packed;
-
-/**
- * struct sta_id_modify
- * @addr[ETH_ALEN]: station's MAC address
- * @sta_id: index of station in uCode's station table
- * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
- *
- * Driver selects unused table index when adding new station,
- * or the index to a pre-existing station entry when modifying that station.
- * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
- *
- * modify_mask flags select which parameters to modify vs. leave alone.
- */
-struct sta_id_modify {
-       u8 addr[ETH_ALEN];
-       __le16 reserved1;
-       u8 sta_id;
-       u8 modify_mask;
-       __le16 reserved2;
-} __packed;
-
-/*
- * REPLY_ADD_STA = 0x18 (command)
- *
- * The device contains an internal table of per-station information,
- * with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (agn devices uses
- * REPLY_TX_LINK_QUALITY_CMD,
- *
- * REPLY_ADD_STA sets up the table entry for one station, either creating
- * a new entry, or modifying a pre-existing one.
- *
- * NOTE:  RXON command (without "associated" bit set) wipes the station table
- *        clean.  Moving into RF_KILL state does this also.  Driver must set up
- *        new station table before transmitting anything on the RXON channel
- *        (except active scans or active measurements; those commands carry
- *        their own txpower/rate setup data).
- *
- *        When getting started on a new channel, driver must set up the
- *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
- *        station in a BSS, once an AP is selected, driver sets up the AP STA
- *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
- *        are all that are needed for a BSS client station.  If the device is
- *        used as AP, or in an IBSS network, driver must set up station table
- *        entries for all STAs in network, starting with index IWL_STA_ID.
- */
-
-struct iwl_addsta_cmd {
-       u8 mode;                /* 1: modify existing, 0: add new station */
-       u8 reserved[3];
-       struct sta_id_modify sta;
-       struct iwl_keyinfo key;
-       __le32 station_flags;           /* STA_FLG_* */
-       __le32 station_flags_msk;       /* STA_FLG_* */
-
-       /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
-        * corresponding to bit (e.g. bit 5 controls TID 5).
-        * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
-       __le16 tid_disable_tx;
-       __le16 legacy_reserved;
-
-       /* TID for which to add block-ack support.
-        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-       u8 add_immediate_ba_tid;
-
-       /* TID for which to remove block-ack support.
-        * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
-       u8 remove_immediate_ba_tid;
-
-       /* Starting Sequence Number for added block-ack support.
-        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
-       __le16 add_immediate_ba_ssn;
-
-       /*
-        * Number of packets OK to transmit to station even though
-        * it is asleep -- used to synchronise PS-poll and u-APSD
-        * responses while ucode keeps track of STA sleep state.
-        */
-       __le16 sleep_tx_count;
-
-       __le16 reserved2;
-} __packed;
-
-
-#define ADD_STA_SUCCESS_MSK            0x1
-#define ADD_STA_NO_ROOM_IN_TABLE       0x2
-#define ADD_STA_NO_BLOCK_ACK_RESOURCE  0x4
-#define ADD_STA_MODIFY_NON_EXIST_STA   0x8
-/*
- * REPLY_ADD_STA = 0x18 (response)
- */
-struct iwl_add_sta_resp {
-       u8 status;      /* ADD_STA_* */
-} __packed;
-
-#define REM_STA_SUCCESS_MSK              0x1
-/*
- *  REPLY_REM_STA = 0x19 (response)
- */
-struct iwl_rem_sta_resp {
-       u8 status;
-} __packed;
-
-/*
- *  REPLY_REM_STA = 0x19 (command)
- */
-struct iwl_rem_sta_cmd {
-       u8 num_sta;     /* number of removed stations */
-       u8 reserved[3];
-       u8 addr[ETH_ALEN]; /* MAC addr of the first station */
-       u8 reserved2[2];
-} __packed;
-
-
-/* WiFi queues mask */
-#define IWL_SCD_BK_MSK                 cpu_to_le32(BIT(0))
-#define IWL_SCD_BE_MSK                 cpu_to_le32(BIT(1))
-#define IWL_SCD_VI_MSK                 cpu_to_le32(BIT(2))
-#define IWL_SCD_VO_MSK                 cpu_to_le32(BIT(3))
-#define IWL_SCD_MGMT_MSK               cpu_to_le32(BIT(3))
-
-/* PAN queues mask */
-#define IWL_PAN_SCD_BK_MSK             cpu_to_le32(BIT(4))
-#define IWL_PAN_SCD_BE_MSK             cpu_to_le32(BIT(5))
-#define IWL_PAN_SCD_VI_MSK             cpu_to_le32(BIT(6))
-#define IWL_PAN_SCD_VO_MSK             cpu_to_le32(BIT(7))
-#define IWL_PAN_SCD_MGMT_MSK           cpu_to_le32(BIT(7))
-#define IWL_PAN_SCD_MULTICAST_MSK      cpu_to_le32(BIT(8))
-
-#define IWL_AGG_TX_QUEUE_MSK           cpu_to_le32(0xffc00)
-
-#define IWL_DROP_SINGLE                0
-#define IWL_DROP_ALL           (BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN))
-
-/*
- * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
- *
- * When using full FIFO flush this command checks the scheduler HW block WR/RD
- * pointers to check if all the frames were transferred by DMA into the
- * relevant TX FIFO queue. Only when the DMA is finished and the queue is
- * empty the command can finish.
- * This command is used to flush the TXFIFO from transmit commands, it may
- * operate on single or multiple queues, the command queue can't be flushed by
- * this command. The command response is returned when all the queue flush
- * operations are done. Each TX command flushed return response with the FLUSH
- * status set in the TX response status. When FIFO flush operation is used,
- * the flush operation ends when both the scheduler DMA done and TXFIFO empty
- * are set.
- *
- * @fifo_control: bit mask for which queues to flush
- * @flush_control: flush controls
- *     0: Dump single MSDU
- *     1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
- *     2: Dump all FIFO
- */
-struct iwl_txfifo_flush_cmd {
-       __le32 fifo_control;
-       __le16 flush_control;
-       __le16 reserved;
-} __packed;
-
-/*
- * REPLY_WEP_KEY = 0x20
- */
-struct iwl_wep_key {
-       u8 key_index;
-       u8 key_offset;
-       u8 reserved1[2];
-       u8 key_size;
-       u8 reserved2[3];
-       u8 key[16];
-} __packed;
-
-struct iwl_wep_cmd {
-       u8 num_keys;
-       u8 global_key_type;
-       u8 flags;
-       u8 reserved;
-       struct iwl_wep_key key[0];
-} __packed;
-
-#define WEP_KEY_WEP_TYPE 1
-#define WEP_KEYS_MAX 4
-#define WEP_INVALID_OFFSET 0xff
-#define WEP_KEY_LEN_64 5
-#define WEP_KEY_LEN_128 13
-
-/******************************************************************************
- * (4)
- * Rx Responses:
- *
- *****************************************************************************/
-
-#define RX_RES_STATUS_NO_CRC32_ERROR   cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW  cpu_to_le32(1 << 1)
-
-#define RX_RES_PHY_FLAGS_BAND_24_MSK   cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK           cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK    cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK       cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK           0xf0
-#define RX_RES_PHY_FLAGS_ANTENNA_POS           4
-
-#define RX_RES_STATUS_SEC_TYPE_MSK     (0x7 << 8)
-#define RX_RES_STATUS_SEC_TYPE_NONE    (0x0 << 8)
-#define RX_RES_STATUS_SEC_TYPE_WEP     (0x1 << 8)
-#define RX_RES_STATUS_SEC_TYPE_CCMP    (0x2 << 8)
-#define RX_RES_STATUS_SEC_TYPE_TKIP    (0x3 << 8)
-#define        RX_RES_STATUS_SEC_TYPE_ERR      (0x7 << 8)
-
-#define RX_RES_STATUS_STATION_FOUND    (1<<6)
-#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)
-
-#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
-#define RX_RES_STATUS_NOT_DECRYPT      (0x0 << 11)
-#define RX_RES_STATUS_DECRYPT_OK       (0x3 << 11)
-#define RX_RES_STATUS_BAD_ICV_MIC      (0x1 << 11)
-#define RX_RES_STATUS_BAD_KEY_TTAK     (0x2 << 11)
-
-#define RX_MPDU_RES_STATUS_ICV_OK      (0x20)
-#define RX_MPDU_RES_STATUS_MIC_OK      (0x40)
-#define RX_MPDU_RES_STATUS_TTAK_OK     (1 << 7)
-#define RX_MPDU_RES_STATUS_DEC_DONE_MSK        (0x800)
-
-
-#define IWLAGN_RX_RES_PHY_CNT 8
-#define IWLAGN_RX_RES_AGC_IDX     1
-#define IWLAGN_RX_RES_RSSI_AB_IDX 2
-#define IWLAGN_RX_RES_RSSI_C_IDX  3
-#define IWLAGN_OFDM_AGC_MSK 0xfe00
-#define IWLAGN_OFDM_AGC_BIT_POS 9
-#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
-#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
-#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
-#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
-#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
-#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
-#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
-#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
-#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
-
-struct iwlagn_non_cfg_phy {
-       __le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT];  /* up to 8 phy entries */
-} __packed;
-
-
-/*
- * REPLY_RX = 0xc3 (response only, not a command)
- * Used only for legacy (non 11n) frames.
- */
-struct iwl_rx_phy_res {
-       u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
-       u8 cfg_phy_cnt;         /* configurable DSP phy data byte count */
-       u8 stat_id;             /* configurable DSP phy data set ID */
-       u8 reserved1;
-       __le64 timestamp;       /* TSF at on air rise */
-       __le32 beacon_time_stamp; /* beacon at on-air rise */
-       __le16 phy_flags;       /* general phy flags: band, modulation, ... */
-       __le16 channel;         /* channel number */
-       u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
-       __le32 rate_n_flags;    /* RATE_MCS_* */
-       __le16 byte_count;      /* frame's byte-count */
-       __le16 frame_time;      /* frame's time on the air */
-} __packed;
-
-struct iwl_rx_mpdu_res_start {
-       __le16 byte_count;
-       __le16 reserved;
-} __packed;
-
-
-/******************************************************************************
- * (5)
- * Tx Commands & Responses:
- *
- * Driver must place each REPLY_TX command into one of the prioritized Tx
- * queues in host DRAM, shared between driver and device (see comments for
- * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
- * are preparing to transmit, the device pulls the Tx command over the PCI
- * bus via one of the device's Tx DMA channels, to fill an internal FIFO
- * from which data will be transmitted.
- *
- * uCode handles all timing and protocol related to control frames
- * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
- * handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA.
- *
- * uCode handles retrying Tx when an ACK is expected but not received.
- * This includes trying lower data rates than the one requested in the Tx
- * command, as set up by the REPLY_TX_LINK_QUALITY_CMD (agn).
- *
- * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
- * This command must be executed after every RXON command, before Tx can occur.
- *****************************************************************************/
-
-/* REPLY_TX Tx flags field */
-
-/*
- * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it
- * before this frame. if CTS-to-self required check
- * RXON_FLG_SELF_CTS_EN status.
- */
-#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)
-
-/* 1: Expect ACK from receiving station
- * 0: Don't expect ACK (MAC header's duration field s/b 0)
- * Set this for unicast frames, but not broadcast/multicast. */
-#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
-
-/* For agn devices:
- * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
- *    Tx command's initial_rate_index indicates first rate to try;
- *    uCode walks through table for additional Tx attempts.
- * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
- *    This rate will be used for all Tx attempts; it will not be scaled. */
-#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4)
-
-/* 1: Expect immediate block-ack.
- * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
-#define TX_CMD_FLG_IMM_BA_RSP_MASK  cpu_to_le32(1 << 6)
-
-/* Tx antenna selection field; reserved (0) for agn devices. */
-#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
-
-/* 1: Ignore Bluetooth priority for this frame.
- * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_IGNORE_BT cpu_to_le32(1 << 12)
-
-/* 1: uCode overrides sequence control field in MAC header.
- * 0: Driver provides sequence control field in MAC header.
- * Set this for management frames, non-QOS data frames, non-unicast frames,
- * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
-#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13)
-
-/* 1: This frame is non-last MPDU; more fragments are coming.
- * 0: Last fragment, or not using fragmentation. */
-#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14)
-
-/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
- * 0: No TSF required in outgoing frame.
- * Set this for transmitting beacons and probe responses. */
-#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16)
-
-/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
- *    alignment of frame's payload data field.
- * 0: No pad
- * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
- * field (but not both).  Driver must align frame data (i.e. data following
- * MAC header) to DWORD boundary. */
-#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
-
-/* accelerate aggregation support
- * 0 - no CCMP encryption; 1 - CCMP encryption */
-#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
-
-/* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
-
-
-/*
- * TX command security control
- */
-#define TX_CMD_SEC_WEP         0x01
-#define TX_CMD_SEC_CCM         0x02
-#define TX_CMD_SEC_TKIP                0x03
-#define TX_CMD_SEC_MSK         0x03
-#define TX_CMD_SEC_SHIFT       6
-#define TX_CMD_SEC_KEY128      0x08
-
-/*
- * security overhead sizes
- */
-#define WEP_IV_LEN 4
-#define WEP_ICV_LEN 4
-#define CCMP_MIC_LEN 8
-#define TKIP_ICV_LEN 4
-
-/*
- * REPLY_TX = 0x1c (command)
- */
-
-/*
- * 4965 uCode updates these Tx attempt count values in host DRAM.
- * Used for managing Tx retries when expecting block-acks.
- * Driver should set these fields to 0.
- */
-struct iwl_dram_scratch {
-       u8 try_cnt;             /* Tx attempts */
-       u8 bt_kill_cnt;         /* Tx attempts blocked by Bluetooth device */
-       __le16 reserved;
-} __packed;
-
-struct iwl_tx_cmd {
-       /*
-        * MPDU byte count:
-        * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
-        * + 8 byte IV for CCM or TKIP (not used for WEP)
-        * + Data payload
-        * + 8-byte MIC (not used for CCM/WEP)
-        * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
-        *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
-        * Range: 14-2342 bytes.
-        */
-       __le16 len;
-
-       /*
-        * MPDU or MSDU byte count for next frame.
-        * Used for fragmentation and bursting, but not 11n aggregation.
-        * Same as "len", but for next frame.  Set to 0 if not applicable.
-        */
-       __le16 next_frame_len;
-
-       __le32 tx_flags;        /* TX_CMD_FLG_* */
-
-       /* uCode may modify this field of the Tx command (in host DRAM!).
-        * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
-       struct iwl_dram_scratch scratch;
-
-       /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
-       __le32 rate_n_flags;    /* RATE_MCS_* */
-
-       /* Index of destination station in uCode's station table */
-       u8 sta_id;
-
-       /* Type of security encryption:  CCM or TKIP */
-       u8 sec_ctl;             /* TX_CMD_SEC_* */
-
-       /*
-        * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
-        * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
-        * data frames, this field may be used to selectively reduce initial
-        * rate (via non-0 value) for special frames (e.g. management), while
-        * still supporting rate scaling for all frames.
-        */
-       u8 initial_rate_index;
-       u8 reserved;
-       u8 key[16];
-       __le16 next_frame_flags;
-       __le16 reserved2;
-       union {
-               __le32 life_time;
-               __le32 attempt;
-       } stop_time;
-
-       /* Host DRAM physical address pointer to "scratch" in this command.
-        * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
-       __le32 dram_lsb_ptr;
-       u8 dram_msb_ptr;
-
-       u8 rts_retry_limit;     /*byte 50 */
-       u8 data_retry_limit;    /*byte 51 */
-       u8 tid_tspec;
-       union {
-               __le16 pm_frame_timeout;
-               __le16 attempt_duration;
-       } timeout;
-
-       /*
-        * Duration of EDCA burst Tx Opportunity, in 32-usec units.
-        * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
-        */
-       __le16 driver_txop;
-
-       /*
-        * MAC header goes here, followed by 2 bytes padding if MAC header
-        * length is 26 or 30 bytes, followed by payload data
-        */
-       u8 payload[0];
-       struct ieee80211_hdr hdr[0];
-} __packed;
-
-/*
- * TX command response is sent after *agn* transmission attempts.
- *
- * both postpone and abort status are expected behavior from uCode. there is
- * no special operation required from driver; except for RFKILL_FLUSH,
- * which required tx flush host command to flush all the tx frames in queues
- */
-enum {
-       TX_STATUS_SUCCESS = 0x01,
-       TX_STATUS_DIRECT_DONE = 0x02,
-       /* postpone TX */
-       TX_STATUS_POSTPONE_DELAY = 0x40,
-       TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
-       TX_STATUS_POSTPONE_BT_PRIO = 0x42,
-       TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
-       TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
-       /* abort TX */
-       TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
-       TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
-       TX_STATUS_FAIL_LONG_LIMIT = 0x83,
-       TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-       TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
-       TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
-       TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
-       TX_STATUS_FAIL_DEST_PS = 0x88,
-       TX_STATUS_FAIL_HOST_ABORTED = 0x89,
-       TX_STATUS_FAIL_BT_RETRY = 0x8a,
-       TX_STATUS_FAIL_STA_INVALID = 0x8b,
-       TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
-       TX_STATUS_FAIL_TID_DISABLE = 0x8d,
-       TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
-       TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-       TX_STATUS_FAIL_PASSIVE_NO_RX = 0x90,
-       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
-};
-
-#define        TX_PACKET_MODE_REGULAR          0x0000
-#define        TX_PACKET_MODE_BURST_SEQ        0x0100
-#define        TX_PACKET_MODE_BURST_FIRST      0x0200
-
-enum {
-       TX_POWER_PA_NOT_ACTIVE = 0x0,
-};
-
-enum {
-       TX_STATUS_MSK = 0x000000ff,             /* bits 0:7 */
-       TX_STATUS_DELAY_MSK = 0x00000040,
-       TX_STATUS_ABORT_MSK = 0x00000080,
-       TX_PACKET_MODE_MSK = 0x0000ff00,        /* bits 8:15 */
-       TX_FIFO_NUMBER_MSK = 0x00070000,        /* bits 16:18 */
-       TX_RESERVED = 0x00780000,               /* bits 19:22 */
-       TX_POWER_PA_DETECT_MSK = 0x7f800000,    /* bits 23:30 */
-       TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
-};
-
-/* *******************************
- * TX aggregation status
- ******************************* */
-
-enum {
-       AGG_TX_STATE_TRANSMITTED = 0x00,
-       AGG_TX_STATE_UNDERRUN_MSK = 0x01,
-       AGG_TX_STATE_BT_PRIO_MSK = 0x02,
-       AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
-       AGG_TX_STATE_ABORT_MSK = 0x08,
-       AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
-       AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
-       AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
-       AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
-       AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
-       AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
-       AGG_TX_STATE_DUMP_TX_MSK = 0x200,
-       AGG_TX_STATE_DELAY_TX_MSK = 0x400
-};
-
-#define AGG_TX_STATUS_MSK      0x00000fff      /* bits 0:11 */
-#define AGG_TX_TRY_MSK         0x0000f000      /* bits 12:15 */
-
-#define AGG_TX_STATE_LAST_SENT_MSK  (AGG_TX_STATE_LAST_SENT_TTL_MSK | \
-                                    AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
-                                    AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
-
-/* # tx attempts for first frame in aggregation */
-#define AGG_TX_STATE_TRY_CNT_POS 12
-#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
-
-/* Command ID and sequence number of Tx command for this frame */
-#define AGG_TX_STATE_SEQ_NUM_POS 16
-#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
-
-/*
- * REPLY_TX = 0x1c (response)
- *
- * This response may be in one of two slightly different formats, indicated
- * by the frame_count field:
- *
- * 1)  No aggregation (frame_count == 1).  This reports Tx results for
- *     a single frame.  Multiple attempts, at various bit rates, may have
- *     been made for this frame.
- *
- * 2)  Aggregation (frame_count > 1).  This reports Tx results for
- *     2 or more frames that used block-acknowledge.  All frames were
- *     transmitted at same rate.  Rate scaling may have been used if first
- *     frame in this new agg block failed in previous agg block(s).
- *
- *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
- *     block-ack has not been received by the time the agn device records
- *     this status.
- *     This status relates to reasons the tx might have been blocked or aborted
- *     within the sending station (this agn device), rather than whether it was
- *     received successfully by the destination station.
- */
-struct agg_tx_status {
-       __le16 status;
-       __le16 sequence;
-} __packed;
-
-/*
- * definitions for initial rate index field
- * bits [3:0] initial rate index
- * bits [6:4] rate table color, used for the initial rate
- * bit-7 invalid rate indication
- *   i.e. rate was not chosen from rate table
- *   or rate table color was changed during frame retries
- * refer tlc rate info
- */
-
-#define IWL50_TX_RES_INIT_RATE_INDEX_POS       0
-#define IWL50_TX_RES_INIT_RATE_INDEX_MSK       0x0f
-#define IWL50_TX_RES_RATE_TABLE_COLOR_POS      4
-#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK      0x70
-#define IWL50_TX_RES_INV_RATE_INDEX_MSK        0x80
-
-/* refer to ra_tid */
-#define IWLAGN_TX_RES_TID_POS  0
-#define IWLAGN_TX_RES_TID_MSK  0x0f
-#define IWLAGN_TX_RES_RA_POS   4
-#define IWLAGN_TX_RES_RA_MSK   0xf0
-
-struct iwlagn_tx_resp {
-       u8 frame_count;         /* 1 no aggregation, >1 aggregation */
-       u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
-       u8 failure_rts;         /* # failures due to unsuccessful RTS */
-       u8 failure_frame;       /* # failures due to no ACK (unused for agg) */
-
-       /* For non-agg:  Rate at which frame was successful.
-        * For agg:  Rate at which all frames were transmitted. */
-       __le32 rate_n_flags;    /* RATE_MCS_*  */
-
-       /* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
-        * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
-       __le16 wireless_media_time;     /* uSecs */
-
-       u8 pa_status;           /* RF power amplifier measurement (not used) */
-       u8 pa_integ_res_a[3];
-       u8 pa_integ_res_b[3];
-       u8 pa_integ_res_C[3];
-
-       __le32 tfd_info;
-       __le16 seq_ctl;
-       __le16 byte_cnt;
-       u8 tlc_info;
-       u8 ra_tid;              /* tid (0:3), sta_id (4:7) */
-       __le16 frame_ctrl;
-       /*
-        * For non-agg:  frame status TX_STATUS_*
-        * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
-        *           fields follow this one, up to frame_count.
-        *           Bit fields:
-        *           11- 0:  AGG_TX_STATE_* status code
-        *           15-12:  Retry count for 1st frame in aggregation (retries
-        *                   occur if tx failed for this frame when it was a
-        *                   member of a previous aggregation block).  If rate
-        *                   scaling is used, retry count indicates the rate
-        *                   table entry used for all frames in the new agg.
-        *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
-        */
-       struct agg_tx_status status;    /* TX status (in aggregation -
-                                        * status of 1st frame) */
-} __packed;
-/*
- * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
- *
- * Reports Block-Acknowledge from recipient station
- */
-struct iwl_compressed_ba_resp {
-       __le32 sta_addr_lo32;
-       __le16 sta_addr_hi16;
-       __le16 reserved;
-
-       /* Index of recipient (BA-sending) station in uCode's station table */
-       u8 sta_id;
-       u8 tid;
-       __le16 seq_ctl;
-       __le64 bitmap;
-       __le16 scd_flow;
-       __le16 scd_ssn;
-       u8 txed;        /* number of frames sent */
-       u8 txed_2_done; /* number of frames acked */
-} __packed;
-
-/*
- * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
- *
- */
-
-/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
-#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK   (1 << 0)
-
-/* # of EDCA prioritized tx fifos */
-#define  LINK_QUAL_AC_NUM AC_NUM
-
-/* # entries in rate scale table to support Tx retries */
-#define  LINK_QUAL_MAX_RETRY_NUM 16
-
-/* Tx antenna selection values */
-#define  LINK_QUAL_ANT_A_MSK (1 << 0)
-#define  LINK_QUAL_ANT_B_MSK (1 << 1)
-#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
-
-
-/**
- * struct iwl_link_qual_general_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_general_params {
-       u8 flags;
-
-       /* No entries at or above this (driver chosen) index contain MIMO */
-       u8 mimo_delimiter;
-
-       /* Best single antenna to use for single stream (legacy, SISO). */
-       u8 single_stream_ant_msk;       /* LINK_QUAL_ANT_* */
-
-       /* Best antennas to use for MIMO (unused for 4965, assumes both). */
-       u8 dual_stream_ant_msk;         /* LINK_QUAL_ANT_* */
-
-       /*
-        * If driver needs to use different initial rates for different
-        * EDCA QOS access categories (as implemented by tx fifos 0-3),
-        * this table will set that up, by indicating the indexes in the
-        * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
-        * Otherwise, driver should set all entries to 0.
-        *
-        * Entry usage:
-        * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
-        * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
-        */
-       u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __packed;
-
-#define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (8000)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (100)
-
-#define LINK_QUAL_AGG_DISABLE_START_DEF        (3)
-#define LINK_QUAL_AGG_DISABLE_START_MAX        (255)
-#define LINK_QUAL_AGG_DISABLE_START_MIN        (0)
-
-#define LINK_QUAL_AGG_FRAME_LIMIT_DEF  (63)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX  (63)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MIN  (0)
-
-/**
- * struct iwl_link_qual_agg_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_agg_params {
-
-       /*
-        *Maximum number of uSec in aggregation.
-        * default set to 4000 (4 milliseconds) if not configured in .cfg
-        */
-       __le16 agg_time_limit;
-
-       /*
-        * Number of Tx retries allowed for a frame, before that frame will
-        * no longer be considered for the start of an aggregation sequence
-        * (scheduler will then try to tx it as single frame).
-        * Driver should set this to 3.
-        */
-       u8 agg_dis_start_th;
-
-       /*
-        * Maximum number of frames in aggregation.
-        * 0 = no limit (default).  1 = no aggregation.
-        * Other values = max # frames in aggregation.
-        */
-       u8 agg_frame_cnt_limit;
-
-       __le32 reserved;
-} __packed;
-
-/*
- * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
- *
- * For agn devices
- *
- * Each station in the agn device's internal station table has its own table
- * of 16
- * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
- * an ACK is not received.  This command replaces the entire table for
- * one station.
- *
- * NOTE:  Station must already be in agn device's station table.
- *       Use REPLY_ADD_STA.
- *
- * The rate scaling procedures described below work well.  Of course, other
- * procedures are possible, and may work better for particular environments.
- *
- *
- * FILLING THE RATE TABLE
- *
- * Given a particular initial rate and mode, as determined by the rate
- * scaling algorithm described below, the Linux driver uses the following
- * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
- * Link Quality command:
- *
- *
- * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
- *     a) Use this same initial rate for first 3 entries.
- *     b) Find next lower available rate using same mode (SISO or MIMO),
- *        use for next 3 entries.  If no lower rate available, switch to
- *        legacy mode (no HT40 channel, no MIMO, no short guard interval).
- *     c) If using MIMO, set command's mimo_delimiter to number of entries
- *        using MIMO (3 or 6).
- *     d) After trying 2 HT rates, switch to legacy mode (no HT40 channel,
- *        no MIMO, no short guard interval), at the next lower bit rate
- *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
- *        legacy procedure for remaining table entries.
- *
- * 2)  If using legacy initial rate:
- *     a) Use the initial rate for only one entry.
- *     b) For each following entry, reduce the rate to next lower available
- *        rate, until reaching the lowest available rate.
- *     c) When reducing rate, also switch antenna selection.
- *     d) Once lowest available rate is reached, repeat this rate until
- *        rate table is filled (16 entries), switching antenna each entry.
- *
- *
- * ACCUMULATING HISTORY
- *
- * The rate scaling algorithm for agn devices, as implemented in Linux driver,
- * uses two sets of frame Tx success history:  One for the current/active
- * modulation mode, and one for a speculative/search mode that is being
- * attempted. If the speculative mode turns out to be more effective (i.e.
- * actual transfer rate is better), then the driver continues to use the
- * speculative mode as the new current active mode.
- *
- * Each history set contains, separately for each possible rate, data for a
- * sliding window of the 62 most recent tx attempts at that rate.  The data
- * includes a shifting bitmap of success(1)/failure(0), and sums of successful
- * and attempted frames, from which the driver can additionally calculate a
- * success ratio (success / attempted) and number of failures
- * (attempted - success), and control the size of the window (attempted).
- * The driver uses the bit map to remove successes from the success sum, as
- * the oldest tx attempts fall out of the window.
- *
- * When the agn device makes multiple tx attempts for a given frame, each
- * attempt might be at a different rate, and have different modulation
- * characteristics (e.g. antenna, fat channel, short guard interval), as set
- * up in the rate scaling table in the Link Quality command.  The driver must
- * determine which rate table entry was used for each tx attempt, to determine
- * which rate-specific history to update, and record only those attempts that
- * match the modulation characteristics of the history set.
- *
- * When using block-ack (aggregation), all frames are transmitted at the same
- * rate, since there is no per-attempt acknowledgment from the destination
- * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
- * rate_n_flags field.  After receiving a block-ack, the driver can update
- * history for the entire block all at once.
- *
- *
- * FINDING BEST STARTING RATE:
- *
- * When working with a selected initial modulation mode (see below), the
- * driver attempts to find a best initial rate.  The initial rate is the
- * first entry in the Link Quality command's rate table.
- *
- * 1)  Calculate actual throughput (success ratio * expected throughput, see
- *     table below) for current initial rate.  Do this only if enough frames
- *     have been attempted to make the value meaningful:  at least 6 failed
- *     tx attempts, or at least 8 successes.  If not enough, don't try rate
- *     scaling yet.
- *
- * 2)  Find available rates adjacent to current initial rate.  Available means:
- *     a)  supported by hardware &&
- *     b)  supported by association &&
- *     c)  within any constraints selected by user
- *
- * 3)  Gather measured throughputs for adjacent rates.  These might not have
- *     enough history to calculate a throughput.  That's okay, we might try
- *     using one of them anyway!
- *
- * 4)  Try decreasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  lower adjacent rate has better measured throughput ||
- *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
- *
- *     As a sanity check, if decrease was determined above, leave rate
- *     unchanged if:
- *     a)  lower rate unavailable
- *     b)  success ratio at current rate > 85% (very good)
- *     c)  current measured throughput is better than expected throughput
- *         of lower rate (under perfect 100% tx conditions, see table below)
- *
- * 5)  Try increasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
- *     b)  higher adjacent rate has better measured throughput ||
- *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
- *
- *     As a sanity check, if increase was determined above, leave rate
- *     unchanged if:
- *     a)  success ratio at current rate < 70%.  This is not particularly
- *         good performance; higher rate is sure to have poorer success.
- *
- * 6)  Re-evaluate the rate after each tx frame.  If working with block-
- *     acknowledge, history and statistics may be calculated for the entire
- *     block (including prior history that fits within the history windows),
- *     before re-evaluation.
- *
- * FINDING BEST STARTING MODULATION MODE:
- *
- * After working with a modulation mode for a "while" (and doing rate scaling),
- * the driver searches for a new initial mode in an attempt to improve
- * throughput.  The "while" is measured by numbers of attempted frames:
- *
- * For legacy mode, search for new mode after:
- *   480 successful frames, or 160 failed frames
- * For high-throughput modes (SISO or MIMO), search for new mode after:
- *   4500 successful frames, or 400 failed frames
- *
- * Mode switch possibilities are (3 for each mode):
- *
- * For legacy:
- *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
- * For SISO:
- *   Change antenna, try MIMO, try shortened guard interval (SGI)
- * For MIMO:
- *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
- *
- * When trying a new mode, use the same bit rate as the old/current mode when
- * trying antenna switches and shortened guard interval.  When switching to
- * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
- * for which the expected throughput (under perfect conditions) is about the
- * same or slightly better than the actual measured throughput delivered by
- * the old/current mode.
- *
- * Actual throughput can be estimated by multiplying the expected throughput
- * by the success ratio (successful / attempted tx frames).  Frame size is
- * not considered in this calculation; it assumes that frame size will average
- * out to be fairly consistent over several samples.  The following are
- * metric values for expected throughput assuming 100% success ratio.
- * Only G band has support for CCK rates:
- *
- *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
- *
- *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
- *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
- *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
- * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
- *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
- * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
- *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
- * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
- *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
- * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
- *
- * After the new mode has been tried for a short while (minimum of 6 failed
- * frames or 8 successful frames), compare success ratio and actual throughput
- * estimate of the new mode with the old.  If either is better with the new
- * mode, continue to use the new mode.
- *
- * Continue comparing modes until all 3 possibilities have been tried.
- * If moving from legacy to HT, try all 3 possibilities from the new HT
- * mode.  After trying all 3, a best mode is found.  Continue to use this mode
- * for the longer "while" described above (e.g. 480 successful frames for
- * legacy), and then repeat the search process.
- *
- */
-struct iwl_link_quality_cmd {
-
-       /* Index of destination/recipient station in uCode's station table */
-       u8 sta_id;
-       u8 reserved1;
-       __le16 control;         /* not used */
-       struct iwl_link_qual_general_params general_params;
-       struct iwl_link_qual_agg_params agg_params;
-
-       /*
-        * Rate info; when using rate-scaling, Tx command's initial_rate_index
-        * specifies 1st Tx rate attempted, via index into this table.
-        * agn devices works its way through table when retrying Tx.
-        */
-       struct {
-               __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
-       } rs_table[LINK_QUAL_MAX_RETRY_NUM];
-       __le32 reserved2;
-} __packed;
-
-/*
- * BT configuration enable flags:
- *   bit 0 - 1: BT channel announcement enabled
- *           0: disable
- *   bit 1 - 1: priority of BT device enabled
- *           0: disable
- *   bit 2 - 1: BT 2 wire support enabled
- *           0: disable
- */
-#define BT_COEX_DISABLE (0x0)
-#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
-#define BT_ENABLE_PRIORITY        BIT(1)
-#define BT_ENABLE_2_WIRE          BIT(2)
-
-#define BT_COEX_DISABLE (0x0)
-#define BT_COEX_ENABLE  (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
-
-#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)
-
-#define BT_DURATION_LIMIT_DEF  625
-#define BT_DURATION_LIMIT_MAX  1250
-#define BT_DURATION_LIMIT_MIN  625
-
-#define BT_ON_THRESHOLD_DEF    4
-#define BT_ON_THRESHOLD_MAX    1000
-#define BT_ON_THRESHOLD_MIN    1
-
-#define BT_FRAG_THRESHOLD_DEF  0
-#define BT_FRAG_THRESHOLD_MAX  0
-#define BT_FRAG_THRESHOLD_MIN  0
-
-#define BT_AGG_THRESHOLD_DEF   1200
-#define BT_AGG_THRESHOLD_MAX   8000
-#define BT_AGG_THRESHOLD_MIN   400
-
-/*
- * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
- *
- * agn devices support hardware handshake with Bluetooth device on
- * same platform.  Bluetooth device alerts wireless device when it will Tx;
- * wireless device can delay or kill its own Tx to accommodate.
- */
-struct iwl_bt_cmd {
-       u8 flags;
-       u8 lead_time;
-       u8 max_kill;
-       u8 reserved;
-       __le32 kill_ack_mask;
-       __le32 kill_cts_mask;
-} __packed;
-
-#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION      BIT(0)
-
-#define IWLAGN_BT_FLAG_COEX_MODE_MASK          (BIT(3)|BIT(4)|BIT(5))
-#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT         3
-#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED      0
-#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W     1
-#define IWLAGN_BT_FLAG_COEX_MODE_3W            2
-#define IWLAGN_BT_FLAG_COEX_MODE_4W            3
-
-#define IWLAGN_BT_FLAG_UCODE_DEFAULT           BIT(6)
-/* Disable Sync PSPoll on SCO/eSCO */
-#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE       BIT(7)
-
-#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD       -75 /* dBm */
-#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD       -65 /* dBm */
-
-#define IWLAGN_BT_PRIO_BOOST_MAX       0xFF
-#define IWLAGN_BT_PRIO_BOOST_MIN       0x00
-#define IWLAGN_BT_PRIO_BOOST_DEFAULT   0xF0
-
-#define IWLAGN_BT_MAX_KILL_DEFAULT     5
-
-#define IWLAGN_BT3_T7_DEFAULT          1
-
-enum iwl_bt_kill_idx {
-       IWL_BT_KILL_DEFAULT = 0,
-       IWL_BT_KILL_OVERRIDE = 1,
-       IWL_BT_KILL_REDUCE = 2,
-};
-
-#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT        cpu_to_le32(0xffff0000)
-#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT        cpu_to_le32(0xffff0000)
-#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO        cpu_to_le32(0xffffffff)
-#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE     cpu_to_le32(0)
-
-#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
-
-#define IWLAGN_BT3_T2_DEFAULT          0xc
-
-#define IWLAGN_BT_VALID_ENABLE_FLAGS   cpu_to_le16(BIT(0))
-#define IWLAGN_BT_VALID_BOOST          cpu_to_le16(BIT(1))
-#define IWLAGN_BT_VALID_MAX_KILL       cpu_to_le16(BIT(2))
-#define IWLAGN_BT_VALID_3W_TIMERS      cpu_to_le16(BIT(3))
-#define IWLAGN_BT_VALID_KILL_ACK_MASK  cpu_to_le16(BIT(4))
-#define IWLAGN_BT_VALID_KILL_CTS_MASK  cpu_to_le16(BIT(5))
-#define IWLAGN_BT_VALID_REDUCED_TX_PWR cpu_to_le16(BIT(6))
-#define IWLAGN_BT_VALID_3W_LUT         cpu_to_le16(BIT(7))
-
-#define IWLAGN_BT_ALL_VALID_MSK                (IWLAGN_BT_VALID_ENABLE_FLAGS | \
-                                       IWLAGN_BT_VALID_BOOST | \
-                                       IWLAGN_BT_VALID_MAX_KILL | \
-                                       IWLAGN_BT_VALID_3W_TIMERS | \
-                                       IWLAGN_BT_VALID_KILL_ACK_MASK | \
-                                       IWLAGN_BT_VALID_KILL_CTS_MASK | \
-                                       IWLAGN_BT_VALID_REDUCED_TX_PWR | \
-                                       IWLAGN_BT_VALID_3W_LUT)
-
-#define IWLAGN_BT_REDUCED_TX_PWR       BIT(0)
-
-#define IWLAGN_BT_DECISION_LUT_SIZE    12
-
-struct iwl_basic_bt_cmd {
-       u8 flags;
-       u8 ledtime; /* unused */
-       u8 max_kill;
-       u8 bt3_timer_t7_value;
-       __le32 kill_ack_mask;
-       __le32 kill_cts_mask;
-       u8 bt3_prio_sample_time;
-       u8 bt3_timer_t2_value;
-       __le16 bt4_reaction_time; /* unused */
-       __le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
-       /*
-        * bit 0: use reduced tx power for control frame
-        * bit 1 - 7: reserved
-        */
-       u8 reduce_txpower;
-       u8 reserved;
-       __le16 valid;
-};
-
-struct iwl_bt_cmd_v1 {
-       struct iwl_basic_bt_cmd basic;
-       u8 prio_boost;
-       /*
-        * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
-        * if configure the following patterns
-        */
-       u8 tx_prio_boost;       /* SW boost of WiFi tx priority */
-       __le16 rx_prio_boost;   /* SW boost of WiFi rx priority */
-};
-
-struct iwl_bt_cmd_v2 {
-       struct iwl_basic_bt_cmd basic;
-       __le32 prio_boost;
-       /*
-        * set IWLAGN_BT_VALID_BOOST to "1" in "valid" bitmask
-        * if configure the following patterns
-        */
-       u8 reserved;
-       u8 tx_prio_boost;       /* SW boost of WiFi tx priority */
-       __le16 rx_prio_boost;   /* SW boost of WiFi rx priority */
-};
-
-#define IWLAGN_BT_SCO_ACTIVE   cpu_to_le32(BIT(0))
-
-struct iwlagn_bt_sco_cmd {
-       __le32 flags;
-};
-
-/******************************************************************************
- * (6)
- * Spectrum Management (802.11h) Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/*
- * Spectrum Management
- */
-#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
-                                RXON_FILTER_CTL2HOST_MSK        | \
-                                RXON_FILTER_ACCEPT_GRP_MSK      | \
-                                RXON_FILTER_DIS_DECRYPT_MSK     | \
-                                RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
-                                RXON_FILTER_ASSOC_MSK           | \
-                                RXON_FILTER_BCON_AWARE_MSK)
-
-struct iwl_measure_channel {
-       __le32 duration;        /* measurement duration in extended beacon
-                                * format */
-       u8 channel;             /* channel to measure */
-       u8 type;                /* see enum iwl_measure_type */
-       __le16 reserved;
-} __packed;
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
- */
-struct iwl_spectrum_cmd {
-       __le16 len;             /* number of bytes starting from token */
-       u8 token;               /* token id */
-       u8 id;                  /* measurement id -- 0 or 1 */
-       u8 origin;              /* 0 = TGh, 1 = other, 2 = TGk */
-       u8 periodic;            /* 1 = periodic */
-       __le16 path_loss_timeout;
-       __le32 start_time;      /* start time in extended beacon format */
-       __le32 reserved2;
-       __le32 flags;           /* rxon flags */
-       __le32 filter_flags;    /* rxon filter flags */
-       __le16 channel_count;   /* minimum 1, maximum 10 */
-       __le16 reserved3;
-       struct iwl_measure_channel channels[10];
-} __packed;
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
- */
-struct iwl_spectrum_resp {
-       u8 token;
-       u8 id;                  /* id of the prior command replaced, or 0xff */
-       __le16 status;          /* 0 - command will be handled
-                                * 1 - cannot handle (conflicts with another
-                                *     measurement) */
-} __packed;
-
-enum iwl_measurement_state {
-       IWL_MEASUREMENT_START = 0,
-       IWL_MEASUREMENT_STOP = 1,
-};
-
-enum iwl_measurement_status {
-       IWL_MEASUREMENT_OK = 0,
-       IWL_MEASUREMENT_CONCURRENT = 1,
-       IWL_MEASUREMENT_CSA_CONFLICT = 2,
-       IWL_MEASUREMENT_TGH_CONFLICT = 3,
-       /* 4-5 reserved */
-       IWL_MEASUREMENT_STOPPED = 6,
-       IWL_MEASUREMENT_TIMEOUT = 7,
-       IWL_MEASUREMENT_PERIODIC_FAILED = 8,
-};
-
-#define NUM_ELEMENTS_IN_HISTOGRAM 8
-
-struct iwl_measurement_histogram {
-       __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
-       __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];  /* in 1usec counts */
-} __packed;
-
-/* clear channel availability counters */
-struct iwl_measurement_cca_counters {
-       __le32 ofdm;
-       __le32 cck;
-} __packed;
-
-enum iwl_measure_type {
-       IWL_MEASURE_BASIC = (1 << 0),
-       IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
-       IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
-       IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
-       IWL_MEASURE_FRAME = (1 << 4),
-       /* bits 5:6 are reserved */
-       IWL_MEASURE_IDLE = (1 << 7),
-};
-
-/*
- * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
- */
-struct iwl_spectrum_notification {
-       u8 id;                  /* measurement id -- 0 or 1 */
-       u8 token;
-       u8 channel_index;       /* index in measurement channel list */
-       u8 state;               /* 0 - start, 1 - stop */
-       __le32 start_time;      /* lower 32-bits of TSF */
-       u8 band;                /* 0 - 5.2GHz, 1 - 2.4GHz */
-       u8 channel;
-       u8 type;                /* see enum iwl_measurement_type */
-       u8 reserved1;
-       /* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
-        * valid if applicable for measurement type requested. */
-       __le32 cca_ofdm;        /* cca fraction time in 40Mhz clock periods */
-       __le32 cca_cck;         /* cca fraction time in 44Mhz clock periods */
-       __le32 cca_time;        /* channel load time in usecs */
-       u8 basic_type;          /* 0 - bss, 1 - ofdm preamble, 2 -
-                                * unidentified */
-       u8 reserved2[3];
-       struct iwl_measurement_histogram histogram;
-       __le32 stop_time;       /* lower 32-bits of TSF */
-       __le32 status;          /* see iwl_measurement_status */
-} __packed;
-
-/******************************************************************************
- * (7)
- * Power Management Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/**
- * struct iwl_powertable_cmd - Power Table Command
- * @flags: See below:
- *
- * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
- *
- * PM allow:
- *   bit 0 - '0' Driver not allow power management
- *           '1' Driver allow PM (use rest of parameters)
- *
- * uCode send sleep notifications:
- *   bit 1 - '0' Don't send sleep notification
- *           '1' send sleep notification (SEND_PM_NOTIFICATION)
- *
- * Sleep over DTIM
- *   bit 2 - '0' PM have to walk up every DTIM
- *           '1' PM could sleep over DTIM till listen Interval.
- *
- * PCI power managed
- *   bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
- *           '1' !(PCI_CFG_LINK_CTRL & 0x1)
- *
- * Fast PD
- *   bit 4 - '1' Put radio to sleep when receiving frame for others
- *
- * Force sleep Modes
- *   bit 31/30- '00' use both mac/xtal sleeps
- *              '01' force Mac sleep
- *              '10' force xtal sleep
- *              '11' Illegal set
- *
- * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
- * ucode assume sleep over DTIM is allowed and we don't need to wake up
- * for every DTIM.
- */
-#define IWL_POWER_VEC_SIZE 5
-
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK       cpu_to_le16(BIT(0))
-#define IWL_POWER_POWER_SAVE_ENA_MSK           cpu_to_le16(BIT(0))
-#define IWL_POWER_POWER_MANAGEMENT_ENA_MSK     cpu_to_le16(BIT(1))
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK          cpu_to_le16(BIT(2))
-#define IWL_POWER_PCI_PM_MSK                   cpu_to_le16(BIT(3))
-#define IWL_POWER_FAST_PD                      cpu_to_le16(BIT(4))
-#define IWL_POWER_BEACON_FILTERING             cpu_to_le16(BIT(5))
-#define IWL_POWER_SHADOW_REG_ENA               cpu_to_le16(BIT(6))
-#define IWL_POWER_CT_KILL_SET                  cpu_to_le16(BIT(7))
-#define IWL_POWER_BT_SCO_ENA                   cpu_to_le16(BIT(8))
-#define IWL_POWER_ADVANCE_PM_ENA_MSK           cpu_to_le16(BIT(9))
-
-struct iwl_powertable_cmd {
-       __le16 flags;
-       u8 keep_alive_seconds;
-       u8 debug_flags;
-       __le32 rx_data_timeout;
-       __le32 tx_data_timeout;
-       __le32 sleep_interval[IWL_POWER_VEC_SIZE];
-       __le32 keep_alive_beacons;
-} __packed;
-
-/*
- * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * all devices identical.
- */
-struct iwl_sleep_notification {
-       u8 pm_sleep_mode;
-       u8 pm_wakeup_src;
-       __le16 reserved;
-       __le32 sleep_time;
-       __le32 tsf_low;
-       __le32 bcon_timer;
-} __packed;
-
-/* Sleep states.  all devices identical. */
-enum {
-       IWL_PM_NO_SLEEP = 0,
-       IWL_PM_SLP_MAC = 1,
-       IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
-       IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
-       IWL_PM_SLP_PHY = 4,
-       IWL_PM_SLP_REPENT = 5,
-       IWL_PM_WAKEUP_BY_TIMER = 6,
-       IWL_PM_WAKEUP_BY_DRIVER = 7,
-       IWL_PM_WAKEUP_BY_RFKILL = 8,
-       /* 3 reserved */
-       IWL_PM_NUM_OF_MODES = 12,
-};
-
-/*
- * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
- */
-#define CARD_STATE_CMD_DISABLE 0x00    /* Put card to sleep */
-#define CARD_STATE_CMD_ENABLE  0x01    /* Wake up card */
-#define CARD_STATE_CMD_HALT    0x02    /* Power down permanently */
-struct iwl_card_state_cmd {
-       __le32 status;          /* CARD_STATE_CMD_* request new power state */
-} __packed;
-
-/*
- * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
- */
-struct iwl_card_state_notif {
-       __le32 flags;
-} __packed;
-
-#define HW_CARD_DISABLED   0x01
-#define SW_CARD_DISABLED   0x02
-#define CT_CARD_DISABLED   0x04
-#define RXON_CARD_DISABLED 0x10
-
-struct iwl_ct_kill_config {
-       __le32   reserved;
-       __le32   critical_temperature_M;
-       __le32   critical_temperature_R;
-}  __packed;
-
-/* 1000, and 6x00 */
-struct iwl_ct_kill_throttling_config {
-       __le32   critical_temperature_exit;
-       __le32   reserved;
-       __le32   critical_temperature_enter;
-}  __packed;
-
-/******************************************************************************
- * (8)
- * Scan Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0)
-#define SCAN_CHANNEL_TYPE_ACTIVE  cpu_to_le32(1)
-
-/**
- * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
- *
- * One for each channel in the scan list.
- * Each channel can independently select:
- * 1)  SSID for directed active scans
- * 2)  Txpower setting (for rate specified within Tx command)
- * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
- *     quiet_plcp_th, good_CRC_th)
- *
- * To avoid uCode errors, make sure the following are true (see comments
- * under struct iwl_scan_cmd about max_out_time and quiet_time):
- * 1)  If using passive_dwell (i.e. passive_dwell != 0):
- *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
- * 2)  quiet_time <= active_dwell
- * 3)  If restricting off-channel time (i.e. max_out_time !=0):
- *     passive_dwell < max_out_time
- *     active_dwell < max_out_time
- */
-
-struct iwl_scan_channel {
-       /*
-        * type is defined as:
-        * 0:0 1 = active, 0 = passive
-        * 1:20 SSID direct bit map; if a bit is set, then corresponding
-        *     SSID IE is transmitted in probe request.
-        * 21:31 reserved
-        */
-       __le32 type;
-       __le16 channel; /* band is selected by iwl_scan_cmd "flags" field */
-       u8 tx_gain;             /* gain for analog radio */
-       u8 dsp_atten;           /* gain for DSP */
-       __le16 active_dwell;    /* in 1024-uSec TU (time units), typ 5-50 */
-       __le16 passive_dwell;   /* in 1024-uSec TU (time units), typ 20-500 */
-} __packed;
-
-/* set number of direct probes __le32 type */
-#define IWL_SCAN_PROBE_MASK(n)         cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
-
-/**
- * struct iwl_ssid_ie - directed scan network information element
- *
- * Up to 20 of these may appear in REPLY_SCAN_CMD,
- * selected by "type" bit field in struct iwl_scan_channel;
- * each channel may select different ssids from among the 20 entries.
- * SSID IEs get transmitted in reverse order of entry.
- */
-struct iwl_ssid_ie {
-       u8 id;
-       u8 len;
-       u8 ssid[32];
-} __packed;
-
-#define PROBE_OPTION_MAX               20
-#define TX_CMD_LIFE_TIME_INFINITE      cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH_DISABLED       0
-#define IWL_GOOD_CRC_TH_DEFAULT                cpu_to_le16(1)
-#define IWL_GOOD_CRC_TH_NEVER          cpu_to_le16(0xffff)
-#define IWL_MAX_CMD_SIZE 4096
-
-/*
- * REPLY_SCAN_CMD = 0x80 (command)
- *
- * The hardware scan command is very powerful; the driver can set it up to
- * maintain (relatively) normal network traffic while doing a scan in the
- * background.  The max_out_time and suspend_time control the ratio of how
- * long the device stays on an associated network channel ("service channel")
- * vs. how long it's away from the service channel, i.e. tuned to other channels
- * for scanning.
- *
- * max_out_time is the max time off-channel (in usec), and suspend_time
- * is how long (in "extended beacon" format) that the scan is "suspended"
- * after returning to the service channel.  That is, suspend_time is the
- * time that we stay on the service channel, doing normal work, between
- * scan segments.  The driver may set these parameters differently to support
- * scanning when associated vs. not associated, and light vs. heavy traffic
- * loads when associated.
- *
- * After receiving this command, the device's scan engine does the following;
- *
- * 1)  Sends SCAN_START notification to driver
- * 2)  Checks to see if it has time to do scan for one channel
- * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
- *     to tell AP that we're going off-channel
- * 4)  Tunes to first channel in scan list, does active or passive scan
- * 5)  Sends SCAN_RESULT notification to driver
- * 6)  Checks to see if it has time to do scan on *next* channel in list
- * 7)  Repeats 4-6 until it no longer has time to scan the next channel
- *     before max_out_time expires
- * 8)  Returns to service channel
- * 9)  Sends NULL packet with PS=0 to tell AP that we're back
- * 10) Stays on service channel until suspend_time expires
- * 11) Repeats entire process 2-10 until list is complete
- * 12) Sends SCAN_COMPLETE notification
- *
- * For fast, efficient scans, the scan command also has support for staying on
- * a channel for just a short time, if doing active scanning and getting no
- * responses to the transmitted probe request.  This time is controlled by
- * quiet_time, and the number of received packets below which a channel is
- * considered "quiet" is controlled by quiet_plcp_threshold.
- *
- * For active scanning on channels that have regulatory restrictions against
- * blindly transmitting, the scan can listen before transmitting, to make sure
- * that there is already legitimate activity on the channel.  If enough
- * packets are cleanly received on the channel (controlled by good_CRC_th,
- * typical value 1), the scan engine starts transmitting probe requests.
- *
- * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
- *
- * To avoid uCode errors, see timing restrictions described under
- * struct iwl_scan_channel.
- */
-
-enum iwl_scan_flags {
-       /* BIT(0) currently unused */
-       IWL_SCAN_FLAGS_ACTION_FRAME_TX  = BIT(1),
-       /* bits 2-7 reserved */
-};
-
-struct iwl_scan_cmd {
-       __le16 len;
-       u8 scan_flags;          /* scan flags: see enum iwl_scan_flags */
-       u8 channel_count;       /* # channels in channel list */
-       __le16 quiet_time;      /* dwell only this # millisecs on quiet channel
-                                * (only for active scan) */
-       __le16 quiet_plcp_th;   /* quiet chnl is < this # pkts (typ. 1) */
-       __le16 good_CRC_th;     /* passive -> active promotion threshold */
-       __le16 rx_chain;        /* RXON_RX_CHAIN_* */
-       __le32 max_out_time;    /* max usec to be away from associated (service)
-                                * channel */
-       __le32 suspend_time;    /* pause scan this long (in "extended beacon
-                                * format") when returning to service chnl:
-                                */
-       __le32 flags;           /* RXON_FLG_* */
-       __le32 filter_flags;    /* RXON_FILTER_* */
-
-       /* For active scans (set to all-0s for passive scans).
-        * Does not include payload.  Must specify Tx rate; no rate scaling. */
-       struct iwl_tx_cmd tx_cmd;
-
-       /* For directed active scans (set to all-0s otherwise) */
-       struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
-
-       /*
-        * Probe request frame, followed by channel list.
-        *
-        * Size of probe request frame is specified by byte count in tx_cmd.
-        * Channel list follows immediately after probe request frame.
-        * Number of channels in list is specified by channel_count.
-        * Each channel in list is of type:
-        *
-        * struct iwl_scan_channel channels[0];
-        *
-        * NOTE:  Only one band of channels can be scanned per pass.  You
-        * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
-        * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
-        * before requesting another scan.
-        */
-       u8 data[0];
-} __packed;
-
-/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS       cpu_to_le32(0x1)
-/* complete notification statuses */
-#define ABORT_STATUS            0x2
-
-/*
- * REPLY_SCAN_CMD = 0x80 (response)
- */
-struct iwl_scanreq_notification {
-       __le32 status;          /* 1: okay, 2: cannot fulfill request */
-} __packed;
-
-/*
- * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
- */
-struct iwl_scanstart_notification {
-       __le32 tsf_low;
-       __le32 tsf_high;
-       __le32 beacon_timer;
-       u8 channel;
-       u8 band;
-       u8 reserved[2];
-       __le32 status;
-} __packed;
-
-#define  SCAN_OWNER_STATUS 0x1
-#define  MEASURE_OWNER_STATUS 0x2
-
-#define IWL_PROBE_STATUS_OK            0
-#define IWL_PROBE_STATUS_TX_FAILED     BIT(0)
-/* error statuses combined with TX_FAILED */
-#define IWL_PROBE_STATUS_FAIL_TTL      BIT(1)
-#define IWL_PROBE_STATUS_FAIL_BT       BIT(2)
-
-#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
-/*
- * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
- */
-struct iwl_scanresults_notification {
-       u8 channel;
-       u8 band;
-       u8 probe_status;
-       u8 num_probe_not_sent; /* not enough time to send */
-       __le32 tsf_low;
-       __le32 tsf_high;
-       __le32 statistics[NUMBER_OF_STATISTICS];
-} __packed;
-
-/*
- * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
- */
-struct iwl_scancomplete_notification {
-       u8 scanned_channels;
-       u8 status;
-       u8 bt_status;   /* BT On/Off status */
-       u8 last_channel;
-       __le32 tsf_low;
-       __le32 tsf_high;
-} __packed;
-
-
-/******************************************************************************
- * (9)
- * IBSS/AP Commands and Notifications:
- *
- *****************************************************************************/
-
-enum iwl_ibss_manager {
-       IWL_NOT_IBSS_MANAGER = 0,
-       IWL_IBSS_MANAGER = 1,
-};
-
-/*
- * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
- */
-
-struct iwlagn_beacon_notif {
-       struct iwlagn_tx_resp beacon_notify_hdr;
-       __le32 low_tsf;
-       __le32 high_tsf;
-       __le32 ibss_mgr_status;
-} __packed;
-
-/*
- * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
- */
-
-struct iwl_tx_beacon_cmd {
-       struct iwl_tx_cmd tx;
-       __le16 tim_idx;
-       u8 tim_size;
-       u8 reserved1;
-       struct ieee80211_hdr frame[0];  /* beacon frame */
-} __packed;
-
-/******************************************************************************
- * (10)
- * Statistics Commands and Notifications:
- *
- *****************************************************************************/
-
-#define IWL_TEMP_CONVERT 260
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-/* Used for passing to driver number of successes and failures per rate */
-struct rate_histogram {
-       union {
-               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-       } success;
-       union {
-               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-       } failed;
-} __packed;
-
-/* statistics command response */
-
-struct statistics_dbg {
-       __le32 burst_check;
-       __le32 burst_count;
-       __le32 wait_for_silence_timeout_cnt;
-       __le32 reserved[3];
-} __packed;
-
-struct statistics_rx_phy {
-       __le32 ina_cnt;
-       __le32 fina_cnt;
-       __le32 plcp_err;
-       __le32 crc32_err;
-       __le32 overrun_err;
-       __le32 early_overrun_err;
-       __le32 crc32_good;
-       __le32 false_alarm_cnt;
-       __le32 fina_sync_err_cnt;
-       __le32 sfd_timeout;
-       __le32 fina_timeout;
-       __le32 unresponded_rts;
-       __le32 rxe_frame_limit_overrun;
-       __le32 sent_ack_cnt;
-       __le32 sent_cts_cnt;
-       __le32 sent_ba_rsp_cnt;
-       __le32 dsp_self_kill;
-       __le32 mh_format_err;
-       __le32 re_acq_main_rssi_sum;
-       __le32 reserved3;
-} __packed;
-
-struct statistics_rx_ht_phy {
-       __le32 plcp_err;
-       __le32 overrun_err;
-       __le32 early_overrun_err;
-       __le32 crc32_good;
-       __le32 crc32_err;
-       __le32 mh_format_err;
-       __le32 agg_crc32_good;
-       __le32 agg_mpdu_cnt;
-       __le32 agg_cnt;
-       __le32 unsupport_mcs;
-} __packed;
-
-#define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
-
-struct statistics_rx_non_phy {
-       __le32 bogus_cts;       /* CTS received when not expecting CTS */
-       __le32 bogus_ack;       /* ACK received when not expecting ACK */
-       __le32 non_bssid_frames;        /* number of frames with BSSID that
-                                        * doesn't belong to the STA BSSID */
-       __le32 filtered_frames; /* count frames that were dumped in the
-                                * filtering process */
-       __le32 non_channel_beacons;     /* beacons with our bss id but not on
-                                        * our serving channel */
-       __le32 channel_beacons; /* beacons with our bss id and in our
-                                * serving channel */
-       __le32 num_missed_bcon; /* number of missed beacons */
-       __le32 adc_rx_saturation_time;  /* count in 0.8us units the time the
-                                        * ADC was in saturation */
-       __le32 ina_detection_search_time;/* total time (in 0.8us) searched
-                                         * for INA */
-       __le32 beacon_silence_rssi_a;   /* RSSI silence after beacon frame */
-       __le32 beacon_silence_rssi_b;   /* RSSI silence after beacon frame */
-       __le32 beacon_silence_rssi_c;   /* RSSI silence after beacon frame */
-       __le32 interference_data_flag;  /* flag for interference data
-                                        * availability. 1 when data is
-                                        * available. */
-       __le32 channel_load;            /* counts RX Enable time in uSec */
-       __le32 dsp_false_alarms;        /* DSP false alarm (both OFDM
-                                        * and CCK) counter */
-       __le32 beacon_rssi_a;
-       __le32 beacon_rssi_b;
-       __le32 beacon_rssi_c;
-       __le32 beacon_energy_a;
-       __le32 beacon_energy_b;
-       __le32 beacon_energy_c;
-} __packed;
-
-struct statistics_rx_non_phy_bt {
-       struct statistics_rx_non_phy common;
-       /* additional stats for bt */
-       __le32 num_bt_kills;
-       __le32 reserved[2];
-} __packed;
-
-struct statistics_rx {
-       struct statistics_rx_phy ofdm;
-       struct statistics_rx_phy cck;
-       struct statistics_rx_non_phy general;
-       struct statistics_rx_ht_phy ofdm_ht;
-} __packed;
-
-struct statistics_rx_bt {
-       struct statistics_rx_phy ofdm;
-       struct statistics_rx_phy cck;
-       struct statistics_rx_non_phy_bt general;
-       struct statistics_rx_ht_phy ofdm_ht;
-} __packed;
-
-/**
- * struct statistics_tx_power - current tx power
- *
- * @ant_a: current tx power on chain a in 1/2 dB step
- * @ant_b: current tx power on chain b in 1/2 dB step
- * @ant_c: current tx power on chain c in 1/2 dB step
- */
-struct statistics_tx_power {
-       u8 ant_a;
-       u8 ant_b;
-       u8 ant_c;
-       u8 reserved;
-} __packed;
-
-struct statistics_tx_non_phy_agg {
-       __le32 ba_timeout;
-       __le32 ba_reschedule_frames;
-       __le32 scd_query_agg_frame_cnt;
-       __le32 scd_query_no_agg;
-       __le32 scd_query_agg;
-       __le32 scd_query_mismatch;
-       __le32 frame_not_ready;
-       __le32 underrun;
-       __le32 bt_prio_kill;
-       __le32 rx_ba_rsp_cnt;
-} __packed;
-
-struct statistics_tx {
-       __le32 preamble_cnt;
-       __le32 rx_detected_cnt;
-       __le32 bt_prio_defer_cnt;
-       __le32 bt_prio_kill_cnt;
-       __le32 few_bytes_cnt;
-       __le32 cts_timeout;
-       __le32 ack_timeout;
-       __le32 expected_ack_cnt;
-       __le32 actual_ack_cnt;
-       __le32 dump_msdu_cnt;
-       __le32 burst_abort_next_frame_mismatch_cnt;
-       __le32 burst_abort_missing_next_frame_cnt;
-       __le32 cts_timeout_collision;
-       __le32 ack_or_ba_timeout_collision;
-       struct statistics_tx_non_phy_agg agg;
-       /*
-        * "tx_power" are optional parameters provided by uCode,
-        * 6000 series is the only device provide the information,
-        * Those are reserved fields for all the other devices
-        */
-       struct statistics_tx_power tx_power;
-       __le32 reserved1;
-} __packed;
-
-
-struct statistics_div {
-       __le32 tx_on_a;
-       __le32 tx_on_b;
-       __le32 exec_time;
-       __le32 probe_time;
-       __le32 reserved1;
-       __le32 reserved2;
-} __packed;
-
-struct statistics_general_common {
-       __le32 temperature;   /* radio temperature */
-       __le32 temperature_m; /* radio voltage */
-       struct statistics_dbg dbg;
-       __le32 sleep_time;
-       __le32 slots_out;
-       __le32 slots_idle;
-       __le32 ttl_timestamp;
-       struct statistics_div div;
-       __le32 rx_enable_counter;
-       /*
-        * num_of_sos_states:
-        *  count the number of times we have to re-tune
-        *  in order to get out of bad PHY status
-        */
-       __le32 num_of_sos_states;
-} __packed;
-
-struct statistics_bt_activity {
-       /* Tx statistics */
-       __le32 hi_priority_tx_req_cnt;
-       __le32 hi_priority_tx_denied_cnt;
-       __le32 lo_priority_tx_req_cnt;
-       __le32 lo_priority_tx_denied_cnt;
-       /* Rx statistics */
-       __le32 hi_priority_rx_req_cnt;
-       __le32 hi_priority_rx_denied_cnt;
-       __le32 lo_priority_rx_req_cnt;
-       __le32 lo_priority_rx_denied_cnt;
-} __packed;
-
-struct statistics_general {
-       struct statistics_general_common common;
-       __le32 reserved2;
-       __le32 reserved3;
-} __packed;
-
-struct statistics_general_bt {
-       struct statistics_general_common common;
-       struct statistics_bt_activity activity;
-       __le32 reserved2;
-       __le32 reserved3;
-} __packed;
-
-#define UCODE_STATISTICS_CLEAR_MSK             (0x1 << 0)
-#define UCODE_STATISTICS_FREQUENCY_MSK         (0x1 << 1)
-#define UCODE_STATISTICS_NARROW_BAND_MSK       (0x1 << 2)
-
-/*
- * REPLY_STATISTICS_CMD = 0x9c,
- * all devices identical.
- *
- * This command triggers an immediate response containing uCode statistics.
- * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
- *
- * If the CLEAR_STATS configuration flag is set, uCode will clear its
- * internal copy of the statistics (counters) after issuing the response.
- * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
- *
- * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
- * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
- * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
- */
-#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1)    /* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
-struct iwl_statistics_cmd {
-       __le32 configuration_flags;     /* IWL_STATS_CONF_* */
-} __packed;
-
-/*
- * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
- *
- * By default, uCode issues this notification after receiving a beacon
- * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans.  uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
- */
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_HT40_MODE_MSK        cpu_to_le32(0x8)
-
-struct iwl_notif_statistics {
-       __le32 flag;
-       struct statistics_rx rx;
-       struct statistics_tx tx;
-       struct statistics_general general;
-} __packed;
-
-struct iwl_bt_notif_statistics {
-       __le32 flag;
-       struct statistics_rx_bt rx;
-       struct statistics_tx tx;
-       struct statistics_general_bt general;
-} __packed;
-
-/*
- * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
- *
- * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
- * in regardless of how many missed beacons, which mean when driver receive the
- * notification, inside the command, it can find all the beacons information
- * which include number of total missed beacons, number of consecutive missed
- * beacons, number of beacons received and number of beacons expected to
- * receive.
- *
- * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
- * in order to bring the radio/PHY back to working state; which has no relation
- * to when driver will perform sensitivity calibration.
- *
- * Driver should set it own missed_beacon_threshold to decide when to perform
- * sensitivity calibration based on number of consecutive missed beacons in
- * order to improve overall performance, especially in noisy environment.
- *
- */
-
-#define IWL_MISSED_BEACON_THRESHOLD_MIN        (1)
-#define IWL_MISSED_BEACON_THRESHOLD_DEF        (5)
-#define IWL_MISSED_BEACON_THRESHOLD_MAX        IWL_MISSED_BEACON_THRESHOLD_DEF
-
-struct iwl_missed_beacon_notif {
-       __le32 consecutive_missed_beacons;
-       __le32 total_missed_becons;
-       __le32 num_expected_beacons;
-       __le32 num_recvd_beacons;
-} __packed;
-
-
-/******************************************************************************
- * (11)
- * Rx Calibration Commands:
- *
- * With the uCode used for open source drivers, most Tx calibration (except
- * for Tx Power) and most Rx calibration is done by uCode during the
- * "initialize" phase of uCode boot.  Driver must calibrate only:
- *
- * 1)  Tx power (depends on temperature), described elsewhere
- * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
- * 3)  Receiver sensitivity (to optimize signal detection)
- *
- *****************************************************************************/
-
-/**
- * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
- *
- * This command sets up the Rx signal detector for a sensitivity level that
- * is high enough to lock onto all signals within the associated network,
- * but low enough to ignore signals that are below a certain threshold, so as
- * not to have too many "false alarms".  False alarms are signals that the
- * Rx DSP tries to lock onto, but then discards after determining that they
- * are noise.
- *
- * The optimum number of false alarms is between 5 and 50 per 200 TUs
- * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
- * time listening, not transmitting).  Driver must adjust sensitivity so that
- * the ratio of actual false alarms to actual Rx time falls within this range.
- *
- * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
- * received beacon.  These provide information to the driver to analyze the
- * sensitivity.  Don't analyze statistics that come in from scanning, or any
- * other non-associated-network source.  Pertinent statistics include:
- *
- * From "general" statistics (struct statistics_rx_non_phy):
- *
- * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
- *   Measure of energy of desired signal.  Used for establishing a level
- *   below which the device does not detect signals.
- *
- * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
- *   Measure of background noise in silent period after beacon.
- *
- * channel_load
- *   uSecs of actual Rx time during beacon period (varies according to
- *   how much time was spent transmitting).
- *
- * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
- *
- * false_alarm_cnt
- *   Signal locks abandoned early (before phy-level header).
- *
- * plcp_err
- *   Signal locks abandoned late (during phy-level header).
- *
- * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
- *        beacon to beacon, i.e. each value is an accumulation of all errors
- *        before and including the latest beacon.  Values will wrap around to 0
- *        after counting up to 2^32 - 1.  Driver must differentiate vs.
- *        previous beacon's values to determine # false alarms in the current
- *        beacon period.
- *
- * Total number of false alarms = false_alarms + plcp_errs
- *
- * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for OFDM are at or close to settings for
- * maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
- *
- *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
- *   by *adding* 1 to all 4 of the table entries above, up to the max for
- *   each entry.  Conversely, if false alarm rate is too low (less than 5
- *   for each 204.8 msecs listening), *subtract* 1 from each entry to
- *   increase sensitivity.
- *
- * For CCK sensitivity, keep track of the following:
- *
- *   1).  20-beacon history of maximum background noise, indicated by
- *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
- *        3 receivers.  For any given beacon, the "silence reference" is
- *        the maximum of last 60 samples (20 beacons * 3 receivers).
- *
- *   2).  10-beacon history of strongest signal level, as indicated
- *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
- *        i.e. the strength of the signal through the best receiver at the
- *        moment.  These measurements are "upside down", with lower values
- *        for stronger signals, so max energy will be *minimum* value.
- *
- *        Then for any given beacon, the driver must determine the *weakest*
- *        of the strongest signals; this is the minimum level that needs to be
- *        successfully detected, when using the best receiver at the moment.
- *        "Max cck energy" is the maximum (higher value means lower energy!)
- *        of the last 10 minima.  Once this is determined, driver must add
- *        a little margin by adding "6" to it.
- *
- *   3).  Number of consecutive beacon periods with too few false alarms.
- *        Reset this to 0 at the first beacon period that falls within the
- *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
- *
- * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for CCK are at maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
- *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), method for reducing
- *   sensitivity is:
- *
- *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       up to max 400.
- *
- *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
- *       sensitivity has been reduced a significant amount; bring it up to
- *       a moderate 161.  Otherwise, *add* 3, up to max 200.
- *
- *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
- *       sensitivity has been reduced only a moderate or small amount;
- *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
- *       down to min 0.  Otherwise (if gain has been significantly reduced),
- *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
- *
- *       b)  Save a snapshot of the "silence reference".
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too low
- *   (less than 5 for each 204.8 msecs listening), method for increasing
- *   sensitivity is used only if:
- *
- *   1a)  Previous beacon did not have too many false alarms
- *   1b)  AND difference between previous "silence reference" and current
- *        "silence reference" (prev - current) is 2 or more,
- *   OR 2)  100 or more consecutive beacon periods have had rate of
- *          less than 5 false alarms per 204.8 milliseconds rx time.
- *
- *   Method for increasing sensitivity:
- *
- *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
- *       down to min 125.
- *
- *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       down to min 200.
- *
- *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
- *   (between 5 and 50 for each 204.8 msecs listening):
- *
- *   1)  Save a snapshot of the silence reference.
- *
- *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
- *       give some extra margin to energy threshold by *subtracting* 8
- *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
- *
- *   For all cases (too few, too many, good range), make sure that the CCK
- *   detection threshold (energy) is below the energy level for robust
- *   detection over the past 10 beacon periods, the "Max cck energy".
- *   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".
- *
- */
-
-/*
- * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
- */
-#define HD_TABLE_SIZE  (11)    /* number of entries */
-#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)        /* table indexes */
-#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
-#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
-#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
-#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
-
-/*
- * Additional table entries in enhance SENSITIVITY_CMD
- */
-#define HD_INA_NON_SQUARE_DET_OFDM_INDEX               (11)
-#define HD_INA_NON_SQUARE_DET_CCK_INDEX                        (12)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX          (13)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX         (14)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX     (15)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX             (16)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX         (17)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX          (18)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX      (19)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_INDEX              (20)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX          (21)
-#define HD_RESERVED                                    (22)
-
-/* number of entries for enhanced tbl */
-#define ENHANCE_HD_TABLE_SIZE  (23)
-
-/* number of additional entries for enhanced tbl */
-#define ENHANCE_HD_TABLE_ENTRIES  (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE)
-
-#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1             cpu_to_le16(0)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1              cpu_to_le16(0)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1                cpu_to_le16(0)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1       cpu_to_le16(668)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1   cpu_to_le16(4)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1           cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1       cpu_to_le16(37)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1                cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1    cpu_to_le16(4)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1            cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1                cpu_to_le16(99)
-
-#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2             cpu_to_le16(1)
-#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2              cpu_to_le16(1)
-#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2                cpu_to_le16(1)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2       cpu_to_le16(600)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2   cpu_to_le16(40)
-#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2           cpu_to_le16(486)
-#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2       cpu_to_le16(45)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2                cpu_to_le16(853)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2    cpu_to_le16(60)
-#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2            cpu_to_le16(476)
-#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2                cpu_to_le16(99)
-
-
-/* Control field in struct iwl_sensitivity_cmd */
-#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE  cpu_to_le16(0)
-#define SENSITIVITY_CMD_CONTROL_WORK_TABLE     cpu_to_le16(1)
-
-/**
- * struct iwl_sensitivity_cmd
- * @control:  (1) updates working table, (0) updates default table
- * @table:  energy threshold values, use HD_* as index into table
- *
- * Always use "1" in "control" to update uCode's working table and DSP.
- */
-struct iwl_sensitivity_cmd {
-       __le16 control;                 /* always use "1" */
-       __le16 table[HD_TABLE_SIZE];    /* use HD_* as index */
-} __packed;
-
-/*
- *
- */
-struct iwl_enhance_sensitivity_cmd {
-       __le16 control;                 /* always use "1" */
-       __le16 enhance_table[ENHANCE_HD_TABLE_SIZE];    /* use HD_* as index */
-} __packed;
-
-
-/**
- * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
- *
- * This command sets the relative gains of agn device's 3 radio receiver chains.
- *
- * After the first association, driver should accumulate signal and noise
- * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
- * beacons from the associated network (don't collect statistics that come
- * in from scanning, or any other non-network source).
- *
- * DISCONNECTED ANTENNA:
- *
- * Driver should determine which antennas are actually connected, by comparing
- * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
- * following values over 20 beacons, one accumulator for each of the chains
- * a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the strongest signal from among a/b/c.  Compare the other two to the
- * strongest.  If any signal is more than 15 dB (times 20, unless you
- * divide the accumulated values by 20) below the strongest, the driver
- * considers that antenna to be disconnected, and should not try to use that
- * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
- * driver should declare the stronger one as connected, and attempt to use it
- * (A and B are the only 2 Tx chains!).
- *
- *
- * RX BALANCE:
- *
- * Driver should balance the 3 receivers (but just the ones that are connected
- * to antennas, see above) for gain, by comparing the average signal levels
- * detected during the silence after each beacon (background noise).
- * Accumulate (add) the following values over 20 beacons, one accumulator for
- * each of the chains a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the weakest background noise level from among a/b/c.  This Rx chain
- * will be the reference, with 0 gain adjustment.  Attenuate other channels by
- * finding noise difference:
- *
- * (accum_noise[i] - accum_noise[reference]) / 30
- *
- * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
- * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
- * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
- * and set bit 2 to indicate "reduce gain".  The value for the reference
- * (weakest) chain should be "0".
- *
- * diff_gain_[abc] bit fields:
- *   2: (1) reduce gain, (0) increase gain
- * 1-0: amount of gain, units of 1.5 dB
- */
-
-/* Phy calibration command for series */
-enum {
-       IWL_PHY_CALIBRATE_DC_CMD                = 8,
-       IWL_PHY_CALIBRATE_LO_CMD                = 9,
-       IWL_PHY_CALIBRATE_TX_IQ_CMD             = 11,
-       IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD       = 15,
-       IWL_PHY_CALIBRATE_BASE_BAND_CMD         = 16,
-       IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD        = 17,
-       IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD       = 18,
-};
-
-/* This enum defines the bitmap of various calibrations to enable in both
- * init ucode and runtime ucode through CALIBRATION_CFG_CMD.
- */
-enum iwl_ucode_calib_cfg {
-       IWL_CALIB_CFG_RX_BB_IDX                 = BIT(0),
-       IWL_CALIB_CFG_DC_IDX                    = BIT(1),
-       IWL_CALIB_CFG_LO_IDX                    = BIT(2),
-       IWL_CALIB_CFG_TX_IQ_IDX                 = BIT(3),
-       IWL_CALIB_CFG_RX_IQ_IDX                 = BIT(4),
-       IWL_CALIB_CFG_NOISE_IDX                 = BIT(5),
-       IWL_CALIB_CFG_CRYSTAL_IDX               = BIT(6),
-       IWL_CALIB_CFG_TEMPERATURE_IDX           = BIT(7),
-       IWL_CALIB_CFG_PAPD_IDX                  = BIT(8),
-       IWL_CALIB_CFG_SENSITIVITY_IDX           = BIT(9),
-       IWL_CALIB_CFG_TX_PWR_IDX                = BIT(10),
-};
-
-#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |   \
-                                       IWL_CALIB_CFG_DC_IDX |          \
-                                       IWL_CALIB_CFG_LO_IDX |          \
-                                       IWL_CALIB_CFG_TX_IQ_IDX |       \
-                                       IWL_CALIB_CFG_RX_IQ_IDX |       \
-                                       IWL_CALIB_CFG_CRYSTAL_IDX)
-
-#define IWL_CALIB_RT_CFG_ALL   cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX |   \
-                                       IWL_CALIB_CFG_DC_IDX |          \
-                                       IWL_CALIB_CFG_LO_IDX |          \
-                                       IWL_CALIB_CFG_TX_IQ_IDX |       \
-                                       IWL_CALIB_CFG_RX_IQ_IDX |       \
-                                       IWL_CALIB_CFG_TEMPERATURE_IDX | \
-                                       IWL_CALIB_CFG_PAPD_IDX |        \
-                                       IWL_CALIB_CFG_TX_PWR_IDX |      \
-                                       IWL_CALIB_CFG_CRYSTAL_IDX)
-
-#define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK      cpu_to_le32(BIT(0))
-
-struct iwl_calib_cfg_elmnt_s {
-       __le32 is_enable;
-       __le32 start;
-       __le32 send_res;
-       __le32 apply_res;
-       __le32 reserved;
-} __packed;
-
-struct iwl_calib_cfg_status_s {
-       struct iwl_calib_cfg_elmnt_s once;
-       struct iwl_calib_cfg_elmnt_s perd;
-       __le32 flags;
-} __packed;
-
-struct iwl_calib_cfg_cmd {
-       struct iwl_calib_cfg_status_s ucd_calib_cfg;
-       struct iwl_calib_cfg_status_s drv_calib_cfg;
-       __le32 reserved1;
-} __packed;
-
-struct iwl_calib_hdr {
-       u8 op_code;
-       u8 first_group;
-       u8 groups_num;
-       u8 data_valid;
-} __packed;
-
-struct iwl_calib_cmd {
-       struct iwl_calib_hdr hdr;
-       u8 data[0];
-} __packed;
-
-struct iwl_calib_xtal_freq_cmd {
-       struct iwl_calib_hdr hdr;
-       u8 cap_pin1;
-       u8 cap_pin2;
-       u8 pad[2];
-} __packed;
-
-#define DEFAULT_RADIO_SENSOR_OFFSET    cpu_to_le16(2700)
-struct iwl_calib_temperature_offset_cmd {
-       struct iwl_calib_hdr hdr;
-       __le16 radio_sensor_offset;
-       __le16 reserved;
-} __packed;
-
-struct iwl_calib_temperature_offset_v2_cmd {
-       struct iwl_calib_hdr hdr;
-       __le16 radio_sensor_offset_high;
-       __le16 radio_sensor_offset_low;
-       __le16 burntVoltageRef;
-       __le16 reserved;
-} __packed;
-
-/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
-struct iwl_calib_chain_noise_reset_cmd {
-       struct iwl_calib_hdr hdr;
-       u8 data[0];
-};
-
-/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
-struct iwl_calib_chain_noise_gain_cmd {
-       struct iwl_calib_hdr hdr;
-       u8 delta_gain_1;
-       u8 delta_gain_2;
-       u8 pad[2];
-} __packed;
-
-/******************************************************************************
- * (12)
- * Miscellaneous Commands:
- *
- *****************************************************************************/
-
-/*
- * LEDs Command & Response
- * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
- *
- * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
- * this command turns it on or off, or sets up a periodic blinking cycle.
- */
-struct iwl_led_cmd {
-       __le32 interval;        /* "interval" in uSec */
-       u8 id;                  /* 1: Activity, 2: Link, 3: Tech */
-       u8 off;                 /* # intervals off while blinking;
-                                * "0", with >0 "on" value, turns LED on */
-       u8 on;                  /* # intervals on while blinking;
-                                * "0", regardless of "off", turns LED off */
-       u8 reserved;
-} __packed;
-
-/*
- * station priority table entries
- * also used as potential "events" value for both
- * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD
- */
-
-/*
- * COEX events entry flag masks
- * RP - Requested Priority
- * WP - Win Medium Priority: priority assigned when the contention has been won
- */
-#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG        (0x1)
-#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG        (0x2)
-#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG  (0x4)
-
-#define COEX_CU_UNASSOC_IDLE_RP               4
-#define COEX_CU_UNASSOC_MANUAL_SCAN_RP        4
-#define COEX_CU_UNASSOC_AUTO_SCAN_RP          4
-#define COEX_CU_CALIBRATION_RP                4
-#define COEX_CU_PERIODIC_CALIBRATION_RP       4
-#define COEX_CU_CONNECTION_ESTAB_RP           4
-#define COEX_CU_ASSOCIATED_IDLE_RP            4
-#define COEX_CU_ASSOC_MANUAL_SCAN_RP          4
-#define COEX_CU_ASSOC_AUTO_SCAN_RP            4
-#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP         4
-#define COEX_CU_RF_ON_RP                      6
-#define COEX_CU_RF_OFF_RP                     4
-#define COEX_CU_STAND_ALONE_DEBUG_RP          6
-#define COEX_CU_IPAN_ASSOC_LEVEL_RP           4
-#define COEX_CU_RSRVD1_RP                     4
-#define COEX_CU_RSRVD2_RP                     4
-
-#define COEX_CU_UNASSOC_IDLE_WP               3
-#define COEX_CU_UNASSOC_MANUAL_SCAN_WP        3
-#define COEX_CU_UNASSOC_AUTO_SCAN_WP          3
-#define COEX_CU_CALIBRATION_WP                3
-#define COEX_CU_PERIODIC_CALIBRATION_WP       3
-#define COEX_CU_CONNECTION_ESTAB_WP           3
-#define COEX_CU_ASSOCIATED_IDLE_WP            3
-#define COEX_CU_ASSOC_MANUAL_SCAN_WP          3
-#define COEX_CU_ASSOC_AUTO_SCAN_WP            3
-#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP         3
-#define COEX_CU_RF_ON_WP                      3
-#define COEX_CU_RF_OFF_WP                     3
-#define COEX_CU_STAND_ALONE_DEBUG_WP          6
-#define COEX_CU_IPAN_ASSOC_LEVEL_WP           3
-#define COEX_CU_RSRVD1_WP                     3
-#define COEX_CU_RSRVD2_WP                     3
-
-#define COEX_UNASSOC_IDLE_FLAGS                     0
-#define COEX_UNASSOC_MANUAL_SCAN_FLAGS         \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_UNASSOC_AUTO_SCAN_FLAGS           \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_CALIBRATION_FLAGS                 \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_PERIODIC_CALIBRATION_FLAGS             0
-/*
- * COEX_CONNECTION_ESTAB:
- * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
- */
-#define COEX_CONNECTION_ESTAB_FLAGS            \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |    \
-       COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-#define COEX_ASSOCIATED_IDLE_FLAGS                  0
-#define COEX_ASSOC_MANUAL_SCAN_FLAGS           \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-       COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_ASSOC_AUTO_SCAN_FLAGS             \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS               0
-#define COEX_RF_ON_FLAGS                            0
-#define COEX_RF_OFF_FLAGS                           0
-#define COEX_STAND_ALONE_DEBUG_FLAGS           \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG)
-#define COEX_IPAN_ASSOC_LEVEL_FLAGS            \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |   \
-        COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-#define COEX_RSRVD1_FLAGS                           0
-#define COEX_RSRVD2_FLAGS                           0
-/*
- * COEX_CU_RF_ON is the event wrapping all radio ownership.
- * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network.
- */
-#define COEX_CU_RF_ON_FLAGS                    \
-       (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG |   \
-        COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG |   \
-        COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG)
-
-
-enum {
-       /* un-association part */
-       COEX_UNASSOC_IDLE               = 0,
-       COEX_UNASSOC_MANUAL_SCAN        = 1,
-       COEX_UNASSOC_AUTO_SCAN          = 2,
-       /* calibration */
-       COEX_CALIBRATION                = 3,
-       COEX_PERIODIC_CALIBRATION       = 4,
-       /* connection */
-       COEX_CONNECTION_ESTAB           = 5,
-       /* association part */
-       COEX_ASSOCIATED_IDLE            = 6,
-       COEX_ASSOC_MANUAL_SCAN          = 7,
-       COEX_ASSOC_AUTO_SCAN            = 8,
-       COEX_ASSOC_ACTIVE_LEVEL         = 9,
-       /* RF ON/OFF */
-       COEX_RF_ON                      = 10,
-       COEX_RF_OFF                     = 11,
-       COEX_STAND_ALONE_DEBUG          = 12,
-       /* IPAN */
-       COEX_IPAN_ASSOC_LEVEL           = 13,
-       /* reserved */
-       COEX_RSRVD1                     = 14,
-       COEX_RSRVD2                     = 15,
-       COEX_NUM_OF_EVENTS              = 16
-};
-
-/*
- * Coexistence WIFI/WIMAX  Command
- * COEX_PRIORITY_TABLE_CMD = 0x5a
- *
- */
-struct iwl_wimax_coex_event_entry {
-       u8 request_prio;
-       u8 win_medium_prio;
-       u8 reserved;
-       u8 flags;
-} __packed;
-
-/* COEX flag masks */
-
-/* Station table is valid */
-#define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
-/* UnMask wake up src at unassociated sleep */
-#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
-/* UnMask wake up src at associated sleep */
-#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
-/* Enable CoEx feature. */
-#define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
-
-struct iwl_wimax_coex_cmd {
-       u8 flags;
-       u8 reserved[3];
-       struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
-} __packed;
-
-/*
- * Coexistence MEDIUM NOTIFICATION
- * COEX_MEDIUM_NOTIFICATION = 0x5b
- *
- * notification from uCode to host to indicate medium changes
- *
- */
-/*
- * status field
- * bit 0 - 2: medium status
- * bit 3: medium change indication
- * bit 4 - 31: reserved
- */
-/* status option values, (0 - 2 bits) */
-#define COEX_MEDIUM_BUSY       (0x0) /* radio belongs to WiMAX */
-#define COEX_MEDIUM_ACTIVE     (0x1) /* radio belongs to WiFi */
-#define COEX_MEDIUM_PRE_RELEASE        (0x2) /* received radio release */
-#define COEX_MEDIUM_MSK                (0x7)
-
-/* send notification status (1 bit) */
-#define COEX_MEDIUM_CHANGED    (0x8)
-#define COEX_MEDIUM_CHANGED_MSK        (0x8)
-#define COEX_MEDIUM_SHIFT      (3)
-
-struct iwl_coex_medium_notification {
-       __le32 status;
-       __le32 events;
-} __packed;
-
-/*
- * Coexistence EVENT  Command
- * COEX_EVENT_CMD = 0x5c
- *
- * send from host to uCode for coex event request.
- */
-/* flags options */
-#define COEX_EVENT_REQUEST_MSK (0x1)
-
-struct iwl_coex_event_cmd {
-       u8 flags;
-       u8 event;
-       __le16 reserved;
-} __packed;
-
-struct iwl_coex_event_resp {
-       __le32 status;
-} __packed;
-
-
-/******************************************************************************
- * Bluetooth Coexistence commands
- *
- *****************************************************************************/
-
-/*
- * BT Status notification
- * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
- */
-enum iwl_bt_coex_profile_traffic_load {
-       IWL_BT_COEX_TRAFFIC_LOAD_NONE =         0,
-       IWL_BT_COEX_TRAFFIC_LOAD_LOW =          1,
-       IWL_BT_COEX_TRAFFIC_LOAD_HIGH =         2,
-       IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =   3,
-/*
- * There are no more even though below is a u8, the
- * indication from the BT device only has two bits.
- */
-};
-
-#define BT_SESSION_ACTIVITY_1_UART_MSG         0x1
-#define BT_SESSION_ACTIVITY_2_UART_MSG         0x2
-
-/* BT UART message - Share Part (BT -> WiFi) */
-#define BT_UART_MSG_FRAME1MSGTYPE_POS          (0)
-#define BT_UART_MSG_FRAME1MSGTYPE_MSK          \
-               (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
-#define BT_UART_MSG_FRAME1SSN_POS              (3)
-#define BT_UART_MSG_FRAME1SSN_MSK              \
-               (0x3 << BT_UART_MSG_FRAME1SSN_POS)
-#define BT_UART_MSG_FRAME1UPDATEREQ_POS                (5)
-#define BT_UART_MSG_FRAME1UPDATEREQ_MSK                \
-               (0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
-#define BT_UART_MSG_FRAME1RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME1RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
-
-#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS  (0)
-#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK  \
-               (0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
-#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS      (2)
-#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK      \
-               (0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
-#define BT_UART_MSG_FRAME2CHLSEQN_POS          (4)
-#define BT_UART_MSG_FRAME2CHLSEQN_MSK          \
-               (0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
-#define BT_UART_MSG_FRAME2INBAND_POS           (5)
-#define BT_UART_MSG_FRAME2INBAND_MSK           \
-               (0x1 << BT_UART_MSG_FRAME2INBAND_POS)
-#define BT_UART_MSG_FRAME2RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME2RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
-
-#define BT_UART_MSG_FRAME3SCOESCO_POS          (0)
-#define BT_UART_MSG_FRAME3SCOESCO_MSK          \
-               (0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
-#define BT_UART_MSG_FRAME3SNIFF_POS            (1)
-#define BT_UART_MSG_FRAME3SNIFF_MSK            \
-               (0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
-#define BT_UART_MSG_FRAME3A2DP_POS             (2)
-#define BT_UART_MSG_FRAME3A2DP_MSK             \
-               (0x1 << BT_UART_MSG_FRAME3A2DP_POS)
-#define BT_UART_MSG_FRAME3ACL_POS              (3)
-#define BT_UART_MSG_FRAME3ACL_MSK              \
-               (0x1 << BT_UART_MSG_FRAME3ACL_POS)
-#define BT_UART_MSG_FRAME3MASTER_POS           (4)
-#define BT_UART_MSG_FRAME3MASTER_MSK           \
-               (0x1 << BT_UART_MSG_FRAME3MASTER_POS)
-#define BT_UART_MSG_FRAME3OBEX_POS             (5)
-#define BT_UART_MSG_FRAME3OBEX_MSK             \
-               (0x1 << BT_UART_MSG_FRAME3OBEX_POS)
-#define BT_UART_MSG_FRAME3RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME3RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
-
-#define BT_UART_MSG_FRAME4IDLEDURATION_POS     (0)
-#define BT_UART_MSG_FRAME4IDLEDURATION_MSK     \
-               (0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
-#define BT_UART_MSG_FRAME4RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME4RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
-
-#define BT_UART_MSG_FRAME5TXACTIVITY_POS       (0)
-#define BT_UART_MSG_FRAME5TXACTIVITY_MSK       \
-               (0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
-#define BT_UART_MSG_FRAME5RXACTIVITY_POS       (2)
-#define BT_UART_MSG_FRAME5RXACTIVITY_MSK       \
-               (0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
-#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS   (4)
-#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK   \
-               (0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
-#define BT_UART_MSG_FRAME5RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME5RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
-
-#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS    (0)
-#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK    \
-               (0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
-#define BT_UART_MSG_FRAME6DISCOVERABLE_POS     (5)
-#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK     \
-               (0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
-#define BT_UART_MSG_FRAME6RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME6RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
-
-#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS    (0)
-#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK    \
-               (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
-#define BT_UART_MSG_FRAME7PAGE_POS             (3)
-#define BT_UART_MSG_FRAME7PAGE_MSK             \
-               (0x1 << BT_UART_MSG_FRAME7PAGE_POS)
-#define BT_UART_MSG_FRAME7INQUIRY_POS          (4)
-#define BT_UART_MSG_FRAME7INQUIRY_MSK          \
-               (0x1 << BT_UART_MSG_FRAME7INQUIRY_POS)
-#define BT_UART_MSG_FRAME7CONNECTABLE_POS      (5)
-#define BT_UART_MSG_FRAME7CONNECTABLE_MSK      \
-               (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
-#define BT_UART_MSG_FRAME7RESERVED_POS         (6)
-#define BT_UART_MSG_FRAME7RESERVED_MSK         \
-               (0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
-
-/* BT Session Activity 2 UART message (BT -> WiFi) */
-#define BT_UART_MSG_2_FRAME1RESERVED1_POS      (5)
-#define BT_UART_MSG_2_FRAME1RESERVED1_MSK      \
-               (0x1<<BT_UART_MSG_2_FRAME1RESERVED1_POS)
-#define BT_UART_MSG_2_FRAME1RESERVED2_POS      (6)
-#define BT_UART_MSG_2_FRAME1RESERVED2_MSK      \
-               (0x3<<BT_UART_MSG_2_FRAME1RESERVED2_POS)
-
-#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS (0)
-#define BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_MSK \
-               (0x3F<<BT_UART_MSG_2_FRAME2AGGTRAFFICLOAD_POS)
-#define BT_UART_MSG_2_FRAME2RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME2RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME2RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS  (0)
-#define BT_UART_MSG_2_FRAME3BRLASTTXPOWER_MSK  \
-               (0xF<<BT_UART_MSG_2_FRAME3BRLASTTXPOWER_POS)
-#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS  (4)
-#define BT_UART_MSG_2_FRAME3INQPAGESRMODE_MSK  \
-               (0x1<<BT_UART_MSG_2_FRAME3INQPAGESRMODE_POS)
-#define BT_UART_MSG_2_FRAME3LEMASTER_POS       (5)
-#define BT_UART_MSG_2_FRAME3LEMASTER_MSK       \
-               (0x1<<BT_UART_MSG_2_FRAME3LEMASTER_POS)
-#define BT_UART_MSG_2_FRAME3RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME3RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME3RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS  (0)
-#define BT_UART_MSG_2_FRAME4LELASTTXPOWER_MSK  \
-               (0xF<<BT_UART_MSG_2_FRAME4LELASTTXPOWER_POS)
-#define BT_UART_MSG_2_FRAME4NUMLECONN_POS      (4)
-#define BT_UART_MSG_2_FRAME4NUMLECONN_MSK      \
-               (0x3<<BT_UART_MSG_2_FRAME4NUMLECONN_POS)
-#define BT_UART_MSG_2_FRAME4RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME4RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME4RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME5BTMINRSSI_POS      (0)
-#define BT_UART_MSG_2_FRAME5BTMINRSSI_MSK      \
-               (0xF<<BT_UART_MSG_2_FRAME5BTMINRSSI_POS)
-#define BT_UART_MSG_2_FRAME5LESCANINITMODE_POS (4)
-#define BT_UART_MSG_2_FRAME5LESCANINITMODE_MSK \
-               (0x1<<BT_UART_MSG_2_FRAME5LESCANINITMODE_POS)
-#define BT_UART_MSG_2_FRAME5LEADVERMODE_POS    (5)
-#define BT_UART_MSG_2_FRAME5LEADVERMODE_MSK    \
-               (0x1<<BT_UART_MSG_2_FRAME5LEADVERMODE_POS)
-#define BT_UART_MSG_2_FRAME5RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME5RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME5RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS (0)
-#define BT_UART_MSG_2_FRAME6LECONNINTERVAL_MSK \
-               (0x1F<<BT_UART_MSG_2_FRAME6LECONNINTERVAL_POS)
-#define BT_UART_MSG_2_FRAME6RFU_POS            (5)
-#define BT_UART_MSG_2_FRAME6RFU_MSK            \
-               (0x1<<BT_UART_MSG_2_FRAME6RFU_POS)
-#define BT_UART_MSG_2_FRAME6RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME6RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME6RESERVED_POS)
-
-#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS (0)
-#define BT_UART_MSG_2_FRAME7LECONNSLAVELAT_MSK \
-               (0x7<<BT_UART_MSG_2_FRAME7LECONNSLAVELAT_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILE1_POS     (3)
-#define BT_UART_MSG_2_FRAME7LEPROFILE1_MSK     \
-               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE1_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILE2_POS     (4)
-#define BT_UART_MSG_2_FRAME7LEPROFILE2_MSK     \
-               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILE2_POS)
-#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS (5)
-#define BT_UART_MSG_2_FRAME7LEPROFILEOTHER_MSK \
-               (0x1<<BT_UART_MSG_2_FRAME7LEPROFILEOTHER_POS)
-#define BT_UART_MSG_2_FRAME7RESERVED_POS       (6)
-#define BT_UART_MSG_2_FRAME7RESERVED_MSK       \
-               (0x3<<BT_UART_MSG_2_FRAME7RESERVED_POS)
-
-
-#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD    (-62)
-#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD   (-65)
-
-struct iwl_bt_uart_msg {
-       u8 header;
-       u8 frame1;
-       u8 frame2;
-       u8 frame3;
-       u8 frame4;
-       u8 frame5;
-       u8 frame6;
-       u8 frame7;
-} __attribute__((packed));
-
-struct iwl_bt_coex_profile_notif {
-       struct iwl_bt_uart_msg last_bt_uart_msg;
-       u8 bt_status; /* 0 - off, 1 - on */
-       u8 bt_traffic_load; /* 0 .. 3? */
-       u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
-       u8 reserved;
-} __attribute__((packed));
-
-#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS        0
-#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK        0x1
-#define IWL_BT_COEX_PRIO_TBL_PRIO_POS          1
-#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK         0x0e
-#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS      4
-#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK     0xf0
-#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT                1
-
-/*
- * BT Coexistence Priority table
- * REPLY_BT_COEX_PRIO_TABLE = 0xcc
- */
-enum bt_coex_prio_table_events {
-       BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
-       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
-       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
-       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
-       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
-       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
-       BT_COEX_PRIO_TBL_EVT_DTIM = 6,
-       BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
-       BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
-       BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
-       BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
-       BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
-       BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
-       BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
-       BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
-       BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
-       /* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
-       BT_COEX_PRIO_TBL_EVT_MAX,
-};
-
-enum bt_coex_prio_table_priorities {
-       BT_COEX_PRIO_TBL_DISABLED = 0,
-       BT_COEX_PRIO_TBL_PRIO_LOW = 1,
-       BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
-       BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
-       BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
-       BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
-       BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
-       BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
-       BT_COEX_PRIO_TBL_MAX,
-};
-
-struct iwl_bt_coex_prio_table_cmd {
-       u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
-} __attribute__((packed));
-
-#define IWL_BT_COEX_ENV_CLOSE  0
-#define IWL_BT_COEX_ENV_OPEN   1
-/*
- * BT Protection Envelope
- * REPLY_BT_COEX_PROT_ENV = 0xcd
- */
-struct iwl_bt_coex_prot_env_cmd {
-       u8 action; /* 0 = closed, 1 = open */
-       u8 type; /* 0 .. 15 */
-       u8 reserved[2];
-} __attribute__((packed));
-
-/*
- * REPLY_D3_CONFIG
- */
-enum iwlagn_d3_wakeup_filters {
-       IWLAGN_D3_WAKEUP_RFKILL         = BIT(0),
-       IWLAGN_D3_WAKEUP_SYSASSERT      = BIT(1),
-};
-
-struct iwlagn_d3_config_cmd {
-       __le32 min_sleep_time;
-       __le32 wakeup_flags;
-} __packed;
-
-/*
- * REPLY_WOWLAN_PATTERNS
- */
-#define IWLAGN_WOWLAN_MIN_PATTERN_LEN  16
-#define IWLAGN_WOWLAN_MAX_PATTERN_LEN  128
-
-struct iwlagn_wowlan_pattern {
-       u8 mask[IWLAGN_WOWLAN_MAX_PATTERN_LEN / 8];
-       u8 pattern[IWLAGN_WOWLAN_MAX_PATTERN_LEN];
-       u8 mask_size;
-       u8 pattern_size;
-       __le16 reserved;
-} __packed;
-
-#define IWLAGN_WOWLAN_MAX_PATTERNS     20
-
-struct iwlagn_wowlan_patterns_cmd {
-       __le32 n_patterns;
-       struct iwlagn_wowlan_pattern patterns[];
-} __packed;
-
-/*
- * REPLY_WOWLAN_WAKEUP_FILTER
- */
-enum iwlagn_wowlan_wakeup_filters {
-       IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET       = BIT(0),
-       IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH      = BIT(1),
-       IWLAGN_WOWLAN_WAKEUP_BEACON_MISS        = BIT(2),
-       IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE        = BIT(3),
-       IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL     = BIT(4),
-       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(5),
-       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(6),
-       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(7),
-       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(8),
-};
-
-struct iwlagn_wowlan_wakeup_filter_cmd {
-       __le32 enabled;
-       __le16 non_qos_seq;
-       __le16 reserved;
-       __le16 qos_seq[8];
-};
-
-/*
- * REPLY_WOWLAN_TSC_RSC_PARAMS
- */
-#define IWLAGN_NUM_RSC 16
-
-struct tkip_sc {
-       __le16 iv16;
-       __le16 pad;
-       __le32 iv32;
-} __packed;
-
-struct iwlagn_tkip_rsc_tsc {
-       struct tkip_sc unicast_rsc[IWLAGN_NUM_RSC];
-       struct tkip_sc multicast_rsc[IWLAGN_NUM_RSC];
-       struct tkip_sc tsc;
-} __packed;
-
-struct aes_sc {
-       __le64 pn;
-} __packed;
-
-struct iwlagn_aes_rsc_tsc {
-       struct aes_sc unicast_rsc[IWLAGN_NUM_RSC];
-       struct aes_sc multicast_rsc[IWLAGN_NUM_RSC];
-       struct aes_sc tsc;
-} __packed;
-
-union iwlagn_all_tsc_rsc {
-       struct iwlagn_tkip_rsc_tsc tkip;
-       struct iwlagn_aes_rsc_tsc aes;
-};
-
-struct iwlagn_wowlan_rsc_tsc_params_cmd {
-       union iwlagn_all_tsc_rsc all_tsc_rsc;
-} __packed;
-
-/*
- * REPLY_WOWLAN_TKIP_PARAMS
- */
-#define IWLAGN_MIC_KEY_SIZE    8
-#define IWLAGN_P1K_SIZE                5
-struct iwlagn_mic_keys {
-       u8 tx[IWLAGN_MIC_KEY_SIZE];
-       u8 rx_unicast[IWLAGN_MIC_KEY_SIZE];
-       u8 rx_mcast[IWLAGN_MIC_KEY_SIZE];
-} __packed;
-
-struct iwlagn_p1k_cache {
-       __le16 p1k[IWLAGN_P1K_SIZE];
-} __packed;
-
-#define IWLAGN_NUM_RX_P1K_CACHE        2
-
-struct iwlagn_wowlan_tkip_params_cmd {
-       struct iwlagn_mic_keys mic_keys;
-       struct iwlagn_p1k_cache tx;
-       struct iwlagn_p1k_cache rx_uni[IWLAGN_NUM_RX_P1K_CACHE];
-       struct iwlagn_p1k_cache rx_multi[IWLAGN_NUM_RX_P1K_CACHE];
-} __packed;
-
-/*
- * REPLY_WOWLAN_KEK_KCK_MATERIAL
- */
-
-#define IWLAGN_KCK_MAX_SIZE    32
-#define IWLAGN_KEK_MAX_SIZE    32
-
-struct iwlagn_wowlan_kek_kck_material_cmd {
-       u8      kck[IWLAGN_KCK_MAX_SIZE];
-       u8      kek[IWLAGN_KEK_MAX_SIZE];
-       __le16  kck_len;
-       __le16  kek_len;
-       __le64  replay_ctr;
-} __packed;
-
-/*
- * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
- */
-
-/*
- * Minimum slot time in TU
- */
-#define IWL_MIN_SLOT_TIME      20
-
-/**
- * struct iwl_wipan_slot
- * @width: Time in TU
- * @type:
- *   0 - BSS
- *   1 - PAN
- */
-struct iwl_wipan_slot {
-       __le16 width;
-       u8 type;
-       u8 reserved;
-} __packed;
-
-#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS         BIT(1)  /* reserved */
-#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET       BIT(2)  /* reserved */
-#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE              BIT(3)  /* reserved */
-#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF       BIT(4)
-#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE         BIT(5)
-
-/**
- * struct iwl_wipan_params_cmd
- * @flags:
- *   bit0: reserved
- *   bit1: CP leave channel with CTS
- *   bit2: CP leave channel qith Quiet
- *   bit3: slotted mode
- *     1 - work in slotted mode
- *     0 - work in non slotted mode
- *   bit4: filter beacon notification
- *   bit5: full tx slotted mode. if this flag is set,
- *         uCode will perform leaving channel methods in context switch
- *         also when working in same channel mode
- * @num_slots: 1 - 10
- */
-struct iwl_wipan_params_cmd {
-       __le16 flags;
-       u8 reserved;
-       u8 num_slots;
-       struct iwl_wipan_slot slots[10];
-} __packed;
-
-/*
- * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
- *
- * TODO: Figure out what this is used for,
- *      it can only switch between 2.4 GHz
- *      channels!!
- */
-
-struct iwl_wipan_p2p_channel_switch_cmd {
-       __le16 channel;
-       __le16 reserved;
-};
-
-/*
- * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
- *
- * This is used by the device to notify us of the
- * NoA schedule it determined so we can forward it
- * to userspace for inclusion in probe responses.
- *
- * In beacons, the NoA schedule is simply appended
- * to the frame we give the device.
- */
-
-struct iwl_wipan_noa_descriptor {
-       u8 count;
-       __le32 duration;
-       __le32 interval;
-       __le32 starttime;
-} __packed;
-
-struct iwl_wipan_noa_attribute {
-       u8 id;
-       __le16 length;
-       u8 index;
-       u8 ct_window;
-       struct iwl_wipan_noa_descriptor descr0, descr1;
-       u8 reserved;
-} __packed;
-
-struct iwl_wipan_noa_notification {
-       u32 noa_active;
-       struct iwl_wipan_noa_attribute noa_attribute;
-} __packed;
-
-#endif                         /* __iwl_commands_h__ */
index 67b28aa7f9bef79470efa15fc01c3f968ca33edb..10e47938b6355a169faed72edf87ed314ea2eaf0 100644 (file)
@@ -113,7 +113,7 @@ enum iwl_led_mode {
 #define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE     0
 
 /* TX queue watchdog timeouts in mSecs */
-#define IWL_WATCHHDOG_DISABLED 0
+#define IWL_WATCHDOG_DISABLED  0
 #define IWL_DEF_WD_TIMEOUT     2000
 #define IWL_LONG_WD_TIMEOUT    10000
 #define IWL_MAX_WD_TIMEOUT     120000
@@ -143,7 +143,7 @@ enum iwl_led_mode {
  * @chain_noise_scale: default chain noise scale used for gain computation
  * @wd_timeout: TX queues watchdog timeout
  * @max_event_log_size: size of event log buffer size for ucode event logging
- * @shadow_reg_enable: HW shadhow register bit
+ * @shadow_reg_enable: HW shadow register support
  * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
  * @no_idle_support: do not support idle mode
  */
@@ -182,13 +182,34 @@ struct iwl_bt_params {
        bool bt_sco_disable;
        bool bt_session_2;
 };
+
 /*
  * @use_rts_for_aggregation: use rts/cts protection for HT traffic
+ * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
  */
 struct iwl_ht_params {
+       enum ieee80211_smps_mode smps_mode;
        const bool ht_greenfield_support; /* if used set to true */
        bool use_rts_for_aggregation;
-       enum ieee80211_smps_mode smps_mode;
+       u8 ht40_bands;
+};
+
+/*
+ * information on how to parse the EEPROM
+ */
+#define EEPROM_REG_BAND_1_CHANNELS             0x08
+#define EEPROM_REG_BAND_2_CHANNELS             0x26
+#define EEPROM_REG_BAND_3_CHANNELS             0x42
+#define EEPROM_REG_BAND_4_CHANNELS             0x5C
+#define EEPROM_REG_BAND_5_CHANNELS             0x74
+#define EEPROM_REG_BAND_24_HT40_CHANNELS       0x82
+#define EEPROM_REG_BAND_52_HT40_CHANNELS       0x92
+#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS  0x80
+#define EEPROM_REGULATORY_BAND_NO_HT40         0
+
+struct iwl_eeprom_params {
+       const u8 regulatory_bands[7];
+       bool enhanced_txpower;
 };
 
 /**
@@ -243,6 +264,7 @@ struct iwl_cfg {
        /* params likely to change within a device family */
        const struct iwl_ht_params *ht_params;
        const struct iwl_bt_params *bt_params;
+       const struct iwl_eeprom_params *eeprom_params;
        const bool need_temp_offset_calib; /* if used set to true */
        const bool no_xtal_calib;
        enum iwl_led_mode led_mode;
index 59750543fce7366ce68ccafa7bfeab2c4e923b54..34a5287dfc2f6d1c366e6555a14ee284dad8bd5e 100644 (file)
 /*
  * Hardware revision info
  * Bit fields:
- * 31-8:  Reserved
- *  7-4:  Type of device:  see CSR_HW_REV_TYPE_xxx definitions
+ * 31-16:  Reserved
+ *  15-4:  Type of device:  see CSR_HW_REV_TYPE_xxx definitions
  *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
  *  1-0:  "Dash" (-) value, as in A-1, etc.
- *
- * NOTE:  Revision step affects calculation of CCK txpower for 4965.
- * NOTE:  See also CSR_HW_REV_WA_REG (work-around for bug in 4965).
  */
 #define CSR_HW_REV              (CSR_BASE+0x028)
 
 #define CSR_DBG_LINK_PWR_MGMT_REG      (CSR_BASE+0x250)
 
 /* Bits for CSR_HW_IF_CONFIG_REG */
-#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER     (0x00000C00)
-#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI        (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH      (0x00000003)
+#define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP      (0x0000000C)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER     (0x000000C0)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI                (0x00000100)
 #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI      (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE      (0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH      (0x00003000)
+#define CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP      (0x0000C000)
+
+#define CSR_HW_IF_CONFIG_REG_POS_MAC_DASH      (0)
+#define CSR_HW_IF_CONFIG_REG_POS_MAC_STEP      (2)
+#define CSR_HW_IF_CONFIG_REG_POS_BOARD_VER     (6)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE      (10)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_DASH      (12)
+#define CSR_HW_IF_CONFIG_REG_POS_PHY_STEP      (14)
 
 #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A  (0x00080000)
 #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM        (0x00200000)
 
 
 /* HW REV */
-#define CSR_HW_REV_TYPE_MSK            (0x00001F0)
+#define CSR_HW_REV_DASH(_val)          (((_val) & 0x0000003) >> 0)
+#define CSR_HW_REV_STEP(_val)          (((_val) & 0x000000C) >> 2)
+
+#define CSR_HW_REV_TYPE_MSK            (0x000FFF0)
 #define CSR_HW_REV_TYPE_5300           (0x0000020)
 #define CSR_HW_REV_TYPE_5350           (0x0000030)
 #define CSR_HW_REV_TYPE_5100           (0x0000050)
index 2d1b42847b9bb3f9510bb111757297054cb9bb67..0f8fcd1d4fe2a00a4d5958f4f1ea4cd1f8377420 100644 (file)
@@ -62,6 +62,7 @@
  *****************************************************************************/
 
 #include <linux/interrupt.h>
+#include <linux/export.h>
 #include "iwl-debug.h"
 #include "iwl-devtrace.h"
 
@@ -81,8 +82,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...)   \
 }
 
 __iwl_fn(warn)
+EXPORT_SYMBOL_GPL(__iwl_warn);
 __iwl_fn(info)
+EXPORT_SYMBOL_GPL(__iwl_info);
 __iwl_fn(crit)
+EXPORT_SYMBOL_GPL(__iwl_crit);
 
 void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
                const char *fmt, ...)
@@ -103,6 +107,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
        trace_iwlwifi_err(&vaf);
        va_end(args);
 }
+EXPORT_SYMBOL_GPL(__iwl_err);
 
 #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
 void __iwl_dbg(struct device *dev,
@@ -125,4 +130,5 @@ void __iwl_dbg(struct device *dev,
        trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
        va_end(args);
 }
+EXPORT_SYMBOL_GPL(__iwl_dbg);
 #endif
index 8376b842bdba719bd08df0fb42aea7cf9e497158..42b20b0e83bc379c346251baccbe7087d8377750 100644 (file)
@@ -38,13 +38,14 @@ static inline bool iwl_have_debug_level(u32 level)
 }
 
 void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
-               const char *fmt, ...);
-void __iwl_warn(struct device *dev, const char *fmt, ...);
-void __iwl_info(struct device *dev, const char *fmt, ...);
-void __iwl_crit(struct device *dev, const char *fmt, ...);
+               const char *fmt, ...) __printf(4, 5);
+void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_info(struct device *dev, const char *fmt, ...) __printf(2, 3);
+void __iwl_crit(struct device *dev, const char *fmt, ...) __printf(2, 3);
 
 /* No matter what is m (priv, bus, trans), this will work */
 #define IWL_ERR(m, f, a...) __iwl_err((m)->dev, false, false, f, ## a)
+#define IWL_ERR_DEV(d, f, a...) __iwl_err((d), false, false, f, ## a)
 #define IWL_WARN(m, f, a...) __iwl_warn((m)->dev, f, ## a)
 #define IWL_INFO(m, f, a...) __iwl_info((m)->dev, f, ## a)
 #define IWL_CRIT(m, f, a...) __iwl_crit((m)->dev, f, ## a)
@@ -52,9 +53,9 @@ void __iwl_crit(struct device *dev, const char *fmt, ...);
 #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
 void __iwl_dbg(struct device *dev,
               u32 level, bool limit, const char *function,
-              const char *fmt, ...);
+              const char *fmt, ...) __printf(5, 6);
 #else
-static inline void
+__printf(5, 6) static inline void
 __iwl_dbg(struct device *dev,
          u32 level, bool limit, const char *function,
          const char *fmt, ...)
@@ -69,6 +70,8 @@ do {                                                                  \
 
 #define IWL_DEBUG(m, level, fmt, args...)                              \
        __iwl_dbg((m)->dev, level, false, __func__, fmt, ##args)
+#define IWL_DEBUG_DEV(dev, level, fmt, args...)                                \
+       __iwl_dbg((dev), level, false, __func__, fmt, ##args)
 #define IWL_DEBUG_LIMIT(m, level, fmt, args...)                                \
        __iwl_dbg((m)->dev, level, true, __func__, fmt, ##args)
 
@@ -153,7 +156,7 @@ do {                                                                \
 #define IWL_DEBUG_LED(p, f, a...)      IWL_DEBUG(p, IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(p, f, a...)      IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
 #define IWL_DEBUG_HC(p, f, a...)       IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
-#define IWL_DEBUG_EEPROM(p, f, a...)   IWL_DEBUG(p, IWL_DL_EEPROM, f, ## a)
+#define IWL_DEBUG_EEPROM(d, f, a...)   IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
 #define IWL_DEBUG_CALIB(p, f, a...)    IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
 #define IWL_DEBUG_FW(p, f, a...)       IWL_DEBUG(p, IWL_DL_FW, f, ## a)
 #define IWL_DEBUG_RF_KILL(p, f, a...)  IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
deleted file mode 100644 (file)
index 7f97dec..0000000
+++ /dev/null
@@ -1,2443 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include <linux/ieee80211.h>
-#include <net/mac80211.h>
-
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-modparams.h"
-
-/* create and remove of files */
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
-       if (!debugfs_create_file(#name, mode, parent, priv,             \
-                                &iwl_dbgfs_##name##_ops))              \
-               goto err;                                               \
-} while (0)
-
-#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                       \
-       struct dentry *__tmp;                                           \
-       __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,           \
-                                   parent, ptr);                       \
-       if (IS_ERR(__tmp) || !__tmp)                                    \
-               goto err;                                               \
-} while (0)
-
-#define DEBUGFS_ADD_X32(name, parent, ptr) do {                                \
-       struct dentry *__tmp;                                           \
-       __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,            \
-                                  parent, ptr);                        \
-       if (IS_ERR(__tmp) || !__tmp)                                    \
-               goto err;                                               \
-} while (0)
-
-#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {                  \
-       struct dentry *__tmp;                                           \
-       __tmp = debugfs_create_u32(#name, mode,                         \
-                                  parent, ptr);                        \
-       if (IS_ERR(__tmp) || !__tmp)                                    \
-               goto err;                                               \
-} while (0)
-
-/* file operation */
-#define DEBUGFS_READ_FUNC(name)                                         \
-static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
-                                       char __user *user_buf,          \
-                                       size_t count, loff_t *ppos);
-
-#define DEBUGFS_WRITE_FUNC(name)                                        \
-static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
-                                       const char __user *user_buf,    \
-                                       size_t count, loff_t *ppos);
-
-
-#define DEBUGFS_READ_FILE_OPS(name)                                     \
-       DEBUGFS_READ_FUNC(name);                                        \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-
-#define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
-       DEBUGFS_READ_FUNC(name);                                        \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-static ssize_t iwl_dbgfs_sram_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       u32 val = 0;
-       char *buf;
-       ssize_t ret;
-       int i = 0;
-       bool device_format = false;
-       int offset = 0;
-       int len = 0;
-       int pos = 0;
-       int sram;
-       struct iwl_priv *priv = file->private_data;
-       const struct fw_img *img;
-       size_t bufsz;
-
-       /* default is to dump the entire data segment */
-       if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
-               priv->dbgfs_sram_offset = 0x800000;
-               if (!priv->ucode_loaded)
-                       return -EINVAL;
-               img = &priv->fw->img[priv->cur_ucode];
-               priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
-       }
-       len = priv->dbgfs_sram_len;
-
-       if (len == -4) {
-               device_format = true;
-               len = 4;
-       }
-
-       bufsz =  50 + len * 4;
-       buf = kmalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
-                        len);
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
-                       priv->dbgfs_sram_offset);
-
-       /* adjust sram address since reads are only on even u32 boundaries */
-       offset = priv->dbgfs_sram_offset & 0x3;
-       sram = priv->dbgfs_sram_offset & ~0x3;
-
-       /* read the first u32 from sram */
-       val = iwl_read_targ_mem(priv->trans, sram);
-
-       for (; len; len--) {
-               /* put the address at the start of every line */
-               if (i == 0)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "%08X: ", sram + offset);
-
-               if (device_format)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "%02x", (val >> (8 * (3 - offset))) & 0xff);
-               else
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "%02x ", (val >> (8 * offset)) & 0xff);
-
-               /* if all bytes processed, read the next u32 from sram */
-               if (++offset == 4) {
-                       sram += 4;
-                       offset = 0;
-                       val = iwl_read_targ_mem(priv->trans, sram);
-               }
-
-               /* put in extra spaces and split lines for human readability */
-               if (++i == 16) {
-                       i = 0;
-                       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-               } else if (!(i & 7)) {
-                       pos += scnprintf(buf + pos, bufsz - pos, "   ");
-               } else if (!(i & 3)) {
-                       pos += scnprintf(buf + pos, bufsz - pos, " ");
-               }
-       }
-       if (i)
-               pos += scnprintf(buf + pos, bufsz - pos, "\n");
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_sram_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[64];
-       int buf_size;
-       u32 offset, len;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
-               priv->dbgfs_sram_offset = offset;
-               priv->dbgfs_sram_len = len;
-       } else if (sscanf(buf, "%x", &offset) == 1) {
-               priv->dbgfs_sram_offset = offset;
-               priv->dbgfs_sram_len = -4;
-       } else {
-               priv->dbgfs_sram_offset = 0;
-               priv->dbgfs_sram_len = 0;
-       }
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
-                                         char __user *user_buf,
-                                         size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       const struct fw_img *img = &priv->fw->img[IWL_UCODE_WOWLAN];
-
-       if (!priv->wowlan_sram)
-               return -ENODATA;
-
-       return simple_read_from_buffer(user_buf, count, ppos,
-                                      priv->wowlan_sram,
-                                      img->sec[IWL_UCODE_SECTION_DATA].len);
-}
-static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct iwl_station_entry *station;
-       struct iwl_tid_data *tid_data;
-       char *buf;
-       int i, j, pos = 0;
-       ssize_t ret;
-       /* Add 30 for initial string */
-       const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
-
-       buf = kmalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
-                       priv->num_stations);
-
-       for (i = 0; i < IWLAGN_STATION_COUNT; i++) {
-               station = &priv->stations[i];
-               if (!station->used)
-                       continue;
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                "station %d - addr: %pM, flags: %#x\n",
-                                i, station->sta.sta.addr,
-                                station->sta.station_flags_msk);
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "TID seqno  next_rclmd "
-                               "rate_n_flags state txq\n");
-
-               for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
-                       tid_data = &priv->tid_data[i][j];
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "%d:  0x%.4x 0x%.4x     0x%.8x   "
-                               "%d     %.2d",
-                               j, tid_data->seq_number,
-                               tid_data->next_reclaimed,
-                               tid_data->agg.rate_n_flags,
-                               tid_data->agg.state,
-                               tid_data->agg.txq_id);
-
-                       if (tid_data->agg.wait_for_ba)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                                " - waitforba");
-                       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-               }
-
-               pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       }
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_nvm_read(struct file *file,
-                                      char __user *user_buf,
-                                      size_t count,
-                                      loff_t *ppos)
-{
-       ssize_t ret;
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0, ofs = 0, buf_size = 0;
-       const u8 *ptr;
-       char *buf;
-       u16 eeprom_ver;
-       size_t eeprom_len = priv->cfg->base_params->eeprom_size;
-       buf_size = 4 * eeprom_len + 256;
-
-       if (eeprom_len % 16)
-               return -ENODATA;
-
-       ptr = priv->eeprom;
-       if (!ptr)
-               return -ENOMEM;
-
-       /* 4 characters for byte 0xYY */
-       buf = kzalloc(buf_size, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       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", 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,
-                                  buf_size - pos, 0);
-               pos += strlen(buf + pos);
-               if (buf_size - pos > 0)
-                       buf[pos++] = '\n';
-       }
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
-                                      size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct ieee80211_channel *channels = NULL;
-       const struct ieee80211_supported_band *supp_band = NULL;
-       int pos = 0, i, bufsz = PAGE_SIZE;
-       char *buf;
-       ssize_t ret;
-
-       if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
-       if (supp_band) {
-               channels = supp_band->channels;
-
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "Displaying %d channels in 2.4GHz band 802.11bg):\n",
-                               supp_band->n_channels);
-
-               for (i = 0; i < supp_band->n_channels; i++)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       "%d: %ddBm: BSS%s%s, %s.\n",
-                                       channels[i].hw_value,
-                                       channels[i].max_power,
-                                       channels[i].flags & IEEE80211_CHAN_RADAR ?
-                                       " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-                                       || (channels[i].flags &
-                                       IEEE80211_CHAN_RADAR)) ? "" :
-                                       ", IBSS",
-                                       channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
-                                       "passive only" : "active/passive");
-       }
-       supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
-       if (supp_band) {
-               channels = supp_band->channels;
-
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "Displaying %d channels in 5.2GHz band (802.11a)\n",
-                               supp_band->n_channels);
-
-               for (i = 0; i < supp_band->n_channels; i++)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       "%d: %ddBm: BSS%s%s, %s.\n",
-                                       channels[i].hw_value,
-                                       channels[i].max_power,
-                                       channels[i].flags & IEEE80211_CHAN_RADAR ?
-                                       " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
-                                       || (channels[i].flags &
-                                       IEEE80211_CHAN_RADAR)) ? "" :
-                                       ", IBSS",
-                                       channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
-                                       "passive only" : "active/passive");
-       }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_status_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       char buf[512];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       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_ALIVE:\t\t %d\n",
-               test_bit(STATUS_ALIVE, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
-               test_bit(STATUS_READY, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
-               test_bit(STATUS_GEO_CONFIGURED, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
-               test_bit(STATUS_EXIT_PENDING, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
-               test_bit(STATUS_STATISTICS, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
-               test_bit(STATUS_SCANNING, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
-               test_bit(STATUS_SCAN_ABORTING, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
-               test_bit(STATUS_SCAN_HW, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
-               test_bit(STATUS_POWER_PMI, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
-               test_bit(STATUS_FW_ERROR, &priv->status));
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-
-       int pos = 0;
-       int cnt = 0;
-       char *buf;
-       int bufsz = 24 * 64; /* 24 items * 64 char per item */
-       ssize_t ret;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       for (cnt = 0; cnt < REPLY_MAX; cnt++) {
-               if (priv->rx_handlers_stats[cnt] > 0)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "\tRx handler[%36s]:\t\t %u\n",
-                               iwl_dvm_get_cmd_string(cnt),
-                               priv->rx_handlers_stats[cnt]);
-       }
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_rx_handlers_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-
-       char buf[8];
-       int buf_size;
-       u32 reset_flag;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%x", &reset_flag) != 1)
-               return -EFAULT;
-       if (reset_flag == 0)
-               memset(&priv->rx_handlers_stats[0], 0,
-                       sizeof(priv->rx_handlers_stats));
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
-                                      size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct iwl_rxon_context *ctx;
-       int pos = 0, i;
-       char buf[256 * NUM_IWL_RXON_CTX];
-       const size_t bufsz = sizeof(buf);
-
-       for_each_context(priv, ctx) {
-               pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
-                                ctx->ctxid);
-               for (i = 0; i < AC_NUM; i++) {
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "\tcw_min\tcw_max\taifsn\ttxop\n");
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "AC[%d]\t%u\t%u\t%u\t%u\n", i,
-                               ctx->qos_data.def_qos_parm.ac[i].cw_min,
-                               ctx->qos_data.def_qos_parm.ac[i].cw_max,
-                               ctx->qos_data.def_qos_parm.ac[i].aifsn,
-                               ctx->qos_data.def_qos_parm.ac[i].edca_txop);
-               }
-               pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
-                               char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-       char buf[100];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "Thermal Throttling Mode: %s\n",
-                       tt->advanced_tt ? "Advance" : "Legacy");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "Thermal Throttling State: %d\n",
-                       tt->state);
-       if (tt->advanced_tt) {
-               restriction = tt->restriction + tt->state;
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "Tx mode: %d\n",
-                               restriction->tx_stream);
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "Rx mode: %d\n",
-                               restriction->rx_stream);
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "HT mode: %d\n",
-                               restriction->is_ht);
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int ht40;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &ht40) != 1)
-               return -EFAULT;
-       if (!iwl_is_any_associated(priv))
-               priv->disable_ht40 = ht40 ? true : false;
-       else
-               return -EINVAL;
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[100];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "11n 40MHz Mode: %s\n",
-                       priv->disable_ht40 ? "Disabled" : "Enabled");
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_temperature_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-
-static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
-                                                   const char __user *user_buf,
-                                                   size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int value;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       if (sscanf(buf, "%d", &value) != 1)
-               return -EINVAL;
-
-       /*
-        * Our users expect 0 to be "CAM", but 0 isn't actually
-        * valid here. However, let's not confuse them and present
-        * IWL_POWER_INDEX_1 as "1", not "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;
-
-       mutex_lock(&priv->mutex);
-       iwl_power_update_mode(priv, true);
-       mutex_unlock(&priv->mutex);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
-                                                  char __user *user_buf,
-                                                  size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[10];
-       int pos, value;
-       const size_t bufsz = sizeof(buf);
-
-       /* see the write function */
-       value = priv->power_data.debug_sleep_level_override;
-       if (value >= 0)
-               value += 1;
-
-       pos = scnprintf(buf, bufsz, "%d\n", value);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
-                                                   char __user *user_buf,
-                                                   size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[200];
-       int pos = 0, i;
-       const size_t bufsz = sizeof(buf);
-       struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "flags: %#.2x\n", le16_to_cpu(cmd->flags));
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "RX/TX timeout: %d/%d usec\n",
-                        le32_to_cpu(cmd->rx_data_timeout),
-                        le32_to_cpu(cmd->tx_data_timeout));
-       for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                "sleep_interval[%d]: %d\n", i,
-                                le32_to_cpu(cmd->sleep_interval[i]));
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-DEBUGFS_READ_WRITE_FILE_OPS(sram);
-DEBUGFS_READ_FILE_OPS(wowlan_sram);
-DEBUGFS_READ_FILE_OPS(nvm);
-DEBUGFS_READ_FILE_OPS(stations);
-DEBUGFS_READ_FILE_OPS(channels);
-DEBUGFS_READ_FILE_OPS(status);
-DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
-DEBUGFS_READ_FILE_OPS(qos);
-DEBUGFS_READ_FILE_OPS(thermal_throttling);
-DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
-DEBUGFS_READ_FILE_OPS(temperature);
-DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
-DEBUGFS_READ_FILE_OPS(current_sleep_command);
-
-static const char *fmt_value = "  %-30s %10u\n";
-static const char *fmt_hex   = "  %-30s       0x%02X\n";
-static const char *fmt_table = "  %-30s %10u  %10u  %10u  %10u\n";
-static const char *fmt_header =
-       "%-32s    current  cumulative       delta         max\n";
-
-static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
-       int p = 0;
-       u32 flag;
-
-       lockdep_assert_held(&priv->statistics.lock);
-
-       flag = le32_to_cpu(priv->statistics.flag);
-
-       p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag);
-       if (flag & UCODE_STATISTICS_CLEAR_MSK)
-               p += scnprintf(buf + p, bufsz - p,
-               "\tStatistics have been cleared\n");
-       p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
-               (flag & UCODE_STATISTICS_FREQUENCY_MSK)
-               ? "2.4 GHz" : "5.2 GHz");
-       p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
-               (flag & UCODE_STATISTICS_NARROW_BAND_MSK)
-                ? "enabled" : "disabled");
-
-       return p;
-}
-
-static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = sizeof(struct statistics_rx_phy) * 40 +
-                   sizeof(struct statistics_rx_non_phy) * 40 +
-                   sizeof(struct statistics_rx_ht_phy) * 40 + 400;
-       ssize_t ret;
-       struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
-       struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
-       struct statistics_rx_non_phy *general, *accum_general;
-       struct statistics_rx_non_phy *delta_general, *max_general;
-       struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /*
-        * the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-       spin_lock_bh(&priv->statistics.lock);
-       ofdm = &priv->statistics.rx_ofdm;
-       cck = &priv->statistics.rx_cck;
-       general = &priv->statistics.rx_non_phy;
-       ht = &priv->statistics.rx_ofdm_ht;
-       accum_ofdm = &priv->accum_stats.rx_ofdm;
-       accum_cck = &priv->accum_stats.rx_cck;
-       accum_general = &priv->accum_stats.rx_non_phy;
-       accum_ht = &priv->accum_stats.rx_ofdm_ht;
-       delta_ofdm = &priv->delta_stats.rx_ofdm;
-       delta_cck = &priv->delta_stats.rx_cck;
-       delta_general = &priv->delta_stats.rx_non_phy;
-       delta_ht = &priv->delta_stats.rx_ofdm_ht;
-       max_ofdm = &priv->max_delta_stats.rx_ofdm;
-       max_cck = &priv->max_delta_stats.rx_cck;
-       max_general = &priv->max_delta_stats.rx_non_phy;
-       max_ht = &priv->max_delta_stats.rx_ofdm_ht;
-
-       pos += iwl_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_Rx - OFDM:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "ina_cnt:",
-                        le32_to_cpu(ofdm->ina_cnt),
-                        accum_ofdm->ina_cnt,
-                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_cnt:",
-                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
-                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "plcp_err:",
-                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
-                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_err:",
-                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
-                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "overrun_err:",
-                        le32_to_cpu(ofdm->overrun_err),
-                        accum_ofdm->overrun_err, delta_ofdm->overrun_err,
-                        max_ofdm->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "early_overrun_err:",
-                        le32_to_cpu(ofdm->early_overrun_err),
-                        accum_ofdm->early_overrun_err,
-                        delta_ofdm->early_overrun_err,
-                        max_ofdm->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_good:",
-                        le32_to_cpu(ofdm->crc32_good),
-                        accum_ofdm->crc32_good, delta_ofdm->crc32_good,
-                        max_ofdm->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "false_alarm_cnt:",
-                        le32_to_cpu(ofdm->false_alarm_cnt),
-                        accum_ofdm->false_alarm_cnt,
-                        delta_ofdm->false_alarm_cnt,
-                        max_ofdm->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_sync_err_cnt:",
-                        le32_to_cpu(ofdm->fina_sync_err_cnt),
-                        accum_ofdm->fina_sync_err_cnt,
-                        delta_ofdm->fina_sync_err_cnt,
-                        max_ofdm->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sfd_timeout:",
-                        le32_to_cpu(ofdm->sfd_timeout),
-                        accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
-                        max_ofdm->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_timeout:",
-                        le32_to_cpu(ofdm->fina_timeout),
-                        accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
-                        max_ofdm->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "unresponded_rts:",
-                        le32_to_cpu(ofdm->unresponded_rts),
-                        accum_ofdm->unresponded_rts,
-                        delta_ofdm->unresponded_rts,
-                        max_ofdm->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "rxe_frame_lmt_ovrun:",
-                        le32_to_cpu(ofdm->rxe_frame_limit_overrun),
-                        accum_ofdm->rxe_frame_limit_overrun,
-                        delta_ofdm->rxe_frame_limit_overrun,
-                        max_ofdm->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_ack_cnt:",
-                        le32_to_cpu(ofdm->sent_ack_cnt),
-                        accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
-                        max_ofdm->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_cts_cnt:",
-                        le32_to_cpu(ofdm->sent_cts_cnt),
-                        accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
-                        max_ofdm->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_ba_rsp_cnt:",
-                        le32_to_cpu(ofdm->sent_ba_rsp_cnt),
-                        accum_ofdm->sent_ba_rsp_cnt,
-                        delta_ofdm->sent_ba_rsp_cnt,
-                        max_ofdm->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "dsp_self_kill:",
-                        le32_to_cpu(ofdm->dsp_self_kill),
-                        accum_ofdm->dsp_self_kill,
-                        delta_ofdm->dsp_self_kill,
-                        max_ofdm->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "mh_format_err:",
-                        le32_to_cpu(ofdm->mh_format_err),
-                        accum_ofdm->mh_format_err,
-                        delta_ofdm->mh_format_err,
-                        max_ofdm->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "re_acq_main_rssi_sum:",
-                        le32_to_cpu(ofdm->re_acq_main_rssi_sum),
-                        accum_ofdm->re_acq_main_rssi_sum,
-                        delta_ofdm->re_acq_main_rssi_sum,
-                        max_ofdm->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_Rx - CCK:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "ina_cnt:",
-                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
-                        delta_cck->ina_cnt, max_cck->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_cnt:",
-                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
-                        delta_cck->fina_cnt, max_cck->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "plcp_err:",
-                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
-                        delta_cck->plcp_err, max_cck->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_err:",
-                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
-                        delta_cck->crc32_err, max_cck->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "overrun_err:",
-                        le32_to_cpu(cck->overrun_err),
-                        accum_cck->overrun_err, delta_cck->overrun_err,
-                        max_cck->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "early_overrun_err:",
-                        le32_to_cpu(cck->early_overrun_err),
-                        accum_cck->early_overrun_err,
-                        delta_cck->early_overrun_err,
-                        max_cck->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_good:",
-                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
-                        delta_cck->crc32_good, max_cck->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "false_alarm_cnt:",
-                        le32_to_cpu(cck->false_alarm_cnt),
-                        accum_cck->false_alarm_cnt,
-                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_sync_err_cnt:",
-                        le32_to_cpu(cck->fina_sync_err_cnt),
-                        accum_cck->fina_sync_err_cnt,
-                        delta_cck->fina_sync_err_cnt,
-                        max_cck->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sfd_timeout:",
-                        le32_to_cpu(cck->sfd_timeout),
-                        accum_cck->sfd_timeout, delta_cck->sfd_timeout,
-                        max_cck->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "fina_timeout:",
-                        le32_to_cpu(cck->fina_timeout),
-                        accum_cck->fina_timeout, delta_cck->fina_timeout,
-                        max_cck->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "unresponded_rts:",
-                        le32_to_cpu(cck->unresponded_rts),
-                        accum_cck->unresponded_rts, delta_cck->unresponded_rts,
-                        max_cck->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "rxe_frame_lmt_ovrun:",
-                        le32_to_cpu(cck->rxe_frame_limit_overrun),
-                        accum_cck->rxe_frame_limit_overrun,
-                        delta_cck->rxe_frame_limit_overrun,
-                        max_cck->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_ack_cnt:",
-                        le32_to_cpu(cck->sent_ack_cnt),
-                        accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
-                        max_cck->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_cts_cnt:",
-                        le32_to_cpu(cck->sent_cts_cnt),
-                        accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
-                        max_cck->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sent_ba_rsp_cnt:",
-                        le32_to_cpu(cck->sent_ba_rsp_cnt),
-                        accum_cck->sent_ba_rsp_cnt,
-                        delta_cck->sent_ba_rsp_cnt,
-                        max_cck->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "dsp_self_kill:",
-                        le32_to_cpu(cck->dsp_self_kill),
-                        accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
-                        max_cck->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "mh_format_err:",
-                        le32_to_cpu(cck->mh_format_err),
-                        accum_cck->mh_format_err, delta_cck->mh_format_err,
-                        max_cck->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "re_acq_main_rssi_sum:",
-                        le32_to_cpu(cck->re_acq_main_rssi_sum),
-                        accum_cck->re_acq_main_rssi_sum,
-                        delta_cck->re_acq_main_rssi_sum,
-                        max_cck->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_Rx - GENERAL:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "bogus_cts:",
-                        le32_to_cpu(general->bogus_cts),
-                        accum_general->bogus_cts, delta_general->bogus_cts,
-                        max_general->bogus_cts);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "bogus_ack:",
-                        le32_to_cpu(general->bogus_ack),
-                        accum_general->bogus_ack, delta_general->bogus_ack,
-                        max_general->bogus_ack);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "non_bssid_frames:",
-                        le32_to_cpu(general->non_bssid_frames),
-                        accum_general->non_bssid_frames,
-                        delta_general->non_bssid_frames,
-                        max_general->non_bssid_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "filtered_frames:",
-                        le32_to_cpu(general->filtered_frames),
-                        accum_general->filtered_frames,
-                        delta_general->filtered_frames,
-                        max_general->filtered_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "non_channel_beacons:",
-                        le32_to_cpu(general->non_channel_beacons),
-                        accum_general->non_channel_beacons,
-                        delta_general->non_channel_beacons,
-                        max_general->non_channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "channel_beacons:",
-                        le32_to_cpu(general->channel_beacons),
-                        accum_general->channel_beacons,
-                        delta_general->channel_beacons,
-                        max_general->channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "num_missed_bcon:",
-                        le32_to_cpu(general->num_missed_bcon),
-                        accum_general->num_missed_bcon,
-                        delta_general->num_missed_bcon,
-                        max_general->num_missed_bcon);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "adc_rx_saturation_time:",
-                        le32_to_cpu(general->adc_rx_saturation_time),
-                        accum_general->adc_rx_saturation_time,
-                        delta_general->adc_rx_saturation_time,
-                        max_general->adc_rx_saturation_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "ina_detect_search_tm:",
-                        le32_to_cpu(general->ina_detection_search_time),
-                        accum_general->ina_detection_search_time,
-                        delta_general->ina_detection_search_time,
-                        max_general->ina_detection_search_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_silence_rssi_a:",
-                        le32_to_cpu(general->beacon_silence_rssi_a),
-                        accum_general->beacon_silence_rssi_a,
-                        delta_general->beacon_silence_rssi_a,
-                        max_general->beacon_silence_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_silence_rssi_b:",
-                        le32_to_cpu(general->beacon_silence_rssi_b),
-                        accum_general->beacon_silence_rssi_b,
-                        delta_general->beacon_silence_rssi_b,
-                        max_general->beacon_silence_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_silence_rssi_c:",
-                        le32_to_cpu(general->beacon_silence_rssi_c),
-                        accum_general->beacon_silence_rssi_c,
-                        delta_general->beacon_silence_rssi_c,
-                        max_general->beacon_silence_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "interference_data_flag:",
-                        le32_to_cpu(general->interference_data_flag),
-                        accum_general->interference_data_flag,
-                        delta_general->interference_data_flag,
-                        max_general->interference_data_flag);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "channel_load:",
-                        le32_to_cpu(general->channel_load),
-                        accum_general->channel_load,
-                        delta_general->channel_load,
-                        max_general->channel_load);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "dsp_false_alarms:",
-                        le32_to_cpu(general->dsp_false_alarms),
-                        accum_general->dsp_false_alarms,
-                        delta_general->dsp_false_alarms,
-                        max_general->dsp_false_alarms);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_rssi_a:",
-                        le32_to_cpu(general->beacon_rssi_a),
-                        accum_general->beacon_rssi_a,
-                        delta_general->beacon_rssi_a,
-                        max_general->beacon_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_rssi_b:",
-                        le32_to_cpu(general->beacon_rssi_b),
-                        accum_general->beacon_rssi_b,
-                        delta_general->beacon_rssi_b,
-                        max_general->beacon_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_rssi_c:",
-                        le32_to_cpu(general->beacon_rssi_c),
-                        accum_general->beacon_rssi_c,
-                        delta_general->beacon_rssi_c,
-                        max_general->beacon_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_energy_a:",
-                        le32_to_cpu(general->beacon_energy_a),
-                        accum_general->beacon_energy_a,
-                        delta_general->beacon_energy_a,
-                        max_general->beacon_energy_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_energy_b:",
-                        le32_to_cpu(general->beacon_energy_b),
-                        accum_general->beacon_energy_b,
-                        delta_general->beacon_energy_b,
-                        max_general->beacon_energy_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "beacon_energy_c:",
-                        le32_to_cpu(general->beacon_energy_c),
-                        accum_general->beacon_energy_c,
-                        delta_general->beacon_energy_c,
-                        max_general->beacon_energy_c);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_Rx - OFDM_HT:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "plcp_err:",
-                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
-                        delta_ht->plcp_err, max_ht->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "overrun_err:",
-                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
-                        delta_ht->overrun_err, max_ht->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "early_overrun_err:",
-                        le32_to_cpu(ht->early_overrun_err),
-                        accum_ht->early_overrun_err,
-                        delta_ht->early_overrun_err,
-                        max_ht->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_good:",
-                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
-                        delta_ht->crc32_good, max_ht->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "crc32_err:",
-                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
-                        delta_ht->crc32_err, max_ht->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "mh_format_err:",
-                        le32_to_cpu(ht->mh_format_err),
-                        accum_ht->mh_format_err,
-                        delta_ht->mh_format_err, max_ht->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg_crc32_good:",
-                        le32_to_cpu(ht->agg_crc32_good),
-                        accum_ht->agg_crc32_good,
-                        delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg_mpdu_cnt:",
-                        le32_to_cpu(ht->agg_mpdu_cnt),
-                        accum_ht->agg_mpdu_cnt,
-                        delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg_cnt:",
-                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
-                        delta_ht->agg_cnt, max_ht->agg_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "unsupport_mcs:",
-                        le32_to_cpu(ht->unsupport_mcs),
-                        accum_ht->unsupport_mcs,
-                        delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
-       ssize_t ret;
-       struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /* the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-       spin_lock_bh(&priv->statistics.lock);
-
-       tx = &priv->statistics.tx;
-       accum_tx = &priv->accum_stats.tx;
-       delta_tx = &priv->delta_stats.tx;
-       max_tx = &priv->max_delta_stats.tx;
-
-       pos += iwl_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_Tx:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "preamble:",
-                        le32_to_cpu(tx->preamble_cnt),
-                        accum_tx->preamble_cnt,
-                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "rx_detected_cnt:",
-                        le32_to_cpu(tx->rx_detected_cnt),
-                        accum_tx->rx_detected_cnt,
-                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "bt_prio_defer_cnt:",
-                        le32_to_cpu(tx->bt_prio_defer_cnt),
-                        accum_tx->bt_prio_defer_cnt,
-                        delta_tx->bt_prio_defer_cnt,
-                        max_tx->bt_prio_defer_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "bt_prio_kill_cnt:",
-                        le32_to_cpu(tx->bt_prio_kill_cnt),
-                        accum_tx->bt_prio_kill_cnt,
-                        delta_tx->bt_prio_kill_cnt,
-                        max_tx->bt_prio_kill_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "few_bytes_cnt:",
-                        le32_to_cpu(tx->few_bytes_cnt),
-                        accum_tx->few_bytes_cnt,
-                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "cts_timeout:",
-                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
-                        delta_tx->cts_timeout, max_tx->cts_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "ack_timeout:",
-                        le32_to_cpu(tx->ack_timeout),
-                        accum_tx->ack_timeout,
-                        delta_tx->ack_timeout, max_tx->ack_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "expected_ack_cnt:",
-                        le32_to_cpu(tx->expected_ack_cnt),
-                        accum_tx->expected_ack_cnt,
-                        delta_tx->expected_ack_cnt,
-                        max_tx->expected_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "actual_ack_cnt:",
-                        le32_to_cpu(tx->actual_ack_cnt),
-                        accum_tx->actual_ack_cnt,
-                        delta_tx->actual_ack_cnt,
-                        max_tx->actual_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "dump_msdu_cnt:",
-                        le32_to_cpu(tx->dump_msdu_cnt),
-                        accum_tx->dump_msdu_cnt,
-                        delta_tx->dump_msdu_cnt,
-                        max_tx->dump_msdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "abort_nxt_frame_mismatch:",
-                        le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
-                        accum_tx->burst_abort_next_frame_mismatch_cnt,
-                        delta_tx->burst_abort_next_frame_mismatch_cnt,
-                        max_tx->burst_abort_next_frame_mismatch_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "abort_missing_nxt_frame:",
-                        le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
-                        accum_tx->burst_abort_missing_next_frame_cnt,
-                        delta_tx->burst_abort_missing_next_frame_cnt,
-                        max_tx->burst_abort_missing_next_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "cts_timeout_collision:",
-                        le32_to_cpu(tx->cts_timeout_collision),
-                        accum_tx->cts_timeout_collision,
-                        delta_tx->cts_timeout_collision,
-                        max_tx->cts_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "ack_ba_timeout_collision:",
-                        le32_to_cpu(tx->ack_or_ba_timeout_collision),
-                        accum_tx->ack_or_ba_timeout_collision,
-                        delta_tx->ack_or_ba_timeout_collision,
-                        max_tx->ack_or_ba_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg ba_timeout:",
-                        le32_to_cpu(tx->agg.ba_timeout),
-                        accum_tx->agg.ba_timeout,
-                        delta_tx->agg.ba_timeout,
-                        max_tx->agg.ba_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg ba_resched_frames:",
-                        le32_to_cpu(tx->agg.ba_reschedule_frames),
-                        accum_tx->agg.ba_reschedule_frames,
-                        delta_tx->agg.ba_reschedule_frames,
-                        max_tx->agg.ba_reschedule_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg scd_query_agg_frame:",
-                        le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
-                        accum_tx->agg.scd_query_agg_frame_cnt,
-                        delta_tx->agg.scd_query_agg_frame_cnt,
-                        max_tx->agg.scd_query_agg_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg scd_query_no_agg:",
-                        le32_to_cpu(tx->agg.scd_query_no_agg),
-                        accum_tx->agg.scd_query_no_agg,
-                        delta_tx->agg.scd_query_no_agg,
-                        max_tx->agg.scd_query_no_agg);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg scd_query_agg:",
-                        le32_to_cpu(tx->agg.scd_query_agg),
-                        accum_tx->agg.scd_query_agg,
-                        delta_tx->agg.scd_query_agg,
-                        max_tx->agg.scd_query_agg);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg scd_query_mismatch:",
-                        le32_to_cpu(tx->agg.scd_query_mismatch),
-                        accum_tx->agg.scd_query_mismatch,
-                        delta_tx->agg.scd_query_mismatch,
-                        max_tx->agg.scd_query_mismatch);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg frame_not_ready:",
-                        le32_to_cpu(tx->agg.frame_not_ready),
-                        accum_tx->agg.frame_not_ready,
-                        delta_tx->agg.frame_not_ready,
-                        max_tx->agg.frame_not_ready);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg underrun:",
-                        le32_to_cpu(tx->agg.underrun),
-                        accum_tx->agg.underrun,
-                        delta_tx->agg.underrun, max_tx->agg.underrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg bt_prio_kill:",
-                        le32_to_cpu(tx->agg.bt_prio_kill),
-                        accum_tx->agg.bt_prio_kill,
-                        delta_tx->agg.bt_prio_kill,
-                        max_tx->agg.bt_prio_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "agg rx_ba_rsp_cnt:",
-                        le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
-                        accum_tx->agg.rx_ba_rsp_cnt,
-                        delta_tx->agg.rx_ba_rsp_cnt,
-                        max_tx->agg.rx_ba_rsp_cnt);
-
-       if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "tx power: (1/2 dB step)\n");
-               if ((priv->hw_params.valid_tx_ant & ANT_A) &&
-                   tx->tx_power.ant_a)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       fmt_hex, "antenna A:",
-                                       tx->tx_power.ant_a);
-               if ((priv->hw_params.valid_tx_ant & ANT_B) &&
-                   tx->tx_power.ant_b)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       fmt_hex, "antenna B:",
-                                       tx->tx_power.ant_b);
-               if ((priv->hw_params.valid_tx_ant & ANT_C) &&
-                   tx->tx_power.ant_c)
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                                       fmt_hex, "antenna C:",
-                                       tx->tx_power.ant_c);
-       }
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = sizeof(struct statistics_general) * 10 + 300;
-       ssize_t ret;
-       struct statistics_general_common *general, *accum_general;
-       struct statistics_general_common *delta_general, *max_general;
-       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
-       struct statistics_div *div, *accum_div, *delta_div, *max_div;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /* the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-
-       spin_lock_bh(&priv->statistics.lock);
-
-       general = &priv->statistics.common;
-       dbg = &priv->statistics.common.dbg;
-       div = &priv->statistics.common.div;
-       accum_general = &priv->accum_stats.common;
-       accum_dbg = &priv->accum_stats.common.dbg;
-       accum_div = &priv->accum_stats.common.div;
-       delta_general = &priv->delta_stats.common;
-       max_general = &priv->max_delta_stats.common;
-       delta_dbg = &priv->delta_stats.common.dbg;
-       max_dbg = &priv->max_delta_stats.common.dbg;
-       delta_div = &priv->delta_stats.common.div;
-       max_div = &priv->max_delta_stats.common.div;
-
-       pos += iwl_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_header, "Statistics_General:");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_value, "temperature:",
-                        le32_to_cpu(general->temperature));
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_value, "temperature_m:",
-                        le32_to_cpu(general->temperature_m));
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_value, "ttl_timestamp:",
-                        le32_to_cpu(general->ttl_timestamp));
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "burst_check:",
-                        le32_to_cpu(dbg->burst_check),
-                        accum_dbg->burst_check,
-                        delta_dbg->burst_check, max_dbg->burst_check);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "burst_count:",
-                        le32_to_cpu(dbg->burst_count),
-                        accum_dbg->burst_count,
-                        delta_dbg->burst_count, max_dbg->burst_count);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "wait_for_silence_timeout_count:",
-                        le32_to_cpu(dbg->wait_for_silence_timeout_cnt),
-                        accum_dbg->wait_for_silence_timeout_cnt,
-                        delta_dbg->wait_for_silence_timeout_cnt,
-                        max_dbg->wait_for_silence_timeout_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "sleep_time:",
-                        le32_to_cpu(general->sleep_time),
-                        accum_general->sleep_time,
-                        delta_general->sleep_time, max_general->sleep_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "slots_out:",
-                        le32_to_cpu(general->slots_out),
-                        accum_general->slots_out,
-                        delta_general->slots_out, max_general->slots_out);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "slots_idle:",
-                        le32_to_cpu(general->slots_idle),
-                        accum_general->slots_idle,
-                        delta_general->slots_idle, max_general->slots_idle);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "tx_on_a:",
-                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
-                        delta_div->tx_on_a, max_div->tx_on_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "tx_on_b:",
-                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
-                        delta_div->tx_on_b, max_div->tx_on_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "exec_time:",
-                        le32_to_cpu(div->exec_time), accum_div->exec_time,
-                        delta_div->exec_time, max_div->exec_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "probe_time:",
-                        le32_to_cpu(div->probe_time), accum_div->probe_time,
-                        delta_div->probe_time, max_div->probe_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "rx_enable_counter:",
-                        le32_to_cpu(general->rx_enable_counter),
-                        accum_general->rx_enable_counter,
-                        delta_general->rx_enable_counter,
-                        max_general->rx_enable_counter);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        fmt_table, "num_of_sos_states:",
-                        le32_to_cpu(general->num_of_sos_states),
-                        accum_general->num_of_sos_states,
-                        delta_general->num_of_sos_states,
-                        max_general->num_of_sos_states);
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200;
-       ssize_t ret;
-       struct statistics_bt_activity *bt, *accum_bt;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       if (!priv->bt_enable_flag)
-               return -EINVAL;
-
-       /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (ret)
-               return -EAGAIN;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       /*
-        * the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-
-       spin_lock_bh(&priv->statistics.lock);
-
-       bt = &priv->statistics.bt_activity;
-       accum_bt = &priv->accum_stats.bt_activity;
-
-       pos += iwl_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->hi_priority_tx_req_cnt),
-                        accum_bt->hi_priority_tx_req_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->hi_priority_tx_denied_cnt),
-                        accum_bt->hi_priority_tx_denied_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->lo_priority_tx_req_cnt),
-                        accum_bt->lo_priority_tx_req_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->lo_priority_tx_denied_cnt),
-                        accum_bt->lo_priority_tx_denied_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->hi_priority_rx_req_cnt),
-                        accum_bt->hi_priority_rx_req_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->hi_priority_rx_denied_cnt),
-                        accum_bt->hi_priority_rx_denied_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->lo_priority_rx_req_cnt),
-                        accum_bt->lo_priority_rx_req_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n",
-                        le32_to_cpu(bt->lo_priority_rx_denied_cnt),
-                        accum_bt->lo_priority_rx_denied_cnt);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "(rx)num_bt_kills:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(priv->statistics.num_bt_kills),
-                        priv->statistics.accum_num_bt_kills);
-
-       spin_unlock_bh(&priv->statistics.lock);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) +
-               (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
-       ssize_t ret;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
-                        priv->reply_tx_stats.pp_delay);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
-                        priv->reply_tx_stats.pp_few_bytes);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
-                        priv->reply_tx_stats.pp_bt_prio);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
-                        priv->reply_tx_stats.pp_quiet_period);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
-                        priv->reply_tx_stats.pp_calc_ttak);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_tx_fail_reason(
-                               TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
-                        priv->reply_tx_stats.int_crossed_retry);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
-                        priv->reply_tx_stats.short_limit);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
-                        priv->reply_tx_stats.long_limit);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
-                        priv->reply_tx_stats.fifo_underrun);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
-                        priv->reply_tx_stats.drain_flow);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
-                        priv->reply_tx_stats.rfkill_flush);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
-                        priv->reply_tx_stats.life_expire);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
-                        priv->reply_tx_stats.dest_ps);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
-                        priv->reply_tx_stats.host_abort);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
-                        priv->reply_tx_stats.pp_delay);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
-                        priv->reply_tx_stats.sta_invalid);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
-                        priv->reply_tx_stats.frag_drop);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
-                        priv->reply_tx_stats.tid_disable);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
-                        priv->reply_tx_stats.fifo_flush);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_tx_fail_reason(
-                               TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
-                        priv->reply_tx_stats.insuff_cf_poll);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
-                        priv->reply_tx_stats.fail_hw_drop);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_tx_fail_reason(
-                               TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
-                        priv->reply_tx_stats.sta_color_mismatch);
-       pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-                        priv->reply_tx_stats.unknown);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "\nStatistics_Agg_TX_Error:\n");
-
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
-                        priv->reply_agg_tx_stats.underrun);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
-                        priv->reply_agg_tx_stats.bt_prio);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
-                        priv->reply_agg_tx_stats.few_bytes);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
-                        priv->reply_agg_tx_stats.abort);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(
-                               AGG_TX_STATE_LAST_SENT_TTL_MSK),
-                        priv->reply_agg_tx_stats.last_sent_ttl);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(
-                               AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
-                        priv->reply_agg_tx_stats.last_sent_try);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(
-                               AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
-                        priv->reply_agg_tx_stats.last_sent_bt_kill);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
-                        priv->reply_agg_tx_stats.scd_query);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(
-                               AGG_TX_STATE_TEST_BAD_CRC32_MSK),
-                        priv->reply_agg_tx_stats.bad_crc32);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
-                        priv->reply_agg_tx_stats.response);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
-                        priv->reply_agg_tx_stats.dump_tx);
-       pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
-                        iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
-                        priv->reply_agg_tx_stats.delay_tx);
-       pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
-                        priv->reply_agg_tx_stats.unknown);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       int cnt = 0;
-       char *buf;
-       int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
-       ssize_t ret;
-       struct iwl_sensitivity_data *data;
-
-       data = &priv->sensitivity_data;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
-                       data->auto_corr_ofdm);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "auto_corr_ofdm_mrc:\t\t %u\n",
-                       data->auto_corr_ofdm_mrc);
-       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
-                       data->auto_corr_ofdm_x1);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "auto_corr_ofdm_mrc_x1:\t\t %u\n",
-                       data->auto_corr_ofdm_mrc_x1);
-       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
-                       data->auto_corr_cck);
-       pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
-                       data->auto_corr_cck_mrc);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "last_bad_plcp_cnt_ofdm:\t\t %u\n",
-                       data->last_bad_plcp_cnt_ofdm);
-       pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
-                       data->last_fa_cnt_ofdm);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "last_bad_plcp_cnt_cck:\t\t %u\n",
-                       data->last_bad_plcp_cnt_cck);
-       pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
-                       data->last_fa_cnt_cck);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
-                       data->nrg_curr_state);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
-                       data->nrg_prev_state);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
-       for (cnt = 0; cnt < 10; cnt++) {
-               pos += scnprintf(buf + pos, bufsz - pos, " %u",
-                               data->nrg_value[cnt]);
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
-       for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
-               pos += scnprintf(buf + pos, bufsz - pos, " %u",
-                               data->nrg_silence_rssi[cnt]);
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
-                       data->nrg_silence_ref);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
-                       data->nrg_energy_idx);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
-                       data->nrg_silence_idx);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
-                       data->nrg_th_cck);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "nrg_auto_corr_silence_diff:\t %u\n",
-                       data->nrg_auto_corr_silence_diff);
-       pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
-                       data->num_in_cck_no_fa);
-       pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
-                       data->nrg_th_ofdm);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-
-static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       int cnt = 0;
-       char *buf;
-       int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
-       ssize_t ret;
-       struct iwl_chain_noise_data *data;
-
-       data = &priv->chain_noise_data;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
-                       data->active_chains);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
-                       data->chain_noise_a);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
-                       data->chain_noise_b);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
-                       data->chain_noise_c);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
-                       data->chain_signal_a);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
-                       data->chain_signal_b);
-       pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
-                       data->chain_signal_c);
-       pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
-                       data->beacon_count);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
-       for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
-               pos += scnprintf(buf + pos, bufsz - pos, " %u",
-                               data->disconn_array[cnt]);
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
-       for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
-               pos += scnprintf(buf + pos, bufsz - pos, " %u",
-                               data->delta_gain_code[cnt]);
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
-                       data->radio_write);
-       pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
-                       data->state);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-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 = file->private_data;
-       char buf[60];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-       u32 pwrsave_status;
-
-       pwrsave_status = iwl_read32(priv->trans, 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);
-}
-
-static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int clear;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &clear) != 1)
-               return -EFAULT;
-
-       /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->mutex);
-       iwl_send_statistics_request(priv, CMD_SYNC, true);
-       mutex_unlock(&priv->mutex);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char buf[128];
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
-                       priv->event_log.ucode_trace ? "On" : "Off");
-       pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
-                       priv->event_log.non_wraps_count);
-       pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
-                       priv->event_log.wraps_once_count);
-       pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
-                       priv->event_log.wraps_more_count);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int trace;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &trace) != 1)
-               return -EFAULT;
-
-       if (trace) {
-               priv->event_log.ucode_trace = true;
-               if (iwl_is_alive(priv)) {
-                       /* start collecting data now */
-                       mod_timer(&priv->ucode_trace, jiffies);
-               }
-       } else {
-               priv->event_log.ucode_trace = false;
-               del_timer_sync(&priv->ucode_trace);
-       }
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int len = 0;
-       char buf[20];
-
-       len = sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int len = 0;
-       char buf[20];
-
-       len = sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char buf[12];
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
-                       priv->missed_beacon_threshold);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int missed;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &missed) != 1)
-               return -EINVAL;
-
-       if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
-           missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
-               priv->missed_beacon_threshold =
-                       IWL_MISSED_BEACON_THRESHOLD_DEF;
-       else
-               priv->missed_beacon_threshold = missed;
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char buf[12];
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
-                       priv->plcp_delta_threshold);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int plcp;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &plcp) != 1)
-               return -EINVAL;
-       if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
-               (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
-               priv->plcp_delta_threshold =
-                       IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE;
-       else
-               priv->plcp_delta_threshold = plcp;
-       return count;
-}
-
-static ssize_t iwl_dbgfs_rf_reset_read(struct file *file,
-                                      char __user *user_buf,
-                                      size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char buf[300];
-       const size_t bufsz = sizeof(buf);
-       struct iwl_rf_reset *rf_reset = &priv->rf_reset;
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "RF reset statistics\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tnumber of reset request: %d\n",
-                       rf_reset->reset_request_count);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tnumber of reset request success: %d\n",
-                       rf_reset->reset_success_count);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tnumber of reset request reject: %d\n",
-                       rf_reset->reset_reject_count);
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_rf_reset_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       int ret;
-
-       ret = iwl_force_rf_reset(priv, true);
-       return ret ? ret : count;
-}
-
-static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int flush;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &flush) != 1)
-               return -EINVAL;
-
-       if (iwl_is_rfkill(priv))
-               return -EFAULT;
-
-       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-       int pos = 0;
-       char buf[200];
-       const size_t bufsz = sizeof(buf);
-
-       if (!priv->bt_enable_flag) {
-               pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
-               return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       }
-       pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
-               priv->bt_enable_flag);
-       pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
-               priv->bt_full_concurrent ? "full concurrency" : "3-wire");
-       pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
-                        "last traffic notif: %d\n",
-               priv->bt_status ? "On" : "Off", priv->last_bt_traffic_load);
-       pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
-                        "kill_ack_mask: %x, kill_cts_mask: %x\n",
-               priv->bt_ch_announce, priv->kill_ack_mask,
-               priv->kill_cts_mask);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
-       switch (priv->bt_traffic_load) {
-       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
-               pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
-               pos += scnprintf(buf + pos, bufsz - pos, "High\n");
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
-               pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
-               break;
-       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
-       default:
-               pos += scnprintf(buf + pos, bufsz - pos, "None\n");
-               break;
-       }
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-
-       int pos = 0;
-       char buf[40];
-       const size_t bufsz = sizeof(buf);
-
-       if (priv->cfg->ht_params)
-               pos += scnprintf(buf + pos, bufsz - pos,
-                        "use %s for aggregation\n",
-                        (priv->hw_params.use_rts_for_aggregation) ?
-                               "rts/cts" : "cts-to-self");
-       else
-               pos += scnprintf(buf + pos, bufsz - pos, "N/A");
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-       int rts;
-
-       if (!priv->cfg->ht_params)
-               return -EINVAL;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &rts) != 1)
-               return -EINVAL;
-       if (rts)
-               priv->hw_params.use_rts_for_aggregation = true;
-       else
-               priv->hw_params.use_rts_for_aggregation = false;
-       return count;
-}
-
-static int iwl_cmd_echo_test(struct iwl_priv *priv)
-{
-       int ret;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_ECHO,
-               .len = { 0 },
-               .flags = CMD_SYNC,
-       };
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-       if (ret)
-               IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
-       else
-               IWL_DEBUG_INFO(priv, "echo testing pass\n");
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_echo_test_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-
-       iwl_cmd_echo_test(priv);
-       return count;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static ssize_t iwl_dbgfs_log_event_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char *buf;
-       int pos = 0;
-       ssize_t ret = -ENOMEM;
-
-       ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
-       if (buf) {
-               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-               kfree(buf);
-       }
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_log_event_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       u32 event_log_flag;
-       char buf[8];
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &event_log_flag) != 1)
-               return -EFAULT;
-       if (event_log_flag == 1)
-               iwl_dump_nic_event_log(priv, true, NULL, false);
-
-       return count;
-}
-#endif
-
-static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[120];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "Sensitivity calibrations %s\n",
-                        (priv->calib_disabled &
-                                       IWL_SENSITIVITY_CALIB_DISABLED) ?
-                        "DISABLED" : "ENABLED");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "Chain noise calibrations %s\n",
-                        (priv->calib_disabled &
-                                       IWL_CHAIN_NOISE_CALIB_DISABLED) ?
-                        "DISABLED" : "ENABLED");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "Tx power calibrations %s\n",
-                        (priv->calib_disabled &
-                                       IWL_TX_POWER_CALIB_DISABLED) ?
-                        "DISABLED" : "ENABLED");
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file,
-                                             const char __user *user_buf,
-                                             size_t count, loff_t *ppos)
-{
-       struct iwl_priv *priv = file->private_data;
-       char buf[8];
-       u32 calib_disabled;
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%x", &calib_disabled) != 1)
-               return -EFAULT;
-
-       priv->calib_disabled = calib_disabled;
-
-       return count;
-}
-
-DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
-DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
-DEBUGFS_READ_FILE_OPS(ucode_general_stats);
-DEBUGFS_READ_FILE_OPS(sensitivity);
-DEBUGFS_READ_FILE_OPS(chain_noise);
-DEBUGFS_READ_FILE_OPS(power_save_status);
-DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
-DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
-DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
-DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
-DEBUGFS_READ_WRITE_FILE_OPS(rf_reset);
-DEBUGFS_READ_FILE_OPS(rxon_flags);
-DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
-DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
-DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
-DEBUGFS_READ_FILE_OPS(bt_traffic);
-DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
-DEBUGFS_READ_FILE_OPS(reply_tx_error);
-DEBUGFS_WRITE_FILE_OPS(echo_test);
-#ifdef CONFIG_IWLWIFI_DEBUG
-DEBUGFS_READ_WRITE_FILE_OPS(log_event);
-#endif
-DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled);
-
-/*
- * Create the debugfs files and directories
- *
- */
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
-{
-       struct dentry *phyd = priv->hw->wiphy->debugfsdir;
-       struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
-
-       dir_drv = debugfs_create_dir(name, phyd);
-       if (!dir_drv)
-               return -ENOMEM;
-
-       priv->debugfs_dir = dir_drv;
-
-       dir_data = debugfs_create_dir("data", dir_drv);
-       if (!dir_data)
-               goto err;
-       dir_rf = debugfs_create_dir("rf", dir_drv);
-       if (!dir_rf)
-               goto err;
-       dir_debug = debugfs_create_dir("debug", dir_drv);
-       if (!dir_debug)
-               goto err;
-
-       DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
-
-       DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
-#ifdef CONFIG_IWLWIFI_DEBUG
-       DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
-#endif
-
-       if (iwl_advanced_bt_coexist(priv))
-               DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
-
-       /* Calibrations disabled/enabled status*/
-       DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR);
-
-       if (iwl_trans_dbgfs_register(priv->trans, dir_debug))
-               goto err;
-       return 0;
-
-err:
-       IWL_ERR(priv, "Can't create the debugfs directory\n");
-       iwl_dbgfs_unregister(priv);
-       return -ENOMEM;
-}
-
-/**
- * Remove the debugfs files and directories
- *
- */
-void iwl_dbgfs_unregister(struct iwl_priv *priv)
-{
-       if (!priv->debugfs_dir)
-               return;
-
-       debugfs_remove_recursive(priv->debugfs_dir);
-       priv->debugfs_dir = NULL;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
deleted file mode 100644 (file)
index 7006237..0000000
+++ /dev/null
@@ -1,1071 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-dev.h) for driver implementation definitions.
- * Please use iwl-commands.h for uCode API definitions.
- */
-
-#ifndef __iwl_dev_h__
-#define __iwl_dev_h__
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include "iwl-fw.h"
-#include "iwl-eeprom.h"
-#include "iwl-csr.h"
-#include "iwl-debug.h"
-#include "iwl-agn-hw.h"
-#include "iwl-led.h"
-#include "iwl-power.h"
-#include "iwl-agn-rs.h"
-#include "iwl-agn-tt.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-notif-wait.h"
-
-/* CT-KILL constants */
-#define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
-#define CT_KILL_THRESHOLD         114 /* in Celsius */
-#define CT_KILL_EXIT_THRESHOLD     95  /* in Celsius */
-
-/* Default noise level to report when noise measurement is not available.
- *   This may be because we're:
- *   1)  Not associated  no beacon statistics being sent to driver)
- *   2)  Scanning (noise measurement does not apply to associated channel)
- * Use default noise value of -127 ... this is below the range of measurable
- *   Rx dBm for all agn devices, so it can indicate "unmeasurable" to user.
- *   Also, -127 works better than 0 when averaging frames with/without
- *   noise info (e.g. averaging might be done in app); measured dBm values are
- *   always negative ... using a negative value as the default keeps all
- *   averages within an s8's (used in some apps) range of negative values. */
-#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
-
-/*
- * RTS threshold here is total size [2347] minus 4 FCS bytes
- * Per spec:
- *   a value of 0 means RTS on all data/management packets
- *   a value > max MSDU size means no RTS
- * else RTS for data/management frames where MPDU is larger
- *   than RTS value.
- */
-#define DEFAULT_RTS_THRESHOLD     2347U
-#define MIN_RTS_THRESHOLD         0U
-#define MAX_RTS_THRESHOLD         2347U
-#define MAX_MSDU_SIZE            2304U
-#define MAX_MPDU_SIZE            2346U
-#define DEFAULT_BEACON_INTERVAL   200U
-#define        DEFAULT_SHORT_RETRY_LIMIT 7U
-#define        DEFAULT_LONG_RETRY_LIMIT  4U
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-/*
- * One for each channel, holds all channel setup data
- * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
- *     with one another!
- */
-struct iwl_channel_info {
-       struct iwl_eeprom_channel eeprom;       /* EEPROM regulatory limit */
-       struct iwl_eeprom_channel ht40_eeprom;  /* EEPROM regulatory limit for
-                                                * HT40 channel */
-
-       u8 channel;       /* channel number */
-       u8 flags;         /* flags copied from EEPROM */
-       s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
-       s8 curr_txpow;    /* (dBm) regulatory/spectrum/user (not h/w) limit */
-       s8 min_power;     /* always 0 */
-       s8 scan_power;    /* (dBm) regul. eeprom, direct scans, any rate */
-
-       u8 group_index;   /* 0-4, maps channel to group1/2/3/4/5 */
-       u8 band_index;    /* 0-4, maps channel to band1/2/3/4/5 */
-       enum ieee80211_band band;
-
-       /* HT40 channel info */
-       s8 ht40_max_power_avg;  /* (dBm) regul. eeprom, normal Tx, any rate */
-       u8 ht40_flags;          /* flags copied from EEPROM */
-       u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
-};
-
-/*
- * Minimum number of queues. MAX_NUM is defined in hw specific files.
- * Set the minimum to accommodate
- *  - 4 standard TX queues
- *  - the command queue
- *  - 4 PAN TX queues
- *  - the PAN multicast queue, and
- *  - the AUX (TX during scan dwell) queue.
- */
-#define IWL_MIN_NUM_QUEUES     11
-
-/*
- * Command queue depends on iPAN support.
- */
-#define IWL_DEFAULT_CMD_QUEUE_NUM      4
-#define IWL_IPAN_CMD_QUEUE_NUM         9
-
-#define IEEE80211_DATA_LEN              2304
-#define IEEE80211_4ADDR_LEN             30
-#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-#define IWL_SUPPORTED_RATES_IE_LEN         8
-
-#define IWL_INVALID_RATE     0xFF
-#define IWL_INVALID_VALUE    -1
-
-union iwl_ht_rate_supp {
-       u16 rates;
-       struct {
-               u8 siso_rate;
-               u8 mimo_rate;
-       };
-};
-
-#define CFG_HT_RX_AMPDU_FACTOR_8K   (0x0)
-#define CFG_HT_RX_AMPDU_FACTOR_16K  (0x1)
-#define CFG_HT_RX_AMPDU_FACTOR_32K  (0x2)
-#define CFG_HT_RX_AMPDU_FACTOR_64K  (0x3)
-#define CFG_HT_RX_AMPDU_FACTOR_DEF  CFG_HT_RX_AMPDU_FACTOR_64K
-#define CFG_HT_RX_AMPDU_FACTOR_MAX  CFG_HT_RX_AMPDU_FACTOR_64K
-#define CFG_HT_RX_AMPDU_FACTOR_MIN  CFG_HT_RX_AMPDU_FACTOR_8K
-
-/*
- * Maximal MPDU density for TX aggregation
- * 4 - 2us density
- * 5 - 4us density
- * 6 - 8us density
- * 7 - 16us density
- */
-#define CFG_HT_MPDU_DENSITY_2USEC   (0x4)
-#define CFG_HT_MPDU_DENSITY_4USEC   (0x5)
-#define CFG_HT_MPDU_DENSITY_8USEC   (0x6)
-#define CFG_HT_MPDU_DENSITY_16USEC  (0x7)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
-#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
-#define CFG_HT_MPDU_DENSITY_MIN     (0x1)
-
-struct iwl_ht_config {
-       bool single_chain_sufficient;
-       enum ieee80211_smps_mode smps; /* current smps mode */
-};
-
-/* QoS structures */
-struct iwl_qos_info {
-       int qos_active;
-       struct iwl_qosparam_cmd def_qos_parm;
-};
-
-/**
- * enum iwl_agg_state
- *
- * The state machine of the BA agreement establishment / tear down.
- * These states relate to a specific RA / TID.
- *
- * @IWL_AGG_OFF: aggregation is not used
- * @IWL_AGG_STARTING: aggregation are starting (between start and oper)
- * @IWL_AGG_ON: aggregation session is up
- * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
- *     HW queue to be empty from packets for this RA /TID.
- * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
- *     HW queue to be empty from packets for this RA /TID.
- */
-enum iwl_agg_state {
-       IWL_AGG_OFF = 0,
-       IWL_AGG_STARTING,
-       IWL_AGG_ON,
-       IWL_EMPTYING_HW_QUEUE_ADDBA,
-       IWL_EMPTYING_HW_QUEUE_DELBA,
-};
-
-/**
- * struct iwl_ht_agg - aggregation state machine
-
- * This structs holds the states for the BA agreement establishment and tear
- * down. It also holds the state during the BA session itself. This struct is
- * duplicated for each RA / TID.
-
- * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
- *     Tx response (REPLY_TX), and the block ack notification
- *     (REPLY_COMPRESSED_BA).
- * @state: state of the BA agreement establishment / tear down.
- * @txq_id: Tx queue used by the BA session
- * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
- *     the first packet to be sent in legacy HW queue in Tx AGG stop flow.
- *     Basically when next_reclaimed reaches ssn, we can tell mac80211 that
- *     we are ready to finish the Tx AGG stop / start flow.
- * @wait_for_ba: Expect block-ack before next Tx reply
- */
-struct iwl_ht_agg {
-       u32 rate_n_flags;
-       enum iwl_agg_state state;
-       u16 txq_id;
-       u16 ssn;
-       bool wait_for_ba;
-};
-
-/**
- * struct iwl_tid_data - one for each RA / TID
-
- * This structs holds the states for each RA / TID.
-
- * @seq_number: the next WiFi sequence number to use
- * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
- *     This is basically (last acked packet++).
- * @agg: aggregation state machine
- */
-struct iwl_tid_data {
-       u16 seq_number;
-       u16 next_reclaimed;
-       struct iwl_ht_agg agg;
-};
-
-/*
- * Structure should be accessed with sta_lock held. When station addition
- * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only
- * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock
- * held.
- */
-struct iwl_station_entry {
-       struct iwl_addsta_cmd sta;
-       u8 used, ctxid;
-       struct iwl_link_quality_cmd *lq;
-};
-
-/*
- * 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.
- */
-struct iwl_station_priv {
-       struct iwl_rxon_context *ctx;
-       struct iwl_lq_sta lq_sta;
-       atomic_t pending_frames;
-       bool client;
-       bool asleep;
-       u8 max_agg_bufsize;
-       u8 sta_id;
-};
-
-/**
- * struct iwl_vif_priv - driver's private per-interface information
- *
- * When mac80211 allocates a virtual interface, it can allocate
- * space for us to put data into.
- */
-struct iwl_vif_priv {
-       struct iwl_rxon_context *ctx;
-       u8 ibss_bssid_sta_id;
-};
-
-struct iwl_sensitivity_ranges {
-       u16 min_nrg_cck;
-
-       u16 nrg_th_cck;
-       u16 nrg_th_ofdm;
-
-       u16 auto_corr_min_ofdm;
-       u16 auto_corr_min_ofdm_mrc;
-       u16 auto_corr_min_ofdm_x1;
-       u16 auto_corr_min_ofdm_mrc_x1;
-
-       u16 auto_corr_max_ofdm;
-       u16 auto_corr_max_ofdm_mrc;
-       u16 auto_corr_max_ofdm_x1;
-       u16 auto_corr_max_ofdm_mrc_x1;
-
-       u16 auto_corr_max_cck;
-       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;
-};
-
-
-#define KELVIN_TO_CELSIUS(x) ((x)-273)
-#define CELSIUS_TO_KELVIN(x) ((x)+273)
-
-
-/******************************************************************************
- *
- * Functions implemented in core module which are forward declared here
- * for use by iwl-[4-5].c
- *
- * NOTE:  The implementation of these functions are not hardware specific
- * which is why they are in the core module files.
- *
- * Naming convention --
- * iwl_         <-- Is part of iwlwifi
- * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- *
- ****************************************************************************/
-extern void iwl_update_chain_flags(struct iwl_priv *priv);
-extern const u8 iwl_bcast_addr[ETH_ALEN];
-
-#define IWL_OPERATION_MODE_AUTO     0
-#define IWL_OPERATION_MODE_HT_ONLY  1
-#define IWL_OPERATION_MODE_MIXED    2
-#define IWL_OPERATION_MODE_20MHZ    3
-
-#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-
-/* Sensitivity and chain noise calibration */
-#define INITIALIZATION_VALUE           0xFFFF
-#define IWL_CAL_NUM_BEACONS            16
-#define MAXIMUM_ALLOWED_PATHLOSS       15
-
-#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
-
-#define MAX_FA_OFDM  50
-#define MIN_FA_OFDM  5
-#define MAX_FA_CCK   50
-#define MIN_FA_CCK   5
-
-#define AUTO_CORR_STEP_OFDM       1
-
-#define AUTO_CORR_STEP_CCK     3
-#define AUTO_CORR_MAX_TH_CCK   160
-
-#define NRG_DIFF               2
-#define NRG_STEP_CCK           2
-#define NRG_MARGIN             8
-#define MAX_NUMBER_CCK_NO_FA 100
-
-#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
-
-#define CHAIN_A             0
-#define CHAIN_B             1
-#define CHAIN_C             2
-#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
-#define ALL_BAND_FILTER                        0xFF00
-#define IN_BAND_FILTER                 0xFF
-#define MIN_AVERAGE_NOISE_MAX_VALUE    0xFFFFFFFF
-
-#define NRG_NUM_PREV_STAT_L     20
-#define NUM_RX_CHAINS           3
-
-enum iwlagn_false_alarm_state {
-       IWL_FA_TOO_MANY = 0,
-       IWL_FA_TOO_FEW = 1,
-       IWL_FA_GOOD_RANGE = 2,
-};
-
-enum iwlagn_chain_noise_state {
-       IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
-       IWL_CHAIN_NOISE_ACCUMULATE,
-       IWL_CHAIN_NOISE_CALIBRATED,
-       IWL_CHAIN_NOISE_DONE,
-};
-
-/* Sensitivity calib data */
-struct iwl_sensitivity_data {
-       u32 auto_corr_ofdm;
-       u32 auto_corr_ofdm_mrc;
-       u32 auto_corr_ofdm_x1;
-       u32 auto_corr_ofdm_mrc_x1;
-       u32 auto_corr_cck;
-       u32 auto_corr_cck_mrc;
-
-       u32 last_bad_plcp_cnt_ofdm;
-       u32 last_fa_cnt_ofdm;
-       u32 last_bad_plcp_cnt_cck;
-       u32 last_fa_cnt_cck;
-
-       u32 nrg_curr_state;
-       u32 nrg_prev_state;
-       u32 nrg_value[10];
-       u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
-       u32 nrg_silence_ref;
-       u32 nrg_energy_idx;
-       u32 nrg_silence_idx;
-       u32 nrg_th_cck;
-       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 */
-struct iwl_chain_noise_data {
-       u32 active_chains;
-       u32 chain_noise_a;
-       u32 chain_noise_b;
-       u32 chain_noise_c;
-       u32 chain_signal_a;
-       u32 chain_signal_b;
-       u32 chain_signal_c;
-       u16 beacon_count;
-       u8 disconn_array[NUM_RX_CHAINS];
-       u8 delta_gain_code[NUM_RX_CHAINS];
-       u8 radio_write;
-       u8 state;
-};
-
-enum {
-       MEASUREMENT_READY = (1 << 0),
-       MEASUREMENT_ACTIVE = (1 << 1),
-};
-
-enum iwl_nvm_type {
-       NVM_DEVICE_TYPE_EEPROM = 0,
-       NVM_DEVICE_TYPE_OTP,
-};
-
-/*
- * Two types of OTP memory access modes
- *   IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
- *                             based on physical memory addressing
- *   IWL_OTP_ACCESS_RELATIVE - relative address mode,
- *                            based on logical memory addressing
- */
-enum iwl_access_mode {
-       IWL_OTP_ACCESS_ABSOLUTE,
-       IWL_OTP_ACCESS_RELATIVE,
-};
-
-/* reply_tx_statistics (for _agn devices) */
-struct reply_tx_error_statistics {
-       u32 pp_delay;
-       u32 pp_few_bytes;
-       u32 pp_bt_prio;
-       u32 pp_quiet_period;
-       u32 pp_calc_ttak;
-       u32 int_crossed_retry;
-       u32 short_limit;
-       u32 long_limit;
-       u32 fifo_underrun;
-       u32 drain_flow;
-       u32 rfkill_flush;
-       u32 life_expire;
-       u32 dest_ps;
-       u32 host_abort;
-       u32 bt_retry;
-       u32 sta_invalid;
-       u32 frag_drop;
-       u32 tid_disable;
-       u32 fifo_flush;
-       u32 insuff_cf_poll;
-       u32 fail_hw_drop;
-       u32 sta_color_mismatch;
-       u32 unknown;
-};
-
-/* reply_agg_tx_statistics (for _agn devices) */
-struct reply_agg_tx_error_statistics {
-       u32 underrun;
-       u32 bt_prio;
-       u32 few_bytes;
-       u32 abort;
-       u32 last_sent_ttl;
-       u32 last_sent_try;
-       u32 last_sent_bt_kill;
-       u32 scd_query;
-       u32 bad_crc32;
-       u32 response;
-       u32 dump_tx;
-       u32 delay_tx;
-       u32 unknown;
-};
-
-/*
- * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
- * to perform continuous uCode event logging operation if enabled
- */
-#define UCODE_TRACE_PERIOD (10)
-
-/*
- * iwl_event_log: current uCode event log position
- *
- * @ucode_trace: enable/disable ucode continuous trace timer
- * @num_wraps: how many times the event buffer wraps
- * @next_entry:  the entry just before the next one that uCode would fill
- * @non_wraps_count: counter for no wrap detected when dump ucode events
- * @wraps_once_count: counter for wrap once detected when dump ucode events
- * @wraps_more_count: counter for wrap more than once detected
- *                   when dump ucode events
- */
-struct iwl_event_log {
-       bool ucode_trace;
-       u32 num_wraps;
-       u32 next_entry;
-       int non_wraps_count;
-       int wraps_once_count;
-       int wraps_more_count;
-};
-
-#define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
-
-/* BT Antenna Coupling Threshold (dB) */
-#define IWL_BT_ANTENNA_COUPLING_THRESHOLD      (35)
-
-/* Firmware reload counter and Timestamp */
-#define IWL_MIN_RELOAD_DURATION                1000 /* 1000 ms */
-#define IWL_MAX_CONTINUE_RELOAD_CNT    4
-
-
-struct iwl_rf_reset {
-       int reset_request_count;
-       int reset_success_count;
-       int reset_reject_count;
-       unsigned long last_reset_jiffies;
-};
-
-enum iwl_rxon_context_id {
-       IWL_RXON_CTX_BSS,
-       IWL_RXON_CTX_PAN,
-
-       NUM_IWL_RXON_CTX
-};
-
-/* extend beacon time format bit shifting  */
-/*
- * for _agn devices
- * bits 31:22 - extended
- * bits 21:0  - interval
- */
-#define IWLAGN_EXT_BEACON_TIME_POS     22
-
-struct iwl_rxon_context {
-       struct ieee80211_vif *vif;
-
-       u8 mcast_queue;
-       u8 ac_to_queue[IEEE80211_NUM_ACS];
-       u8 ac_to_fifo[IEEE80211_NUM_ACS];
-
-       /*
-        * We could use the vif to indicate active, but we
-        * also need it to be active during disabling when
-        * we already removed the vif for type setting.
-        */
-       bool always_active, is_active;
-
-       bool ht_need_multiple_chains;
-
-       enum iwl_rxon_context_id ctxid;
-
-       u32 interface_modes, exclusive_interface_modes;
-       u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
-
-       /*
-        * We declare this const so it can only be
-        * changed via explicit cast within the
-        * routines that actually update the physical
-        * hardware.
-        */
-       const struct iwl_rxon_cmd active;
-       struct iwl_rxon_cmd staging;
-
-       struct iwl_rxon_time_cmd timing;
-
-       struct iwl_qos_info qos_data;
-
-       u8 bcast_sta_id, ap_sta_id;
-
-       u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
-       u8 qos_cmd;
-       u8 wep_key_cmd;
-
-       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
-       u8 key_mapping_keys;
-
-       __le32 station_flags;
-
-       int beacon_int;
-
-       struct {
-               bool non_gf_sta_present;
-               u8 protection;
-               bool enabled, is_40mhz;
-               u8 extension_chan_offset;
-       } ht;
-};
-
-enum iwl_scan_type {
-       IWL_SCAN_NORMAL,
-       IWL_SCAN_RADIO_RESET,
-       IWL_SCAN_ROC,
-};
-
-/**
- * struct iwl_hw_params
- *
- * Holds the module parameters
- *
- * @tx_chains_num: Number of TX chains
- * @rx_chains_num: Number of RX chains
- * @valid_tx_ant: usable antennas for TX
- * @valid_rx_ant: usable antennas for RX
- * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
- * @sku: sku read from EEPROM
- * @ct_kill_threshold: temperature threshold - in hw dependent unit
- * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
- *     relevant for 1000, 6000 and up
- * @struct iwl_sensitivity_ranges: range of sensitivity values
- * @use_rts_for_aggregation: use rts/cts protection for HT traffic
- */
-struct iwl_hw_params {
-       u8  tx_chains_num;
-       u8  rx_chains_num;
-       u8  valid_tx_ant;
-       u8  valid_rx_ant;
-       u8  ht40_channel;
-       bool use_rts_for_aggregation;
-       u16 sku;
-       u32 ct_kill_threshold;
-       u32 ct_kill_exit_threshold;
-
-       const struct iwl_sensitivity_ranges *sens;
-};
-
-struct iwl_lib_ops {
-       /* set hw dependent parameters */
-       void (*set_hw_params)(struct iwl_priv *priv);
-       int (*set_channel_switch)(struct iwl_priv *priv,
-                                 struct ieee80211_channel_switch *ch_switch);
-       /* device specific configuration */
-       void (*nic_config)(struct iwl_priv *priv);
-
-       /* eeprom operations (as defined in iwl-eeprom.h) */
-       struct iwl_eeprom_ops eeprom_ops;
-
-       /* temperature */
-       void (*temperature)(struct iwl_priv *priv);
-};
-
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-struct iwl_testmode_trace {
-       u32 buff_size;
-       u32 total_size;
-       u32 num_chunks;
-       u8 *cpu_addr;
-       u8 *trace_addr;
-       dma_addr_t dma_addr;
-       bool trace_enabled;
-};
-struct iwl_testmode_mem {
-       u32 buff_size;
-       u32 num_chunks;
-       u8 *buff_addr;
-       bool read_in_progress;
-};
-#endif
-
-struct iwl_wipan_noa_data {
-       struct rcu_head rcu_head;
-       u32 length;
-       u8 data[];
-};
-
-/* Calibration disabling bit mask */
-enum {
-       IWL_CALIB_ENABLE_ALL                    = 0,
-
-       IWL_SENSITIVITY_CALIB_DISABLED          = BIT(0),
-       IWL_CHAIN_NOISE_CALIB_DISABLED          = BIT(1),
-       IWL_TX_POWER_CALIB_DISABLED             = BIT(2),
-
-       IWL_CALIB_DISABLE_ALL                   = 0xFFFFFFFF,
-};
-
-#define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \
-       ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific))
-
-#define IWL_MAC80211_GET_DVM(_hw) \
-       ((struct iwl_priv *) ((struct iwl_op_mode *) \
-       (_hw)->priv)->op_mode_specific)
-
-struct iwl_priv {
-
-       struct iwl_trans *trans;
-       struct device *dev;             /* for debug prints only */
-       const struct iwl_cfg *cfg;
-       const struct iwl_fw *fw;
-       const struct iwl_lib_ops *lib;
-       unsigned long status;
-
-       spinlock_t sta_lock;
-       struct mutex mutex;
-
-       unsigned long transport_queue_stop;
-       bool passive_no_rx;
-#define IWL_INVALID_MAC80211_QUEUE     0xff
-       u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
-       atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
-
-       unsigned long agg_q_alloc[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-
-       /* ieee device used by generic ieee processing code */
-       struct ieee80211_hw *hw;
-       struct ieee80211_channel *ieee_channels;
-       struct ieee80211_rate *ieee_rates;
-
-       struct list_head calib_results;
-
-       struct workqueue_struct *workqueue;
-
-       struct iwl_hw_params hw_params;
-
-       enum ieee80211_band band;
-       u8 valid_contexts;
-
-       void (*pre_rx_handler)(struct iwl_priv *priv,
-                              struct iwl_rx_cmd_buffer *rxb);
-       int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-                                      struct iwl_rx_cmd_buffer *rxb,
-                                      struct iwl_device_cmd *cmd);
-
-       struct iwl_notif_wait_data notif_wait;
-
-       struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
-
-       /* spectrum measurement report caching */
-       struct iwl_spectrum_notification measure_report;
-       u8 measurement_status;
-
-#define IWL_OWNERSHIP_DRIVER   0
-#define IWL_OWNERSHIP_TM       1
-       u8 ucode_owner;
-
-       /* ucode beacon time */
-       u32 ucode_beacon_time;
-       int missed_beacon_threshold;
-
-       /* track IBSS manager (last beacon) status */
-       u32 ibss_manager;
-
-       /* jiffies when last recovery from statistics was performed */
-       unsigned long rx_statistics_jiffies;
-
-       /*counters */
-       u32 rx_handlers_stats[REPLY_MAX];
-
-       /* rf reset */
-       struct iwl_rf_reset rf_reset;
-
-       /* firmware reload counter and timestamp */
-       unsigned long reload_jiffies;
-       int reload_count;
-       bool ucode_loaded;
-       bool init_ucode_run;            /* Don't run init uCode again */
-
-       /* we allocate array of iwl_channel_info for NIC's valid channels.
-        *    Access via channel # using indirect index array */
-       struct iwl_channel_info *channel_info;  /* channel info array */
-       u8 channel_count;       /* # of channels */
-
-       u8 plcp_delta_threshold;
-
-       /* thermal calibration */
-       s32 temperature;        /* Celsius */
-       s32 last_temperature;
-
-       struct iwl_wipan_noa_data __rcu *noa_data;
-
-       /* Scan related variables */
-       unsigned long scan_start;
-       unsigned long scan_start_tsf;
-       void *scan_cmd;
-       enum ieee80211_band scan_band;
-       struct cfg80211_scan_request *scan_request;
-       struct ieee80211_vif *scan_vif;
-       enum iwl_scan_type scan_type;
-       u8 scan_tx_ant[IEEE80211_NUM_BANDS];
-       u8 mgmt_tx_ant;
-
-       /* max number of station keys */
-       u8 sta_key_max_num;
-
-       bool new_scan_threshold_behaviour;
-
-       bool wowlan;
-
-       /* EEPROM MAC addresses */
-       struct mac_address addresses[2];
-
-       struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
-
-       __le16 switch_channel;
-
-       u8 start_calib;
-       struct iwl_sensitivity_data sensitivity_data;
-       struct iwl_chain_noise_data chain_noise_data;
-       __le16 sensitivity_tbl[HD_TABLE_SIZE];
-       __le16 enhance_sensitivity_tbl[ENHANCE_HD_TABLE_ENTRIES];
-
-       struct iwl_ht_config current_ht_config;
-
-       /* Rate scaling data */
-       u8 retry_rate;
-
-       int activity_timer_active;
-
-       struct iwl_power_mgr power_data;
-       struct iwl_tt_mgmt thermal_throttle;
-
-       /* station table variables */
-       int num_stations;
-       struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
-       unsigned long ucode_key_table;
-       struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
-
-       u8 mac80211_registered;
-
-       /* Indication if ieee80211_ops->open has been called */
-       u8 is_open;
-
-       enum nl80211_iftype iw_mode;
-
-       /* Last Rx'd beacon timestamp */
-       u64 timestamp;
-
-       struct {
-               __le32 flag;
-               struct statistics_general_common common;
-               struct statistics_rx_non_phy rx_non_phy;
-               struct statistics_rx_phy rx_ofdm;
-               struct statistics_rx_ht_phy rx_ofdm_ht;
-               struct statistics_rx_phy rx_cck;
-               struct statistics_tx tx;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               struct statistics_bt_activity bt_activity;
-               __le32 num_bt_kills, accum_num_bt_kills;
-#endif
-               spinlock_t lock;
-       } statistics;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       struct {
-               struct statistics_general_common common;
-               struct statistics_rx_non_phy rx_non_phy;
-               struct statistics_rx_phy rx_ofdm;
-               struct statistics_rx_ht_phy rx_ofdm_ht;
-               struct statistics_rx_phy rx_cck;
-               struct statistics_tx tx;
-               struct statistics_bt_activity bt_activity;
-       } accum_stats, delta_stats, max_delta_stats;
-#endif
-
-       /*
-        * reporting the number of tids has AGG on. 0 means
-        * no AGGREGATION
-        */
-       u8 agg_tids_count;
-
-       struct iwl_rx_phy_res last_phy_res;
-       bool last_phy_res_valid;
-
-       /*
-        * chain noise reset and gain commands are the
-        * two extra calibration commands follows the standard
-        * phy calibration commands
-        */
-       u8 phy_calib_chain_noise_reset_cmd;
-       u8 phy_calib_chain_noise_gain_cmd;
-
-       /* counts reply_tx error */
-       struct reply_tx_error_statistics reply_tx_stats;
-       struct reply_agg_tx_error_statistics reply_agg_tx_stats;
-
-       /* remain-on-channel offload support */
-       struct ieee80211_channel *hw_roc_channel;
-       struct delayed_work hw_roc_disable_work;
-       enum nl80211_channel_type hw_roc_chantype;
-       int hw_roc_duration;
-       bool hw_roc_setup, hw_roc_start_notified;
-
-       /* bt coex */
-       u8 bt_enable_flag;
-       u8 bt_status;
-       u8 bt_traffic_load, last_bt_traffic_load;
-       bool bt_ch_announce;
-       bool bt_full_concurrent;
-       bool bt_ant_couple_ok;
-       __le32 kill_ack_mask;
-       __le32 kill_cts_mask;
-       __le16 bt_valid;
-       bool reduced_txpower;
-       u16 bt_on_thresh;
-       u16 bt_duration;
-       u16 dynamic_frag_thresh;
-       u8 bt_ci_compliance;
-       struct work_struct bt_traffic_change_work;
-       bool bt_enable_pspoll;
-       struct iwl_rxon_context *cur_rssi_ctx;
-       bool bt_is_sco;
-
-       struct work_struct restart;
-       struct work_struct scan_completed;
-       struct work_struct abort_scan;
-
-       struct work_struct beacon_update;
-       struct iwl_rxon_context *beacon_ctx;
-       struct sk_buff *beacon_skb;
-       void *beacon_cmd;
-
-       struct work_struct tt_work;
-       struct work_struct ct_enter;
-       struct work_struct ct_exit;
-       struct work_struct start_internal_scan;
-       struct work_struct tx_flush;
-       struct work_struct bt_full_concurrency;
-       struct work_struct bt_runtime_config;
-
-       struct delayed_work scan_check;
-
-       /* TX Power */
-       s8 tx_power_user_lmt;
-       s8 tx_power_device_lmt;
-       s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */
-       s8 tx_power_next;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       /* debugfs */
-       struct dentry *debugfs_dir;
-       u32 dbgfs_sram_offset, dbgfs_sram_len;
-       bool disable_ht40;
-       void *wowlan_sram;
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-
-       /* eeprom -- this is in the card's little endian byte order */
-       u8 *eeprom;
-       enum iwl_nvm_type nvm_device_type;
-
-       struct work_struct txpower_work;
-       u32 calib_disabled;
-       struct work_struct run_time_calib_work;
-       struct timer_list statistics_periodic;
-       struct timer_list ucode_trace;
-
-       struct iwl_event_log event_log;
-
-       struct led_classdev led;
-       unsigned long blink_on, blink_off;
-       bool led_registered;
-#ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE
-       struct iwl_testmode_trace testmode_trace;
-       struct iwl_testmode_mem testmode_mem;
-       u32 tm_fixed_rate;
-#endif
-
-       /* WoWLAN GTK rekey data */
-       u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
-       __le64 replay_ctr;
-       __le16 last_seq_ctl;
-       bool have_rekey_data;
-
-       /* device_pointers: pointers to ucode event tables */
-       struct {
-               u32 error_event_table;
-               u32 log_event_table;
-       } device_pointers;
-
-       /* indicator of loaded ucode image */
-       enum iwl_ucode_type cur_ucode;
-}; /*iwl_priv */
-
-extern struct kmem_cache *iwl_tx_cmd_pool;
-
-static inline struct iwl_rxon_context *
-iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
-{
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-
-       return vif_priv->ctx;
-}
-
-#define for_each_context(priv, ctx)                            \
-       for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];           \
-            ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)    \
-               if (priv->valid_contexts & BIT(ctx->ctxid))
-
-static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
-{
-       return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
-}
-
-static inline int iwl_is_associated(struct iwl_priv *priv,
-                                   enum iwl_rxon_context_id ctxid)
-{
-       return iwl_is_associated_ctx(&priv->contexts[ctxid]);
-}
-
-static inline int iwl_is_any_associated(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       for_each_context(priv, ctx)
-               if (iwl_is_associated_ctx(ctx))
-                       return true;
-       return false;
-}
-
-static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
-{
-       if (ch_info == NULL)
-               return 0;
-       return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
-}
-
-static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
-{
-       return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
-}
-
-static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
-{
-       return ch_info->band == IEEE80211_BAND_5GHZ;
-}
-
-static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
-{
-       return ch_info->band == IEEE80211_BAND_2GHZ;
-}
-
-static inline int is_channel_passive(const struct iwl_channel_info *ch)
-{
-       return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
-}
-
-static inline int is_channel_ibss(const struct iwl_channel_info *ch)
-{
-       return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
-}
-
-#endif                         /* __iwl_dev_h__ */
index 91f45e71e0a2568498e60f01003f8c79e27670f7..70191ddbd8f6ac1cbcd787fee1a511a13f7f655f 100644 (file)
@@ -42,4 +42,9 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
 #endif
index 06203d6a1d86fe50c38c590ded15954aa0ab0c04..65364793021f840206f0362402d956bcc2eaa68a 100644 (file)
@@ -28,6 +28,7 @@
 #define __IWLWIFI_DEVICE_TRACE
 
 #include <linux/tracepoint.h>
+#include <linux/device.h>
 
 
 #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
index fac67a526a30880199bb12b8fb7310e6a3471a75..a175997e782965022703e7850a2600f62b5da9ac 100644 (file)
 /* private includes */
 #include "iwl-fw-file.h"
 
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/*
+ * module name, copyright, version, etc.
+ */
+#define DRV_DESCRIPTION        "Intel(R) Wireless WiFi driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#define DRV_VERSION     IWLWIFI_VERSION VD
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+
 /**
  * struct iwl_drv - drv common data
+ * @list: list of drv structures using this opmode
  * @fw: the iwl_fw structure
  * @op_mode: the running op_mode
  * @trans: transport layer
  * @request_firmware_complete: the firmware has been obtained from user space
  */
 struct iwl_drv {
+       struct list_head list;
        struct iwl_fw fw;
 
        struct iwl_op_mode *op_mode;
@@ -102,7 +128,19 @@ struct iwl_drv {
        struct completion request_firmware_complete;
 };
 
-
+#define DVM_OP_MODE    0
+#define MVM_OP_MODE    1
+
+/* Protects the table contents, i.e. the ops pointer & drv list */
+static struct mutex iwlwifi_opmode_table_mtx;
+static struct iwlwifi_opmode_table {
+       const char *name;                       /* name: iwldvm, iwlmvm, etc */
+       const struct iwl_op_mode_ops *ops;      /* pointer to op_mode ops */
+       struct list_head drv;           /* list of devices using this op_mode */
+} iwlwifi_opmode_table[] = {           /* ops set when driver is initialized */
+       { .name = "iwldvm", .ops = NULL },
+       { .name = "iwlmvm", .ops = NULL },
+};
 
 /*
  * struct fw_sec: Just for the image parsing proccess.
@@ -721,7 +759,6 @@ static int validate_sec_sizes(struct iwl_drv *drv,
        return 0;
 }
 
-
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -733,6 +770,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        struct iwl_drv *drv = context;
        struct iwl_fw *fw = &drv->fw;
        struct iwl_ucode_header *ucode;
+       struct iwlwifi_opmode_table *op;
        int err;
        struct iwl_firmware_pieces pieces;
        const unsigned int api_max = drv->cfg->ucode_api_max;
@@ -740,6 +778,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        const unsigned int api_min = drv->cfg->ucode_api_min;
        u32 api_ver;
        int i;
+       bool load_module = false;
 
        fw->ucode_capa.max_probe_length = 200;
        fw->ucode_capa.standard_phy_calibration_size =
@@ -862,10 +901,24 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* We have our copies now, allow OS release its copies */
        release_firmware(ucode_raw);
 
-       drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw);
+       mutex_lock(&iwlwifi_opmode_table_mtx);
+       op = &iwlwifi_opmode_table[DVM_OP_MODE];
 
-       if (!drv->op_mode)
-               goto out_unbind;
+       /* add this device to the list of devices using this op_mode */
+       list_add_tail(&drv->list, &op->drv);
+
+       if (op->ops) {
+               const struct iwl_op_mode_ops *ops = op->ops;
+               drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw);
+
+               if (!drv->op_mode) {
+                       mutex_unlock(&iwlwifi_opmode_table_mtx);
+                       goto out_unbind;
+               }
+       } else {
+               load_module = true;
+       }
+       mutex_unlock(&iwlwifi_opmode_table_mtx);
 
        /*
         * Complete the firmware request last so that
@@ -873,6 +926,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
         * are doing the start() above.
         */
        complete(&drv->request_firmware_complete);
+
+       /*
+        * Load the module last so we don't block anything
+        * else from proceeding if the module fails to load
+        * or hangs loading.
+        */
+       if (load_module)
+               request_module("%s", op->name);
        return;
 
  try_again:
@@ -906,6 +967,7 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
        drv->cfg = cfg;
 
        init_completion(&drv->request_firmware_complete);
+       INIT_LIST_HEAD(&drv->list);
 
        ret = iwl_request_firmware(drv, true);
 
@@ -928,6 +990,16 @@ void iwl_drv_stop(struct iwl_drv *drv)
 
        iwl_dealloc_ucode(drv);
 
+       mutex_lock(&iwlwifi_opmode_table_mtx);
+       /*
+        * List is empty (this item wasn't added)
+        * when firmware loading failed -- in that
+        * case we can't remove it from any list.
+        */
+       if (!list_empty(&drv->list))
+               list_del(&drv->list);
+       mutex_unlock(&iwlwifi_opmode_table_mtx);
+
        kfree(drv);
 }
 
@@ -943,6 +1015,75 @@ struct iwl_mod_params iwlwifi_mod_params = {
        .auto_agg = true,
        /* the rest are 0 by default */
 };
+EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
+
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
+{
+       int i;
+       struct iwl_drv *drv;
+
+       mutex_lock(&iwlwifi_opmode_table_mtx);
+       for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+               if (strcmp(iwlwifi_opmode_table[i].name, name))
+                       continue;
+               iwlwifi_opmode_table[i].ops = ops;
+               list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list)
+                       drv->op_mode = ops->start(drv->trans, drv->cfg,
+                                                 &drv->fw);
+               mutex_unlock(&iwlwifi_opmode_table_mtx);
+               return 0;
+       }
+       mutex_unlock(&iwlwifi_opmode_table_mtx);
+       return -EIO;
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_register);
+
+void iwl_opmode_deregister(const char *name)
+{
+       int i;
+       struct iwl_drv *drv;
+
+       mutex_lock(&iwlwifi_opmode_table_mtx);
+       for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) {
+               if (strcmp(iwlwifi_opmode_table[i].name, name))
+                       continue;
+               iwlwifi_opmode_table[i].ops = NULL;
+
+               /* call the stop routine for all devices */
+               list_for_each_entry(drv, &iwlwifi_opmode_table[i].drv, list) {
+                       if (drv->op_mode) {
+                               iwl_op_mode_stop(drv->op_mode);
+                               drv->op_mode = NULL;
+                       }
+               }
+               mutex_unlock(&iwlwifi_opmode_table_mtx);
+               return;
+       }
+       mutex_unlock(&iwlwifi_opmode_table_mtx);
+}
+EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
+
+static int __init iwl_drv_init(void)
+{
+       int i;
+
+       mutex_init(&iwlwifi_opmode_table_mtx);
+
+       for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
+               INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
+
+       pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+       pr_info(DRV_COPYRIGHT "\n");
+
+       return iwl_pci_register_driver();
+}
+module_init(iwl_drv_init);
+
+static void __exit iwl_drv_exit(void)
+{
+       iwl_pci_unregister_driver();
+}
+module_exit(iwl_drv_exit);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 module_param_named(debug, iwlwifi_mod_params.debug_level, uint,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
new file mode 100644 (file)
index 0000000..f10170f
--- /dev/null
@@ -0,0 +1,903 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "iwl-modparams.h"
+#include "iwl-eeprom-parse.h"
+
+/* EEPROM offset definitions */
+
+/* indirect access definitions */
+#define ADDRESS_MSK                 0x0000FFFF
+#define INDIRECT_TYPE_MSK           0x000F0000
+#define INDIRECT_HOST               0x00010000
+#define INDIRECT_GENERAL            0x00020000
+#define INDIRECT_REGULATORY         0x00030000
+#define INDIRECT_CALIBRATION        0x00040000
+#define INDIRECT_PROCESS_ADJST      0x00050000
+#define INDIRECT_OTHERS             0x00060000
+#define INDIRECT_TXP_LIMIT          0x00070000
+#define INDIRECT_TXP_LIMIT_SIZE     0x00080000
+#define INDIRECT_ADDRESS            0x00100000
+
+/* corresponding link offsets in EEPROM */
+#define EEPROM_LINK_HOST             (2*0x64)
+#define EEPROM_LINK_GENERAL          (2*0x65)
+#define EEPROM_LINK_REGULATORY       (2*0x66)
+#define EEPROM_LINK_CALIBRATION      (2*0x67)
+#define EEPROM_LINK_PROCESS_ADJST    (2*0x68)
+#define EEPROM_LINK_OTHERS           (2*0x69)
+#define EEPROM_LINK_TXP_LIMIT        (2*0x6a)
+#define EEPROM_LINK_TXP_LIMIT_SIZE   (2*0x6b)
+
+/* General */
+#define EEPROM_DEVICE_ID                    (2*0x08)   /* 2 bytes */
+#define EEPROM_SUBSYSTEM_ID                (2*0x0A)    /* 2 bytes */
+#define EEPROM_MAC_ADDRESS                  (2*0x15)   /* 6  bytes */
+#define EEPROM_BOARD_REVISION               (2*0x35)   /* 2  bytes */
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1) /* 9  bytes */
+#define EEPROM_VERSION                      (2*0x44)   /* 2  bytes */
+#define EEPROM_SKU_CAP                      (2*0x45)   /* 2  bytes */
+#define EEPROM_OEM_MODE                     (2*0x46)   /* 2  bytes */
+#define EEPROM_RADIO_CONFIG                 (2*0x48)   /* 2  bytes */
+#define EEPROM_NUM_MAC_ADDRESS              (2*0x4C)   /* 2  bytes */
+
+/* calibration */
+struct iwl_eeprom_calib_hdr {
+       u8 version;
+       u8 pa_type;
+       __le16 voltage;
+} __packed;
+
+#define EEPROM_CALIB_ALL       (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
+#define EEPROM_XTAL            ((2*0x128) | EEPROM_CALIB_ALL)
+
+/* temperature */
+#define EEPROM_KELVIN_TEMPERATURE      ((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_RAW_TEMPERATURE         ((2*0x12B) | EEPROM_CALIB_ALL)
+
+/*
+ * EEPROM bands
+ * These are the channel numbers from each band in the order
+ * that they are stored in the EEPROM band information. Note
+ * that EEPROM bands aren't the same as mac80211 bands, and
+ * there are even special "ht40 bands" in the EEPROM.
+ */
+static const u8 iwl_eeprom_band_1[14] = { /* 2.4 GHz */
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+static const u8 iwl_eeprom_band_2[] = {        /* 4915-5080MHz */
+       183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = {        /* 5170-5320MHz */
+       34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = {        /* 5500-5700MHz */
+       100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = {        /* 5725-5825MHz */
+       145, 149, 153, 157, 161, 165
+};
+
+static const u8 iwl_eeprom_band_6[] = {        /* 2.4 ht40 channel */
+       1, 2, 3, 4, 5, 6, 7
+};
+
+static const u8 iwl_eeprom_band_7[] = {        /* 5.2 ht40 channel */
+       36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+#define IWL_NUM_CHANNELS       (ARRAY_SIZE(iwl_eeprom_band_1) + \
+                                ARRAY_SIZE(iwl_eeprom_band_2) + \
+                                ARRAY_SIZE(iwl_eeprom_band_3) + \
+                                ARRAY_SIZE(iwl_eeprom_band_4) + \
+                                ARRAY_SIZE(iwl_eeprom_band_5))
+
+/* rate data (static) */
+static struct ieee80211_rate iwl_cfg80211_rates[] = {
+       { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
+       { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+       { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+       { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
+       { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
+       { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
+       { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
+       { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
+       { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
+       { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
+       { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
+       { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
+};
+#define RATES_24_OFFS  0
+#define N_RATES_24     ARRAY_SIZE(iwl_cfg80211_rates)
+#define RATES_52_OFFS  4
+#define N_RATES_52     (N_RATES_24 - RATES_52_OFFS)
+
+/* EEPROM reading functions */
+
+static u16 iwl_eeprom_query16(const u8 *eeprom, size_t eeprom_size, int offset)
+{
+       if (WARN_ON(offset + sizeof(u16) > eeprom_size))
+               return 0;
+       return le16_to_cpup((__le16 *)(eeprom + offset));
+}
+
+static u32 eeprom_indirect_address(const u8 *eeprom, size_t eeprom_size,
+                                  u32 address)
+{
+       u16 offset = 0;
+
+       if ((address & INDIRECT_ADDRESS) == 0)
+               return address;
+
+       switch (address & INDIRECT_TYPE_MSK) {
+       case INDIRECT_HOST:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_HOST);
+               break;
+       case INDIRECT_GENERAL:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_GENERAL);
+               break;
+       case INDIRECT_REGULATORY:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_REGULATORY);
+               break;
+       case INDIRECT_TXP_LIMIT:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_TXP_LIMIT);
+               break;
+       case INDIRECT_TXP_LIMIT_SIZE:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_TXP_LIMIT_SIZE);
+               break;
+       case INDIRECT_CALIBRATION:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_CALIBRATION);
+               break;
+       case INDIRECT_PROCESS_ADJST:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_PROCESS_ADJST);
+               break;
+       case INDIRECT_OTHERS:
+               offset = iwl_eeprom_query16(eeprom, eeprom_size,
+                                           EEPROM_LINK_OTHERS);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       /* translate the offset from words to byte */
+       return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+static const u8 *iwl_eeprom_query_addr(const u8 *eeprom, size_t eeprom_size,
+                                      u32 offset)
+{
+       u32 address = eeprom_indirect_address(eeprom, eeprom_size, offset);
+
+       if (WARN_ON(address >= eeprom_size))
+               return NULL;
+
+       return &eeprom[address];
+}
+
+static int iwl_eeprom_read_calib(const u8 *eeprom, size_t eeprom_size,
+                                struct iwl_eeprom_data *data)
+{
+       struct iwl_eeprom_calib_hdr *hdr;
+
+       hdr = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+                                           EEPROM_CALIB_ALL);
+       if (!hdr)
+               return -ENODATA;
+       data->calib_version = hdr->version;
+       data->calib_voltage = hdr->voltage;
+
+       return 0;
+}
+
+/**
+ * enum iwl_eeprom_channel_flags - channel flags in EEPROM
+ * @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo
+ * @EEPROM_CHANNEL_IBSS: usable as an IBSS channel
+ * @EEPROM_CHANNEL_ACTIVE: active scanning allowed
+ * @EEPROM_CHANNEL_RADAR: radar detection required
+ * @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?)
+ * @EEPROM_CHANNEL_DFS: dynamic freq selection candidate
+ */
+enum iwl_eeprom_channel_flags {
+       EEPROM_CHANNEL_VALID = BIT(0),
+       EEPROM_CHANNEL_IBSS = BIT(1),
+       EEPROM_CHANNEL_ACTIVE = BIT(3),
+       EEPROM_CHANNEL_RADAR = BIT(4),
+       EEPROM_CHANNEL_WIDE = BIT(5),
+       EEPROM_CHANNEL_DFS = BIT(7),
+};
+
+/**
+ * struct iwl_eeprom_channel - EEPROM channel data
+ * @flags: %EEPROM_CHANNEL_* flags
+ * @max_power_avg: max power (in dBm) on this channel, at most 31 dBm
+ */
+struct iwl_eeprom_channel {
+       u8 flags;
+       s8 max_power_avg;
+} __packed;
+
+
+enum iwl_eeprom_enhanced_txpwr_flags {
+       IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0),
+       IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1),
+       IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2),
+       IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3),
+       IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4),
+       IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5),
+       IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6),
+       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7),
+};
+
+/**
+ * iwl_eeprom_enhanced_txpwr structure
+ * @flags: entry flags
+ * @channel: channel number
+ * @chain_a_max_pwr: chain a max power in 1/2 dBm
+ * @chain_b_max_pwr: chain b max power in 1/2 dBm
+ * @chain_c_max_pwr: chain c max power in 1/2 dBm
+ * @delta_20_in_40: 20-in-40 deltas (hi/lo)
+ * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
+ * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
+ *
+ * This structure presents the enhanced regulatory tx power limit layout
+ * in an EEPROM image.
+ */
+struct iwl_eeprom_enhanced_txpwr {
+       u8 flags;
+       u8 channel;
+       s8 chain_a_max;
+       s8 chain_b_max;
+       s8 chain_c_max;
+       u8 delta_20_in_40;
+       s8 mimo2_max;
+       s8 mimo3_max;
+} __packed;
+
+static s8 iwl_get_max_txpwr_half_dbm(const struct iwl_eeprom_data *data,
+                                    struct iwl_eeprom_enhanced_txpwr *txp)
+{
+       s8 result = 0; /* (.5 dBm) */
+
+       /* Take the highest tx power from any valid chains */
+       if (data->valid_tx_ant & ANT_A && txp->chain_a_max > result)
+               result = txp->chain_a_max;
+
+       if (data->valid_tx_ant & ANT_B && txp->chain_b_max > result)
+               result = txp->chain_b_max;
+
+       if (data->valid_tx_ant & ANT_C && txp->chain_c_max > result)
+               result = txp->chain_c_max;
+
+       if ((data->valid_tx_ant == ANT_AB ||
+            data->valid_tx_ant == ANT_BC ||
+            data->valid_tx_ant == ANT_AC) && txp->mimo2_max > result)
+               result = txp->mimo2_max;
+
+       if (data->valid_tx_ant == ANT_ABC && txp->mimo3_max > result)
+               result = txp->mimo3_max;
+
+       return result;
+}
+
+#define EEPROM_TXP_OFFS        (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+#define TXP_CHECK_AND_PRINT(x) \
+       ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) ? # x " " : "")
+
+static void
+iwl_eeprom_enh_txp_read_element(struct iwl_eeprom_data *data,
+                               struct iwl_eeprom_enhanced_txpwr *txp,
+                               int n_channels, s8 max_txpower_avg)
+{
+       int ch_idx;
+       enum ieee80211_band band;
+
+       band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+               IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+       for (ch_idx = 0; ch_idx < n_channels; ch_idx++) {
+               struct ieee80211_channel *chan = &data->channels[ch_idx];
+
+               /* update matching channel or from common data only */
+               if (txp->channel != 0 && chan->hw_value != txp->channel)
+                       continue;
+
+               /* update matching band only */
+               if (band != chan->band)
+                       continue;
+
+               if (chan->max_power < max_txpower_avg &&
+                   !(txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ))
+                       chan->max_power = max_txpower_avg;
+       }
+}
+
+static void iwl_eeprom_enhanced_txpower(struct device *dev,
+                                       struct iwl_eeprom_data *data,
+                                       const u8 *eeprom, size_t eeprom_size,
+                                       int n_channels)
+{
+       struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+       int idx, entries;
+       __le16 *txp_len;
+       s8 max_txp_avg_halfdbm;
+
+       BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+       /* the length is in 16-bit words, but we want entries */
+       txp_len = (__le16 *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+                                                 EEPROM_TXP_SZ_OFFS);
+       entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+       txp_array = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size,
+                                                 EEPROM_TXP_OFFS);
+
+       for (idx = 0; idx < entries; idx++) {
+               txp = &txp_array[idx];
+               /* skip invalid entries */
+               if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+                       continue;
+
+               IWL_DEBUG_EEPROM(dev, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
+                                (txp->channel && (txp->flags &
+                                       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
+                                       "Common " : (txp->channel) ?
+                                       "Channel" : "Common",
+                                (txp->channel),
+                                TXP_CHECK_AND_PRINT(VALID),
+                                TXP_CHECK_AND_PRINT(BAND_52G),
+                                TXP_CHECK_AND_PRINT(OFDM),
+                                TXP_CHECK_AND_PRINT(40MHZ),
+                                TXP_CHECK_AND_PRINT(HT_AP),
+                                TXP_CHECK_AND_PRINT(RES1),
+                                TXP_CHECK_AND_PRINT(RES2),
+                                TXP_CHECK_AND_PRINT(COMMON_TYPE),
+                                txp->flags);
+               IWL_DEBUG_EEPROM(dev,
+                                "\t\t chain_A: 0x%02x chain_B: 0X%02x chain_C: 0X%02x\n",
+                                txp->chain_a_max, txp->chain_b_max,
+                                txp->chain_c_max);
+               IWL_DEBUG_EEPROM(dev,
+                                "\t\t MIMO2: 0x%02x MIMO3: 0x%02x High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n",
+                                txp->mimo2_max, txp->mimo3_max,
+                                ((txp->delta_20_in_40 & 0xf0) >> 4),
+                                (txp->delta_20_in_40 & 0x0f));
+
+               max_txp_avg_halfdbm = iwl_get_max_txpwr_half_dbm(data, txp);
+
+               iwl_eeprom_enh_txp_read_element(data, txp, n_channels,
+                               DIV_ROUND_UP(max_txp_avg_halfdbm, 2));
+
+               if (max_txp_avg_halfdbm > data->max_tx_pwr_half_dbm)
+                       data->max_tx_pwr_half_dbm = max_txp_avg_halfdbm;
+       }
+}
+
+static void iwl_init_band_reference(const struct iwl_cfg *cfg,
+                                   const u8 *eeprom, size_t eeprom_size,
+                                   int eeprom_band, int *eeprom_ch_count,
+                                   const struct iwl_eeprom_channel **ch_info,
+                                   const u8 **eeprom_ch_array)
+{
+       u32 offset = cfg->eeprom_params->regulatory_bands[eeprom_band - 1];
+
+       offset |= INDIRECT_ADDRESS | INDIRECT_REGULATORY;
+
+       *ch_info = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, offset);
+
+       switch (eeprom_band) {
+       case 1:         /* 2.4GHz band */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+               *eeprom_ch_array = iwl_eeprom_band_1;
+               break;
+       case 2:         /* 4.9GHz band */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+               *eeprom_ch_array = iwl_eeprom_band_2;
+               break;
+       case 3:         /* 5.2GHz band */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+               *eeprom_ch_array = iwl_eeprom_band_3;
+               break;
+       case 4:         /* 5.5GHz band */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+               *eeprom_ch_array = iwl_eeprom_band_4;
+               break;
+       case 5:         /* 5.7GHz band */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+               *eeprom_ch_array = iwl_eeprom_band_5;
+               break;
+       case 6:         /* 2.4GHz ht40 channels */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+               *eeprom_ch_array = iwl_eeprom_band_6;
+               break;
+       case 7:         /* 5 GHz ht40 channels */
+               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+               *eeprom_ch_array = iwl_eeprom_band_7;
+               break;
+       default:
+               *eeprom_ch_count = 0;
+               *eeprom_ch_array = NULL;
+               WARN_ON(1);
+       }
+}
+
+#define CHECK_AND_PRINT(x) \
+       ((eeprom_ch->flags & EEPROM_CHANNEL_##x) ? # x " " : "")
+
+static void iwl_mod_ht40_chan_info(struct device *dev,
+                                  struct iwl_eeprom_data *data, int n_channels,
+                                  enum ieee80211_band band, u16 channel,
+                                  const struct iwl_eeprom_channel *eeprom_ch,
+                                  u8 clear_ht40_extension_channel)
+{
+       struct ieee80211_channel *chan = NULL;
+       int i;
+
+       for (i = 0; i < n_channels; i++) {
+               if (data->channels[i].band != band)
+                       continue;
+               if (data->channels[i].hw_value != channel)
+                       continue;
+               chan = &data->channels[i];
+               break;
+       }
+
+       if (!chan)
+               return;
+
+       IWL_DEBUG_EEPROM(dev,
+                        "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+                        channel,
+                        band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
+                        CHECK_AND_PRINT(IBSS),
+                        CHECK_AND_PRINT(ACTIVE),
+                        CHECK_AND_PRINT(RADAR),
+                        CHECK_AND_PRINT(WIDE),
+                        CHECK_AND_PRINT(DFS),
+                        eeprom_ch->flags,
+                        eeprom_ch->max_power_avg,
+                        ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) &&
+                         !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? ""
+                                                                     : "not ");
+
+       if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
+               chan->flags &= ~clear_ht40_extension_channel;
+}
+
+#define CHECK_AND_PRINT_I(x)   \
+       ((eeprom_ch_info[ch_idx].flags & EEPROM_CHANNEL_##x) ? # x " " : "")
+
+static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
+                               struct iwl_eeprom_data *data,
+                               const u8 *eeprom, size_t eeprom_size)
+{
+       int band, ch_idx;
+       const struct iwl_eeprom_channel *eeprom_ch_info;
+       const u8 *eeprom_ch_array;
+       int eeprom_ch_count;
+       int n_channels = 0;
+
+       /*
+        * Loop through the 5 EEPROM bands and add them to the parse list
+        */
+       for (band = 1; band <= 5; band++) {
+               struct ieee80211_channel *channel;
+
+               iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
+                                       &eeprom_ch_count, &eeprom_ch_info,
+                                       &eeprom_ch_array);
+
+               /* Loop through each band adding each of the channels */
+               for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
+                       const struct iwl_eeprom_channel *eeprom_ch;
+
+                       eeprom_ch = &eeprom_ch_info[ch_idx];
+
+                       if (!(eeprom_ch->flags & EEPROM_CHANNEL_VALID)) {
+                               IWL_DEBUG_EEPROM(dev,
+                                                "Ch. %d Flags %x [%sGHz] - No traffic\n",
+                                                eeprom_ch_array[ch_idx],
+                                                eeprom_ch_info[ch_idx].flags,
+                                                (band != 1) ? "5.2" : "2.4");
+                               continue;
+                       }
+
+                       channel = &data->channels[n_channels];
+                       n_channels++;
+
+                       channel->hw_value = eeprom_ch_array[ch_idx];
+                       channel->band = (band == 1) ? IEEE80211_BAND_2GHZ
+                                                   : IEEE80211_BAND_5GHZ;
+                       channel->center_freq =
+                               ieee80211_channel_to_frequency(
+                                       channel->hw_value, channel->band);
+
+                       /* set no-HT40, will enable as appropriate later */
+                       channel->flags = IEEE80211_CHAN_NO_HT40;
+
+                       if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
+                               channel->flags |= IEEE80211_CHAN_NO_IBSS;
+
+                       if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
+                               channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+                       if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
+                               channel->flags |= IEEE80211_CHAN_RADAR;
+
+                       /* Initialize regulatory-based run-time data */
+                       channel->max_power =
+                               eeprom_ch_info[ch_idx].max_power_avg;
+                       IWL_DEBUG_EEPROM(dev,
+                                        "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+                                        channel->hw_value,
+                                        (band != 1) ? "5.2" : "2.4",
+                                        CHECK_AND_PRINT_I(VALID),
+                                        CHECK_AND_PRINT_I(IBSS),
+                                        CHECK_AND_PRINT_I(ACTIVE),
+                                        CHECK_AND_PRINT_I(RADAR),
+                                        CHECK_AND_PRINT_I(WIDE),
+                                        CHECK_AND_PRINT_I(DFS),
+                                        eeprom_ch_info[ch_idx].flags,
+                                        eeprom_ch_info[ch_idx].max_power_avg,
+                                        ((eeprom_ch_info[ch_idx].flags &
+                                                       EEPROM_CHANNEL_IBSS) &&
+                                         !(eeprom_ch_info[ch_idx].flags &
+                                                       EEPROM_CHANNEL_RADAR))
+                                               ? "" : "not ");
+               }
+       }
+
+       if (cfg->eeprom_params->enhanced_txpower) {
+               /*
+                * for newer device (6000 series and up)
+                * EEPROM contain enhanced tx power information
+                * driver need to process addition information
+                * to determine the max channel tx power limits
+                */
+               iwl_eeprom_enhanced_txpower(dev, data, eeprom, eeprom_size,
+                                           n_channels);
+       } else {
+               /* All others use data from channel map */
+               int i;
+
+               data->max_tx_pwr_half_dbm = -128;
+
+               for (i = 0; i < n_channels; i++)
+                       data->max_tx_pwr_half_dbm =
+                               max_t(s8, data->max_tx_pwr_half_dbm,
+                                     data->channels[i].max_power * 2);
+       }
+
+       /* Check if we do have HT40 channels */
+       if (cfg->eeprom_params->regulatory_bands[5] ==
+                               EEPROM_REGULATORY_BAND_NO_HT40 &&
+           cfg->eeprom_params->regulatory_bands[6] ==
+                               EEPROM_REGULATORY_BAND_NO_HT40)
+               return n_channels;
+
+       /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
+       for (band = 6; band <= 7; band++) {
+               enum ieee80211_band ieeeband;
+
+               iwl_init_band_reference(cfg, eeprom, eeprom_size, band,
+                                       &eeprom_ch_count, &eeprom_ch_info,
+                                       &eeprom_ch_array);
+
+               /* EEPROM band 6 is 2.4, band 7 is 5 GHz */
+               ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ
+                                      : IEEE80211_BAND_5GHZ;
+
+               /* Loop through each band adding each of the channels */
+               for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) {
+                       /* Set up driver's info for lower half */
+                       iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
+                                              eeprom_ch_array[ch_idx],
+                                              &eeprom_ch_info[ch_idx],
+                                              IEEE80211_CHAN_NO_HT40PLUS);
+
+                       /* Set up driver's info for upper half */
+                       iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband,
+                                              eeprom_ch_array[ch_idx] + 4,
+                                              &eeprom_ch_info[ch_idx],
+                                              IEEE80211_CHAN_NO_HT40MINUS);
+               }
+       }
+
+       return n_channels;
+}
+
+static int iwl_init_sband_channels(struct iwl_eeprom_data *data,
+                                  struct ieee80211_supported_band *sband,
+                                  int n_channels, enum ieee80211_band band)
+{
+       struct ieee80211_channel *chan = &data->channels[0];
+       int n = 0, idx = 0;
+
+       while (chan->band != band && idx < n_channels)
+               chan = &data->channels[++idx];
+
+       sband->channels = &data->channels[idx];
+
+       while (chan->band == band && idx < n_channels) {
+               chan = &data->channels[++idx];
+               n++;
+       }
+
+       sband->n_channels = n;
+
+       return n;
+}
+
+#define MAX_BIT_RATE_40_MHZ    150 /* Mbps */
+#define MAX_BIT_RATE_20_MHZ    72 /* Mbps */
+
+static void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
+                                struct iwl_eeprom_data *data,
+                                struct ieee80211_sta_ht_cap *ht_info,
+                                enum ieee80211_band band)
+{
+       int max_bit_rate = 0;
+       u8 rx_chains;
+       u8 tx_chains;
+
+       tx_chains = hweight8(data->valid_tx_ant);
+       if (cfg->rx_with_siso_diversity)
+               rx_chains = 1;
+       else
+               rx_chains = hweight8(data->valid_rx_ant);
+
+       if (!(data->sku & EEPROM_SKU_CAP_11N_ENABLE) || !cfg->ht_params) {
+               ht_info->ht_supported = false;
+               return;
+       }
+
+       ht_info->ht_supported = true;
+       ht_info->cap = 0;
+
+       if (iwlwifi_mod_params.amsdu_size_8K)
+               ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
+
+       ht_info->mcs.rx_mask[0] = 0xFF;
+       if (rx_chains >= 2)
+               ht_info->mcs.rx_mask[1] = 0xFF;
+       if (rx_chains >= 3)
+               ht_info->mcs.rx_mask[2] = 0xFF;
+
+       if (cfg->ht_params->ht_greenfield_support)
+               ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+       ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+       max_bit_rate = MAX_BIT_RATE_20_MHZ;
+
+       if (cfg->ht_params->ht40_bands & BIT(band)) {
+               ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+               ht_info->mcs.rx_mask[4] = 0x01;
+               max_bit_rate = MAX_BIT_RATE_40_MHZ;
+       }
+
+       /* Highest supported Rx data rate */
+       max_bit_rate *= rx_chains;
+       WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
+       ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);
+
+       /* Tx MCS capabilities */
+       ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+       if (tx_chains != rx_chains) {
+               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               ht_info->mcs.tx_params |= ((tx_chains - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+       }
+}
+
+static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
+                           struct iwl_eeprom_data *data,
+                           const u8 *eeprom, size_t eeprom_size)
+{
+       int n_channels = iwl_init_channel_map(dev, cfg, data,
+                                             eeprom, eeprom_size);
+       int n_used = 0;
+       struct ieee80211_supported_band *sband;
+
+       sband = &data->bands[IEEE80211_BAND_2GHZ];
+       sband->band = IEEE80211_BAND_2GHZ;
+       sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
+       sband->n_bitrates = N_RATES_24;
+       n_used += iwl_init_sband_channels(data, sband, n_channels,
+                                         IEEE80211_BAND_2GHZ);
+       iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ);
+
+       sband = &data->bands[IEEE80211_BAND_5GHZ];
+       sband->band = IEEE80211_BAND_5GHZ;
+       sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
+       sband->n_bitrates = N_RATES_52;
+       n_used += iwl_init_sband_channels(data, sband, n_channels,
+                                         IEEE80211_BAND_5GHZ);
+       iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+
+       if (n_channels != n_used)
+               IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n",
+                           n_used, n_channels);
+}
+
+/* EEPROM data functions */
+
+struct iwl_eeprom_data *
+iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
+                     const u8 *eeprom, size_t eeprom_size)
+{
+       struct iwl_eeprom_data *data;
+       const void *tmp;
+
+       if (WARN_ON(!cfg || !cfg->eeprom_params))
+               return NULL;
+
+       data = kzalloc(sizeof(*data) +
+                      sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
+                      GFP_KERNEL);
+       if (!data)
+               return NULL;
+
+       /* get MAC address(es) */
+       tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_MAC_ADDRESS);
+       if (!tmp)
+               goto err_free;
+       memcpy(data->hw_addr, tmp, ETH_ALEN);
+       data->n_hw_addrs = iwl_eeprom_query16(eeprom, eeprom_size,
+                                             EEPROM_NUM_MAC_ADDRESS);
+
+       if (iwl_eeprom_read_calib(eeprom, eeprom_size, data))
+               goto err_free;
+
+       tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_XTAL);
+       if (!tmp)
+               goto err_free;
+       memcpy(data->xtal_calib, tmp, sizeof(data->xtal_calib));
+
+       tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
+                                   EEPROM_RAW_TEMPERATURE);
+       if (!tmp)
+               goto err_free;
+       data->raw_temperature = *(__le16 *)tmp;
+
+       tmp = iwl_eeprom_query_addr(eeprom, eeprom_size,
+                                   EEPROM_KELVIN_TEMPERATURE);
+       if (!tmp)
+               goto err_free;
+       data->kelvin_temperature = *(__le16 *)tmp;
+       data->kelvin_voltage = *((__le16 *)tmp + 1);
+
+       data->radio_cfg = iwl_eeprom_query16(eeprom, eeprom_size,
+                                            EEPROM_RADIO_CONFIG);
+       data->sku = iwl_eeprom_query16(eeprom, eeprom_size,
+                                      EEPROM_SKU_CAP);
+       if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
+               data->sku &= ~EEPROM_SKU_CAP_11N_ENABLE;
+
+       data->eeprom_version = iwl_eeprom_query16(eeprom, eeprom_size,
+                                                 EEPROM_VERSION);
+
+       data->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(data->radio_cfg);
+       data->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(data->radio_cfg);
+
+       /* check overrides (some devices have wrong EEPROM) */
+       if (cfg->valid_tx_ant)
+               data->valid_tx_ant = cfg->valid_tx_ant;
+       if (cfg->valid_rx_ant)
+               data->valid_rx_ant = cfg->valid_rx_ant;
+
+       if (!data->valid_tx_ant || !data->valid_rx_ant) {
+               IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
+                           data->valid_tx_ant, data->valid_rx_ant);
+               goto err_free;
+       }
+
+       iwl_init_sbands(dev, cfg, data, eeprom, eeprom_size);
+
+       return data;
+ err_free:
+       kfree(data);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
+
+/* helper functions */
+int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
+                            struct iwl_trans *trans)
+{
+       if (data->eeprom_version >= trans->cfg->eeprom_ver ||
+           data->calib_version >= trans->cfg->eeprom_calib_ver) {
+               IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+                        data->eeprom_version, data->calib_version);
+               return 0;
+       }
+
+       IWL_ERR(trans,
+               "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+               data->eeprom_version, trans->cfg->eeprom_ver,
+               data->calib_version,  trans->cfg->eeprom_calib_ver);
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(iwl_eeprom_check_version);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
new file mode 100644 (file)
index 0000000..9c07c67
--- /dev/null
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_eeprom_parse_h__
+#define __iwl_eeprom_parse_h__
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include "iwl-trans.h"
+
+/* SKU Capabilities (actual values from EEPROM definition) */
+#define EEPROM_SKU_CAP_BAND_24GHZ      (1 << 4)
+#define EEPROM_SKU_CAP_BAND_52GHZ      (1 << 5)
+#define EEPROM_SKU_CAP_11N_ENABLE      (1 << 6)
+#define EEPROM_SKU_CAP_AMT_ENABLE      (1 << 7)
+#define EEPROM_SKU_CAP_IPAN_ENABLE     (1 << 8)
+
+/* radio config bits (actual values from EEPROM definition) */
+#define EEPROM_RF_CFG_TYPE_MSK(x)   (x & 0x3)         /* bits 0-1   */
+#define EEPROM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
+#define EEPROM_RF_CFG_DASH_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
+#define EEPROM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
+#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
+#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+struct iwl_eeprom_data {
+       int n_hw_addrs;
+       u8 hw_addr[ETH_ALEN];
+
+       u16 radio_config;
+
+       u8 calib_version;
+       __le16 calib_voltage;
+
+       __le16 raw_temperature;
+       __le16 kelvin_temperature;
+       __le16 kelvin_voltage;
+       __le16 xtal_calib[2];
+
+       u16 sku;
+       u16 radio_cfg;
+       u16 eeprom_version;
+       s8 max_tx_pwr_half_dbm;
+
+       u8 valid_tx_ant, valid_rx_ant;
+
+       struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+       struct ieee80211_channel channels[];
+};
+
+/**
+ * iwl_parse_eeprom_data - parse EEPROM data and return values
+ *
+ * @dev: device pointer we're parsing for, for debug only
+ * @cfg: device configuration for parsing and overrides
+ * @eeprom: the EEPROM data
+ * @eeprom_size: length of the EEPROM data
+ *
+ * This function parses all EEPROM values we need and then
+ * returns a (newly allocated) struct containing all the
+ * relevant values for driver use. The struct must be freed
+ * later with iwl_free_eeprom_data().
+ */
+struct iwl_eeprom_data *
+iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
+                     const u8 *eeprom, size_t eeprom_size);
+
+/**
+ * iwl_free_eeprom_data - free EEPROM data
+ * @data: the data to free
+ */
+static inline void iwl_free_eeprom_data(struct iwl_eeprom_data *data)
+{
+       kfree(data);
+}
+
+int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
+                            struct iwl_trans *trans);
+
+#endif /* __iwl_eeprom_parse_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
new file mode 100644 (file)
index 0000000..27c7da3
--- /dev/null
@@ -0,0 +1,463 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "iwl-debug.h"
+#include "iwl-eeprom-read.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-csr.h"
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT      5000 /* uSec */
+
+#define IWL_EEPROM_SEM_TIMEOUT         10   /* microseconds */
+#define IWL_EEPROM_SEM_RETRY_LIMIT     1000 /* number of attempts (not time) */
+
+
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+
+#define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
+
+static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
+{
+       u16 count;
+       int ret;
+
+       for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+               /* Request semaphore */
+               iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+                           CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+               /* See if we got it */
+               ret = iwl_poll_bit(trans, 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) {
+                       IWL_DEBUG_EEPROM(trans->dev,
+                                        "Acquired semaphore after %d tries.\n",
+                                        count+1);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
+{
+       iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
+                     CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+static int iwl_eeprom_verify_signature(struct iwl_trans *trans, bool nvm_is_otp)
+{
+       u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+
+       IWL_DEBUG_EEPROM(trans->dev, "EEPROM signature=0x%08x\n", gp);
+
+       switch (gp) {
+       case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
+               if (!nvm_is_otp) {
+                       IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
+                               gp);
+                       return -ENOENT;
+               }
+               return 0;
+       case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
+       case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
+               if (nvm_is_otp) {
+                       IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
+                       return -ENOENT;
+               }
+               return 0;
+       case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
+       default:
+               IWL_ERR(trans,
+                       "bad EEPROM/OTP signature, type=%s, EEPROM_GP=0x%08x\n",
+                       nvm_is_otp ? "OTP" : "EEPROM", gp);
+               return -ENOENT;
+       }
+}
+
+/******************************************************************************
+ *
+ * OTP related functions
+ *
+******************************************************************************/
+
+static void iwl_set_otp_access_absolute(struct iwl_trans *trans)
+{
+       iwl_read32(trans, CSR_OTP_GP_REG);
+
+       iwl_clear_bit(trans, CSR_OTP_GP_REG,
+                     CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
+static int iwl_nvm_is_otp(struct iwl_trans *trans)
+{
+       u32 otpgp;
+
+       /* OTP only valid for CP/PP and after */
+       switch (trans->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_NONE:
+               IWL_ERR(trans, "Unknown hardware type\n");
+               return -EIO;
+       case CSR_HW_REV_TYPE_5300:
+       case CSR_HW_REV_TYPE_5350:
+       case CSR_HW_REV_TYPE_5100:
+       case CSR_HW_REV_TYPE_5150:
+               return 0;
+       default:
+               otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
+               if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
+                       return 1;
+               return 0;
+       }
+}
+
+static int iwl_init_otp_access(struct iwl_trans *trans)
+{
+       int ret;
+
+       /* Enable 40MHz radio clock */
+       iwl_write32(trans, CSR_GP_CNTRL,
+                   iwl_read32(trans, CSR_GP_CNTRL) |
+                   CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+       /* wait for clock to be ready */
+       ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          25000);
+       if (ret < 0) {
+               IWL_ERR(trans, "Time out access OTP\n");
+       } else {
+               iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
+                                 APMG_PS_CTRL_VAL_RESET_REQ);
+               udelay(5);
+               iwl_clear_bits_prph(trans, 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 (trans->cfg->base_params->shadow_ram_support)
+                       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                                   CSR_RESET_LINK_PWR_MGMT_DISABLED);
+       }
+       return ret;
+}
+
+static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
+                            __le16 *eeprom_data)
+{
+       int ret = 0;
+       u32 r;
+       u32 otpgp;
+
+       iwl_write32(trans, CSR_EEPROM_REG,
+                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+       ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
+                                CSR_EEPROM_REG_READ_VALID_MSK,
+                                CSR_EEPROM_REG_READ_VALID_MSK,
+                                IWL_EEPROM_ACCESS_TIMEOUT);
+       if (ret < 0) {
+               IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
+               return ret;
+       }
+       r = iwl_read32(trans, CSR_EEPROM_REG);
+       /* check for ECC errors: */
+       otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
+       if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+               /* stop in this case */
+               /* set the uncorrectable OTP ECC bit for acknowledgement */
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
+                           CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+               IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
+               return -EINVAL;
+       }
+       if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+               /* continue in this case */
+               /* set the correctable OTP ECC bit for acknowledgement */
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
+                           CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+               IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
+       }
+       *eeprom_data = cpu_to_le16(r >> 16);
+       return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_trans *trans)
+{
+       u16 next_link_addr = 0;
+       __le16 link_value;
+       bool is_empty = false;
+
+       /* locate the beginning of OTP link list */
+       if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
+               if (!link_value) {
+                       IWL_ERR(trans, "OTP is empty\n");
+                       is_empty = true;
+               }
+       } else {
+               IWL_ERR(trans, "Unable to read first block of OTP list.\n");
+               is_empty = true;
+       }
+
+       return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ *   finding the OTP block that contains the EEPROM image.
+ *   the last valid block on the link list (the block _before_ the last block)
+ *   is the block we should read and used to configure the device.
+ *   If all the available OTP blocks are full, the last block will be the block
+ *   we should read and used to configure the device.
+ *   only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_trans *trans,
+                                       u16 *validblockaddr)
+{
+       u16 next_link_addr = 0, valid_addr;
+       __le16 link_value = 0;
+       int usedblocks = 0;
+
+       /* set addressing mode to absolute to traverse the link list */
+       iwl_set_otp_access_absolute(trans);
+
+       /* checking for empty OTP or error */
+       if (iwl_is_otp_empty(trans))
+               return -EINVAL;
+
+       /*
+        * start traverse link list
+        * until reach the max number of OTP blocks
+        * different devices have different number of OTP blocks
+        */
+       do {
+               /* save current valid block address
+                * check for more block on the link list
+                */
+               valid_addr = next_link_addr;
+               next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
+               IWL_DEBUG_EEPROM(trans->dev, "OTP blocks %d addr 0x%x\n",
+                                usedblocks, next_link_addr);
+               if (iwl_read_otp_word(trans, next_link_addr, &link_value))
+                       return -EINVAL;
+               if (!link_value) {
+                       /*
+                        * reach the end of link list, return success and
+                        * set address point to the starting address
+                        * of the image
+                        */
+                       *validblockaddr = valid_addr;
+                       /* skip first 2 bytes (link list pointer) */
+                       *validblockaddr += 2;
+                       return 0;
+               }
+               /* more in the link list, continue */
+               usedblocks++;
+       } while (usedblocks <= trans->cfg->base_params->max_ll_items);
+
+       /* OTP has no valid blocks */
+       IWL_DEBUG_EEPROM(trans->dev, "OTP has no valid blocks\n");
+       return -EINVAL;
+}
+
+/**
+ * iwl_read_eeprom - read EEPROM contents
+ *
+ * Load the EEPROM contents from adapter and return it
+ * and its size.
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
+{
+       __le16 *e;
+       u32 gp = iwl_read32(trans, CSR_EEPROM_GP);
+       int sz;
+       int ret;
+       u16 addr;
+       u16 validblockaddr = 0;
+       u16 cache_addr = 0;
+       int nvm_is_otp;
+
+       if (!eeprom || !eeprom_size)
+               return -EINVAL;
+
+       nvm_is_otp = iwl_nvm_is_otp(trans);
+       if (nvm_is_otp < 0)
+               return nvm_is_otp;
+
+       sz = trans->cfg->base_params->eeprom_size;
+       IWL_DEBUG_EEPROM(trans->dev, "NVM size = %d\n", sz);
+
+       e = kmalloc(sz, GFP_KERNEL);
+       if (!e)
+               return -ENOMEM;
+
+       ret = iwl_eeprom_verify_signature(trans, nvm_is_otp);
+       if (ret < 0) {
+               IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
+               goto err_free;
+       }
+
+       /* Make sure driver (instead of uCode) is allowed to read EEPROM */
+       ret = iwl_eeprom_acquire_semaphore(trans);
+       if (ret < 0) {
+               IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n");
+               goto err_free;
+       }
+
+       if (nvm_is_otp) {
+               ret = iwl_init_otp_access(trans);
+               if (ret) {
+                       IWL_ERR(trans, "Failed to initialize OTP access.\n");
+                       goto err_unlock;
+               }
+
+               iwl_write32(trans, CSR_EEPROM_GP,
+                           iwl_read32(trans, CSR_EEPROM_GP) &
+                           ~CSR_EEPROM_GP_IF_OWNER_MSK);
+
+               iwl_set_bit(trans, CSR_OTP_GP_REG,
+                           CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
+                           CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+               /* traversing the linked list if no shadow ram supported */
+               if (!trans->cfg->base_params->shadow_ram_support) {
+                       ret = iwl_find_otp_image(trans, &validblockaddr);
+                       if (ret)
+                               goto err_unlock;
+               }
+               for (addr = validblockaddr; addr < validblockaddr + sz;
+                    addr += sizeof(u16)) {
+                       __le16 eeprom_data;
+
+                       ret = iwl_read_otp_word(trans, addr, &eeprom_data);
+                       if (ret)
+                               goto err_unlock;
+                       e[cache_addr / 2] = eeprom_data;
+                       cache_addr += sizeof(u16);
+               }
+       } else {
+               /* eeprom is an array of 16bit values */
+               for (addr = 0; addr < sz; addr += sizeof(u16)) {
+                       u32 r;
+
+                       iwl_write32(trans, CSR_EEPROM_REG,
+                                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+
+                       ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
+                                          CSR_EEPROM_REG_READ_VALID_MSK,
+                                          CSR_EEPROM_REG_READ_VALID_MSK,
+                                          IWL_EEPROM_ACCESS_TIMEOUT);
+                       if (ret < 0) {
+                               IWL_ERR(trans,
+                                       "Time out reading EEPROM[%d]\n", addr);
+                               goto err_unlock;
+                       }
+                       r = iwl_read32(trans, CSR_EEPROM_REG);
+                       e[addr / 2] = cpu_to_le16(r >> 16);
+               }
+       }
+
+       IWL_DEBUG_EEPROM(trans->dev, "NVM Type: %s\n",
+                        nvm_is_otp ? "OTP" : "EEPROM");
+
+       iwl_eeprom_release_semaphore(trans);
+
+       *eeprom_size = sz;
+       *eeprom = (u8 *)e;
+       return 0;
+
+ err_unlock:
+       iwl_eeprom_release_semaphore(trans);
+ err_free:
+       kfree(e);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iwl_read_eeprom);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
new file mode 100644 (file)
index 0000000..1337c9d
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+#include "iwl-trans.h"
+
+int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size);
+
+#endif  /* __iwl_eeprom_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
deleted file mode 100644 (file)
index b8e2b22..0000000
+++ /dev/null
@@ -1,1148 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-agn.h"
-#include "iwl-eeprom.h"
-#include "iwl-io.h"
-#include "iwl-prph.h"
-
-/************************** EEPROM BANDS ****************************
- *
- * The iwl_eeprom_band definitions below provide the mapping from the
- * EEPROM contents to the specific channel number supported for each
- * band.
- *
- * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
- * definition below maps to physical channel 42 in the 5.2GHz spectrum.
- * The specific geography and calibration information for that channel
- * is contained in the eeprom map itself.
- *
- * During init, we copy the eeprom information and channel map
- * information into priv->channel_info_24/52 and priv->channel_map_24/52
- *
- * channel_map_24/52 provides the index in the channel_info array for a
- * given channel.  We have to have two separate maps as there is channel
- * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
- * band_2
- *
- * A value of 0xff stored in the channel_map indicates that the channel
- * is not supported by the hardware at all.
- *
- * A value of 0xfe in the channel_map indicates that the channel is not
- * valid for Tx with the current hardware.  This means that
- * while the system can tune and receive on a given channel, it may not
- * be able to associate or transmit any frames on that
- * channel.  There is no corresponding channel information for that
- * entry.
- *
- *********************************************************************/
-
-/* 2.4 GHz */
-const u8 iwl_eeprom_band_1[14] = {
-       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
-};
-
-/* 5.2 GHz bands */
-static const u8 iwl_eeprom_band_2[] = {        /* 4915-5080MHz */
-       183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
-};
-
-static const u8 iwl_eeprom_band_3[] = {        /* 5170-5320MHz */
-       34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
-};
-
-static const u8 iwl_eeprom_band_4[] = {        /* 5500-5700MHz */
-       100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
-};
-
-static const u8 iwl_eeprom_band_5[] = {        /* 5725-5825MHz */
-       145, 149, 153, 157, 161, 165
-};
-
-static const u8 iwl_eeprom_band_6[] = {       /* 2.4 ht40 channel */
-       1, 2, 3, 4, 5, 6, 7
-};
-
-static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
-       36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
-};
-
-/******************************************************************************
- *
- * generic NVM functions
- *
-******************************************************************************/
-
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-
-#define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
-#define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
-
-static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
-{
-       u16 count;
-       int ret;
-
-       for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
-               /* Request semaphore */
-               iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-                           CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-               /* See if we got it */
-               ret = iwl_poll_bit(trans, 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) {
-                       IWL_DEBUG_EEPROM(trans,
-                               "Acquired semaphore after %d tries.\n",
-                               count+1);
-                       return ret;
-               }
-       }
-
-       return ret;
-}
-
-static void iwl_eeprom_release_semaphore(struct iwl_trans *trans)
-{
-       iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG,
-               CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-}
-
-static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
-{
-       u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP) &
-                          CSR_EEPROM_GP_VALID_MSK;
-       int ret = 0;
-
-       IWL_DEBUG_EEPROM(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 ret;
-}
-
-u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset)
-{
-       if (!priv->eeprom)
-               return 0;
-       return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
-}
-
-int iwl_eeprom_check_version(struct iwl_priv *priv)
-{
-       u16 eeprom_ver;
-       u16 calib_ver;
-
-       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-       calib_ver = iwl_eeprom_calib_version(priv);
-
-       if (eeprom_ver < priv->cfg->eeprom_ver ||
-           calib_ver < priv->cfg->eeprom_calib_ver)
-               goto err;
-
-       IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
-                eeprom_ver, calib_ver);
-
-       return 0;
-err:
-       IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
-                 "CALIB=0x%x < 0x%x\n",
-                 eeprom_ver, priv->cfg->eeprom_ver,
-                 calib_ver,  priv->cfg->eeprom_calib_ver);
-       return -EINVAL;
-
-}
-
-int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
-{
-       u16 radio_cfg;
-
-       priv->hw_params.sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
-       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE &&
-           !priv->cfg->ht_params) {
-               IWL_ERR(priv, "Invalid 11n configuration\n");
-               return -EINVAL;
-       }
-
-       if (!priv->hw_params.sku) {
-               IWL_ERR(priv, "Invalid device sku\n");
-               return -EINVAL;
-       }
-
-       IWL_INFO(priv, "Device SKU: 0x%X\n", priv->hw_params.sku);
-
-       radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
-
-       priv->hw_params.valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
-       priv->hw_params.valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
-
-       /* check overrides (some devices have wrong EEPROM) */
-       if (priv->cfg->valid_tx_ant)
-               priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
-       if (priv->cfg->valid_rx_ant)
-               priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
-
-       if (!priv->hw_params.valid_tx_ant || !priv->hw_params.valid_rx_ant) {
-               IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n",
-                       priv->hw_params.valid_tx_ant,
-                       priv->hw_params.valid_rx_ant);
-               return -EINVAL;
-       }
-
-       IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
-                priv->hw_params.valid_tx_ant, priv->hw_params.valid_rx_ant);
-
-       return 0;
-}
-
-u16 iwl_eeprom_calib_version(struct iwl_priv *priv)
-{
-       struct iwl_eeprom_calib_hdr *hdr;
-
-       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-                                                       EEPROM_CALIB_ALL);
-       return hdr->version;
-}
-
-static u32 eeprom_indirect_address(struct iwl_priv *priv, u32 address)
-{
-       u16 offset = 0;
-
-       if ((address & INDIRECT_ADDRESS) == 0)
-               return address;
-
-       switch (address & INDIRECT_TYPE_MSK) {
-       case INDIRECT_HOST:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST);
-               break;
-       case INDIRECT_GENERAL:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL);
-               break;
-       case INDIRECT_REGULATORY:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY);
-               break;
-       case INDIRECT_TXP_LIMIT:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT);
-               break;
-       case INDIRECT_TXP_LIMIT_SIZE:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE);
-               break;
-       case INDIRECT_CALIBRATION:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION);
-               break;
-       case INDIRECT_PROCESS_ADJST:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST);
-               break;
-       case INDIRECT_OTHERS:
-               offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS);
-               break;
-       default:
-               IWL_ERR(priv, "illegal indirect type: 0x%X\n",
-               address & INDIRECT_TYPE_MSK);
-               break;
-       }
-
-       /* translate the offset from words to byte */
-       return (address & ADDRESS_MSK) + (offset << 1);
-}
-
-const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset)
-{
-       u32 address = eeprom_indirect_address(priv, offset);
-       BUG_ON(address >= priv->cfg->base_params->eeprom_size);
-       return &priv->eeprom[address];
-}
-
-void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac)
-{
-       const u8 *addr = iwl_eeprom_query_addr(priv,
-                                       EEPROM_MAC_ADDRESS);
-       memcpy(mac, addr, ETH_ALEN);
-}
-
-/******************************************************************************
- *
- * OTP related functions
- *
-******************************************************************************/
-
-static void iwl_set_otp_access(struct iwl_trans *trans,
-                              enum iwl_access_mode mode)
-{
-       iwl_read32(trans, CSR_OTP_GP_REG);
-
-       if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-               iwl_clear_bit(trans, CSR_OTP_GP_REG,
-                             CSR_OTP_GP_REG_OTP_ACCESS_MODE);
-       else
-               iwl_set_bit(trans, CSR_OTP_GP_REG,
-                           CSR_OTP_GP_REG_OTP_ACCESS_MODE);
-}
-
-static int iwl_get_nvm_type(struct iwl_trans *trans, u32 hw_rev)
-{
-       u32 otpgp;
-       int nvm_type;
-
-       /* OTP only valid for CP/PP and after */
-       switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_NONE:
-               IWL_ERR(trans, "Unknown hardware type\n");
-               return -ENOENT;
-       case CSR_HW_REV_TYPE_5300:
-       case CSR_HW_REV_TYPE_5350:
-       case CSR_HW_REV_TYPE_5100:
-       case CSR_HW_REV_TYPE_5150:
-               nvm_type = NVM_DEVICE_TYPE_EEPROM;
-               break;
-       default:
-               otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
-               if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
-                       nvm_type = NVM_DEVICE_TYPE_OTP;
-               else
-                       nvm_type = NVM_DEVICE_TYPE_EEPROM;
-               break;
-       }
-       return  nvm_type;
-}
-
-static int iwl_init_otp_access(struct iwl_trans *trans)
-{
-       int ret;
-
-       /* Enable 40MHz radio clock */
-       iwl_write32(trans, CSR_GP_CNTRL,
-                   iwl_read32(trans, CSR_GP_CNTRL) |
-                   CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
-       /* wait for clock to be ready */
-       ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
-                                CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-                                CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-                                25000);
-       if (ret < 0)
-               IWL_ERR(trans, "Time out access OTP\n");
-       else {
-               iwl_set_bits_prph(trans, APMG_PS_CTRL_REG,
-                                 APMG_PS_CTRL_VAL_RESET_REQ);
-               udelay(5);
-               iwl_clear_bits_prph(trans, 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 (trans->cfg->base_params->shadow_ram_support)
-                       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
-                               CSR_RESET_LINK_PWR_MGMT_DISABLED);
-       }
-       return ret;
-}
-
-static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
-                            __le16 *eeprom_data)
-{
-       int ret = 0;
-       u32 r;
-       u32 otpgp;
-
-       iwl_write32(trans, CSR_EEPROM_REG,
-                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-       ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
-                                CSR_EEPROM_REG_READ_VALID_MSK,
-                                CSR_EEPROM_REG_READ_VALID_MSK,
-                                IWL_EEPROM_ACCESS_TIMEOUT);
-       if (ret < 0) {
-               IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
-               return ret;
-       }
-       r = iwl_read32(trans, CSR_EEPROM_REG);
-       /* check for ECC errors: */
-       otpgp = iwl_read32(trans, CSR_OTP_GP_REG);
-       if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
-               /* stop in this case */
-               /* set the uncorrectable OTP ECC bit for acknowledgement */
-               iwl_set_bit(trans, CSR_OTP_GP_REG,
-                       CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n");
-               return -EINVAL;
-       }
-       if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
-               /* continue in this case */
-               /* set the correctable OTP ECC bit for acknowledgement */
-               iwl_set_bit(trans, CSR_OTP_GP_REG,
-                               CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-               IWL_ERR(trans, "Correctable OTP ECC error, continue read\n");
-       }
-       *eeprom_data = cpu_to_le16(r >> 16);
-       return 0;
-}
-
-/*
- * iwl_is_otp_empty: check for empty OTP
- */
-static bool iwl_is_otp_empty(struct iwl_trans *trans)
-{
-       u16 next_link_addr = 0;
-       __le16 link_value;
-       bool is_empty = false;
-
-       /* locate the beginning of OTP link list */
-       if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) {
-               if (!link_value) {
-                       IWL_ERR(trans, "OTP is empty\n");
-                       is_empty = true;
-               }
-       } else {
-               IWL_ERR(trans, "Unable to read first block of OTP list.\n");
-               is_empty = true;
-       }
-
-       return is_empty;
-}
-
-
-/*
- * iwl_find_otp_image: find EEPROM image in OTP
- *   finding the OTP block that contains the EEPROM image.
- *   the last valid block on the link list (the block _before_ the last block)
- *   is the block we should read and used to configure the device.
- *   If all the available OTP blocks are full, the last block will be the block
- *   we should read and used to configure the device.
- *   only perform this operation if shadow RAM is disabled
- */
-static int iwl_find_otp_image(struct iwl_trans *trans,
-                                       u16 *validblockaddr)
-{
-       u16 next_link_addr = 0, valid_addr;
-       __le16 link_value = 0;
-       int usedblocks = 0;
-
-       /* set addressing mode to absolute to traverse the link list */
-       iwl_set_otp_access(trans, IWL_OTP_ACCESS_ABSOLUTE);
-
-       /* checking for empty OTP or error */
-       if (iwl_is_otp_empty(trans))
-               return -EINVAL;
-
-       /*
-        * start traverse link list
-        * until reach the max number of OTP blocks
-        * different devices have different number of OTP blocks
-        */
-       do {
-               /* save current valid block address
-                * check for more block on the link list
-                */
-               valid_addr = next_link_addr;
-               next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-               IWL_DEBUG_EEPROM(trans, "OTP blocks %d addr 0x%x\n",
-                              usedblocks, next_link_addr);
-               if (iwl_read_otp_word(trans, next_link_addr, &link_value))
-                       return -EINVAL;
-               if (!link_value) {
-                       /*
-                        * reach the end of link list, return success and
-                        * set address point to the starting address
-                        * of the image
-                        */
-                       *validblockaddr = valid_addr;
-                       /* skip first 2 bytes (link list pointer) */
-                       *validblockaddr += 2;
-                       return 0;
-               }
-               /* more in the link list, continue */
-               usedblocks++;
-       } while (usedblocks <= trans->cfg->base_params->max_ll_items);
-
-       /* OTP has no valid blocks */
-       IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n");
-       return -EINVAL;
-}
-
-/******************************************************************************
- *
- * Tx Power related functions
- *
-******************************************************************************/
-/**
- * iwl_get_max_txpower_avg - get the highest tx power from all chains.
- *     find the highest tx power from all chains for the channel
- */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
-               struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
-               int element, s8 *max_txpower_in_half_dbm)
-{
-       s8 max_txpower_avg = 0; /* (dBm) */
-
-       /* Take the highest tx power from any valid chains */
-       if ((priv->hw_params.valid_tx_ant & ANT_A) &&
-           (enhanced_txpower[element].chain_a_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_a_max;
-       if ((priv->hw_params.valid_tx_ant & ANT_B) &&
-           (enhanced_txpower[element].chain_b_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_b_max;
-       if ((priv->hw_params.valid_tx_ant & ANT_C) &&
-           (enhanced_txpower[element].chain_c_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_c_max;
-       if (((priv->hw_params.valid_tx_ant == ANT_AB) |
-           (priv->hw_params.valid_tx_ant == ANT_BC) |
-           (priv->hw_params.valid_tx_ant == ANT_AC)) &&
-           (enhanced_txpower[element].mimo2_max > max_txpower_avg))
-               max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-       if ((priv->hw_params.valid_tx_ant == ANT_ABC) &&
-           (enhanced_txpower[element].mimo3_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].mimo3_max;
-
-       /*
-        * max. tx power in EEPROM is in 1/2 dBm format
-        * convert from 1/2 dBm to dBm (round-up convert)
-        * but we also do not want to loss 1/2 dBm resolution which
-        * will impact performance
-        */
-       *max_txpower_in_half_dbm = max_txpower_avg;
-       return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
-}
-
-static void
-iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
-                                   struct iwl_eeprom_enhanced_txpwr *txp,
-                                   s8 max_txpower_avg)
-{
-       int ch_idx;
-       bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
-       enum ieee80211_band band;
-
-       band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
-               IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
-
-       for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
-               struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
-
-               /* update matching channel or from common data only */
-               if (txp->channel != 0 && ch_info->channel != txp->channel)
-                       continue;
-
-               /* update matching band only */
-               if (band != ch_info->band)
-                       continue;
-
-               if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
-                       ch_info->max_power_avg = max_txpower_avg;
-                       ch_info->curr_txpow = max_txpower_avg;
-                       ch_info->scan_power = max_txpower_avg;
-               }
-
-               if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
-                       ch_info->ht40_max_power_avg = max_txpower_avg;
-       }
-}
-
-#define EEPROM_TXP_OFFS        (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
-#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
-#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
-
-#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
-                           ? # x " " : "")
-
-static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
-{
-       struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
-       int idx, entries;
-       __le16 *txp_len;
-       s8 max_txp_avg, max_txp_avg_halfdbm;
-
-       BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
-
-       /* the length is in 16-bit words, but we want entries */
-       txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
-       entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
-
-       txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
-
-       for (idx = 0; idx < entries; idx++) {
-               txp = &txp_array[idx];
-               /* skip invalid entries */
-               if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
-                       continue;
-
-               IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
-                                (txp->channel && (txp->flags &
-                                       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
-                                       "Common " : (txp->channel) ?
-                                       "Channel" : "Common",
-                                (txp->channel),
-                                TXP_CHECK_AND_PRINT(VALID),
-                                TXP_CHECK_AND_PRINT(BAND_52G),
-                                TXP_CHECK_AND_PRINT(OFDM),
-                                TXP_CHECK_AND_PRINT(40MHZ),
-                                TXP_CHECK_AND_PRINT(HT_AP),
-                                TXP_CHECK_AND_PRINT(RES1),
-                                TXP_CHECK_AND_PRINT(RES2),
-                                TXP_CHECK_AND_PRINT(COMMON_TYPE),
-                                txp->flags);
-               IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
-                                "chain_B: 0X%02x chain_C: 0X%02x\n",
-                                txp->chain_a_max, txp->chain_b_max,
-                                txp->chain_c_max);
-               IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
-                                "MIMO3: 0x%02x High 20_on_40: 0x%02x "
-                                "Low 20_on_40: 0x%02x\n",
-                                txp->mimo2_max, txp->mimo3_max,
-                                ((txp->delta_20_in_40 & 0xf0) >> 4),
-                                (txp->delta_20_in_40 & 0x0f));
-
-               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
-                                                     &max_txp_avg_halfdbm);
-
-               /*
-                * Update the user limit values values to the highest
-                * power supported by any channel
-                */
-               if (max_txp_avg > priv->tx_power_user_lmt)
-                       priv->tx_power_user_lmt = max_txp_avg;
-               if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
-                       priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
-
-               iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
-       }
-}
-
-/**
- * iwl_eeprom_init - read EEPROM contents
- *
- * Load the EEPROM contents from adapter into priv->eeprom
- *
- * NOTE:  This routine uses the non-debug IO access functions.
- */
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
-{
-       __le16 *e;
-       u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP);
-       int sz;
-       int ret;
-       u16 addr;
-       u16 validblockaddr = 0;
-       u16 cache_addr = 0;
-
-       priv->nvm_device_type = iwl_get_nvm_type(priv->trans, hw_rev);
-       if (priv->nvm_device_type == -ENOENT)
-               return -ENOENT;
-       /* allocate eeprom */
-       sz = priv->cfg->base_params->eeprom_size;
-       IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz);
-       priv->eeprom = kzalloc(sz, GFP_KERNEL);
-       if (!priv->eeprom) {
-               ret = -ENOMEM;
-               goto alloc_err;
-       }
-       e = (__le16 *)priv->eeprom;
-
-       ret = iwl_eeprom_verify_signature(priv);
-       if (ret < 0) {
-               IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
-               ret = -ENOENT;
-               goto err;
-       }
-
-       /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = iwl_eeprom_acquire_semaphore(priv->trans);
-       if (ret < 0) {
-               IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
-               ret = -ENOENT;
-               goto err;
-       }
-
-       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
-
-               ret = iwl_init_otp_access(priv->trans);
-               if (ret) {
-                       IWL_ERR(priv, "Failed to initialize OTP access.\n");
-                       ret = -ENOENT;
-                       goto done;
-               }
-               iwl_write32(priv->trans, CSR_EEPROM_GP,
-                           iwl_read32(priv->trans, CSR_EEPROM_GP) &
-                           ~CSR_EEPROM_GP_IF_OWNER_MSK);
-
-               iwl_set_bit(priv->trans, CSR_OTP_GP_REG,
-                            CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
-                            CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               /* traversing the linked list if no shadow ram supported */
-               if (!priv->cfg->base_params->shadow_ram_support) {
-                       if (iwl_find_otp_image(priv->trans, &validblockaddr)) {
-                               ret = -ENOENT;
-                               goto done;
-                       }
-               }
-               for (addr = validblockaddr; addr < validblockaddr + sz;
-                    addr += sizeof(u16)) {
-                       __le16 eeprom_data;
-
-                       ret = iwl_read_otp_word(priv->trans, addr,
-                                               &eeprom_data);
-                       if (ret)
-                               goto done;
-                       e[cache_addr / 2] = eeprom_data;
-                       cache_addr += sizeof(u16);
-               }
-       } else {
-               /* eeprom is an array of 16bit values */
-               for (addr = 0; addr < sz; addr += sizeof(u16)) {
-                       u32 r;
-
-                       iwl_write32(priv->trans, CSR_EEPROM_REG,
-                                   CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
-                       ret = iwl_poll_bit(priv->trans, CSR_EEPROM_REG,
-                                                 CSR_EEPROM_REG_READ_VALID_MSK,
-                                                 CSR_EEPROM_REG_READ_VALID_MSK,
-                                                 IWL_EEPROM_ACCESS_TIMEOUT);
-                       if (ret < 0) {
-                               IWL_ERR(priv,
-                                       "Time out reading EEPROM[%d]\n", addr);
-                               goto done;
-                       }
-                       r = iwl_read32(priv->trans, CSR_EEPROM_REG);
-                       e[addr / 2] = cpu_to_le16(r >> 16);
-               }
-       }
-
-       IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-                      ? "OTP" : "EEPROM",
-                      iwl_eeprom_query16(priv, EEPROM_VERSION));
-
-       ret = 0;
-done:
-       iwl_eeprom_release_semaphore(priv->trans);
-
-err:
-       if (ret)
-               iwl_eeprom_free(priv);
-alloc_err:
-       return ret;
-}
-
-void iwl_eeprom_free(struct iwl_priv *priv)
-{
-       kfree(priv->eeprom);
-       priv->eeprom = NULL;
-}
-
-static void iwl_init_band_reference(struct iwl_priv *priv,
-                       int eep_band, int *eeprom_ch_count,
-                       const struct iwl_eeprom_channel **eeprom_ch_info,
-                       const u8 **eeprom_ch_index)
-{
-       u32 offset = priv->lib->
-                       eeprom_ops.regulatory_bands[eep_band - 1];
-       switch (eep_band) {
-       case 1:         /* 2.4GHz band */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_1;
-               break;
-       case 2:         /* 4.9GHz band */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_2;
-               break;
-       case 3:         /* 5.2GHz band */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_3;
-               break;
-       case 4:         /* 5.5GHz band */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_4;
-               break;
-       case 5:         /* 5.7GHz band */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_5;
-               break;
-       case 6:         /* 2.4GHz ht40 channels */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_6;
-               break;
-       case 7:         /* 5 GHz ht40 channels */
-               *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
-               *eeprom_ch_info = (struct iwl_eeprom_channel *)
-                               iwl_eeprom_query_addr(priv, offset);
-               *eeprom_ch_index = iwl_eeprom_band_7;
-               break;
-       default:
-               BUG();
-               return;
-       }
-}
-
-#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
-                           ? # x " " : "")
-/**
- * iwl_mod_ht40_chan_info - Copy ht40 channel info into driver's priv.
- *
- * Does not set up a command, or touch hardware.
- */
-static int iwl_mod_ht40_chan_info(struct iwl_priv *priv,
-                             enum ieee80211_band band, u16 channel,
-                             const struct iwl_eeprom_channel *eeprom_ch,
-                             u8 clear_ht40_extension_channel)
-{
-       struct iwl_channel_info *ch_info;
-
-       ch_info = (struct iwl_channel_info *)
-                       iwl_get_channel_info(priv, band, channel);
-
-       if (!is_channel_valid(ch_info))
-               return -1;
-
-       IWL_DEBUG_EEPROM(priv, "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm):"
-                       " Ad-Hoc %ssupported\n",
-                       ch_info->channel,
-                       is_channel_a_band(ch_info) ?
-                       "5.2" : "2.4",
-                       CHECK_AND_PRINT(IBSS),
-                       CHECK_AND_PRINT(ACTIVE),
-                       CHECK_AND_PRINT(RADAR),
-                       CHECK_AND_PRINT(WIDE),
-                       CHECK_AND_PRINT(DFS),
-                       eeprom_ch->flags,
-                       eeprom_ch->max_power_avg,
-                       ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
-                        && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
-                       "" : "not ");
-
-       ch_info->ht40_eeprom = *eeprom_ch;
-       ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg;
-       ch_info->ht40_flags = eeprom_ch->flags;
-       if (eeprom_ch->flags & EEPROM_CHANNEL_VALID)
-               ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel;
-
-       return 0;
-}
-
-#define CHECK_AND_PRINT_I(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
-                           ? # x " " : "")
-
-/**
- * iwl_init_channel_map - Set up driver's info for all possible channels
- */
-int iwl_init_channel_map(struct iwl_priv *priv)
-{
-       int eeprom_ch_count = 0;
-       const u8 *eeprom_ch_index = NULL;
-       const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
-       int band, ch;
-       struct iwl_channel_info *ch_info;
-
-       if (priv->channel_count) {
-               IWL_DEBUG_EEPROM(priv, "Channel map already initialized.\n");
-               return 0;
-       }
-
-       IWL_DEBUG_EEPROM(priv, "Initializing regulatory info from EEPROM\n");
-
-       priv->channel_count =
-           ARRAY_SIZE(iwl_eeprom_band_1) +
-           ARRAY_SIZE(iwl_eeprom_band_2) +
-           ARRAY_SIZE(iwl_eeprom_band_3) +
-           ARRAY_SIZE(iwl_eeprom_band_4) +
-           ARRAY_SIZE(iwl_eeprom_band_5);
-
-       IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
-                       priv->channel_count);
-
-       priv->channel_info = kcalloc(priv->channel_count,
-                                    sizeof(struct iwl_channel_info),
-                                    GFP_KERNEL);
-       if (!priv->channel_info) {
-               IWL_ERR(priv, "Could not allocate channel_info\n");
-               priv->channel_count = 0;
-               return -ENOMEM;
-       }
-
-       ch_info = priv->channel_info;
-
-       /* Loop through the 5 EEPROM bands adding them in order to the
-        * channel map we maintain (that contains additional information than
-        * what just in the EEPROM) */
-       for (band = 1; band <= 5; band++) {
-
-               iwl_init_band_reference(priv, band, &eeprom_ch_count,
-                                       &eeprom_ch_info, &eeprom_ch_index);
-
-               /* Loop through each band adding each of the channels */
-               for (ch = 0; ch < eeprom_ch_count; ch++) {
-                       ch_info->channel = eeprom_ch_index[ch];
-                       ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ :
-                           IEEE80211_BAND_5GHZ;
-
-                       /* permanently store EEPROM's channel regulatory flags
-                        *   and max power in channel info database. */
-                       ch_info->eeprom = eeprom_ch_info[ch];
-
-                       /* Copy the run-time flags so they are there even on
-                        * invalid channels */
-                       ch_info->flags = eeprom_ch_info[ch].flags;
-                       /* First write that ht40 is not enabled, and then enable
-                        * one by one */
-                       ch_info->ht40_extension_channel =
-                                       IEEE80211_CHAN_NO_HT40;
-
-                       if (!(is_channel_valid(ch_info))) {
-                               IWL_DEBUG_EEPROM(priv,
-                                              "Ch. %d Flags %x [%sGHz] - "
-                                              "No traffic\n",
-                                              ch_info->channel,
-                                              ch_info->flags,
-                                              is_channel_a_band(ch_info) ?
-                                              "5.2" : "2.4");
-                               ch_info++;
-                               continue;
-                       }
-
-                       /* Initialize regulatory-based run-time data */
-                       ch_info->max_power_avg = ch_info->curr_txpow =
-                           eeprom_ch_info[ch].max_power_avg;
-                       ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
-                       ch_info->min_power = 0;
-
-                       IWL_DEBUG_EEPROM(priv, "Ch. %d [%sGHz] "
-                                      "%s%s%s%s%s%s(0x%02x %ddBm):"
-                                      " Ad-Hoc %ssupported\n",
-                                      ch_info->channel,
-                                      is_channel_a_band(ch_info) ?
-                                      "5.2" : "2.4",
-                                      CHECK_AND_PRINT_I(VALID),
-                                      CHECK_AND_PRINT_I(IBSS),
-                                      CHECK_AND_PRINT_I(ACTIVE),
-                                      CHECK_AND_PRINT_I(RADAR),
-                                      CHECK_AND_PRINT_I(WIDE),
-                                      CHECK_AND_PRINT_I(DFS),
-                                      eeprom_ch_info[ch].flags,
-                                      eeprom_ch_info[ch].max_power_avg,
-                                      ((eeprom_ch_info[ch].
-                                        flags & EEPROM_CHANNEL_IBSS)
-                                       && !(eeprom_ch_info[ch].
-                                            flags & EEPROM_CHANNEL_RADAR))
-                                      ? "" : "not ");
-
-                       ch_info++;
-               }
-       }
-
-       /* Check if we do have HT40 channels */
-       if (priv->lib->eeprom_ops.regulatory_bands[5] ==
-           EEPROM_REGULATORY_BAND_NO_HT40 &&
-           priv->lib->eeprom_ops.regulatory_bands[6] ==
-           EEPROM_REGULATORY_BAND_NO_HT40)
-               return 0;
-
-       /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */
-       for (band = 6; band <= 7; band++) {
-               enum ieee80211_band ieeeband;
-
-               iwl_init_band_reference(priv, band, &eeprom_ch_count,
-                                       &eeprom_ch_info, &eeprom_ch_index);
-
-               /* EEPROM band 6 is 2.4, band 7 is 5 GHz */
-               ieeeband =
-                       (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-
-               /* Loop through each band adding each of the channels */
-               for (ch = 0; ch < eeprom_ch_count; ch++) {
-                       /* Set up driver's info for lower half */
-                       iwl_mod_ht40_chan_info(priv, ieeeband,
-                                               eeprom_ch_index[ch],
-                                               &eeprom_ch_info[ch],
-                                               IEEE80211_CHAN_NO_HT40PLUS);
-
-                       /* Set up driver's info for upper half */
-                       iwl_mod_ht40_chan_info(priv, ieeeband,
-                                               eeprom_ch_index[ch] + 4,
-                                               &eeprom_ch_info[ch],
-                                               IEEE80211_CHAN_NO_HT40MINUS);
-               }
-       }
-
-       /* for newer device (6000 series and up)
-        * EEPROM contain enhanced tx power information
-        * driver need to process addition information
-        * to determine the max channel tx power limits
-        */
-       if (priv->lib->eeprom_ops.enhanced_txpower)
-               iwl_eeprom_enhanced_txpower(priv);
-
-       return 0;
-}
-
-/*
- * iwl_free_channel_map - undo allocations in iwl_init_channel_map
- */
-void iwl_free_channel_map(struct iwl_priv *priv)
-{
-       kfree(priv->channel_info);
-       priv->channel_count = 0;
-}
-
-/**
- * iwl_get_channel_info - Find driver's private channel info
- *
- * Based on band and channel number.
- */
-const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
-                                       enum ieee80211_band band, u16 channel)
-{
-       int i;
-
-       switch (band) {
-       case IEEE80211_BAND_5GHZ:
-               for (i = 14; i < priv->channel_count; i++) {
-                       if (priv->channel_info[i].channel == channel)
-                               return &priv->channel_info[i];
-               }
-               break;
-       case IEEE80211_BAND_2GHZ:
-               if (channel >= 1 && channel <= 14)
-                       return &priv->channel_info[channel - 1];
-               break;
-       default:
-               BUG();
-       }
-
-       return NULL;
-}
-
-void iwl_rf_config(struct iwl_priv *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->trans, 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));
-               IWL_INFO(priv, "Radio type=0x%x-0x%x-0x%x\n",
-                        EEPROM_RF_CFG_TYPE_MSK(radio_cfg),
-                        EEPROM_RF_CFG_STEP_MSK(radio_cfg),
-                        EEPROM_RF_CFG_DASH_MSK(radio_cfg));
-       } else
-               WARN_ON(1);
-
-       /* set CSR_HW_CONFIG_REG for uCode use */
-       iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG,
-                   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
-                   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
deleted file mode 100644 (file)
index 64bfd94..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef __iwl_eeprom_h__
-#define __iwl_eeprom_h__
-
-#include <net/mac80211.h>
-
-struct iwl_priv;
-
-/*
- * EEPROM access time values:
- *
- * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG.
- * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
- * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
- * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
- */
-#define IWL_EEPROM_ACCESS_TIMEOUT      5000 /* uSec */
-
-#define IWL_EEPROM_SEM_TIMEOUT                 10   /* microseconds */
-#define IWL_EEPROM_SEM_RETRY_LIMIT     1000 /* number of attempts (not time) */
-
-
-/*
- * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
- *
- * IBSS and/or AP operation is allowed *only* on those channels with
- * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
- * RADAR detection is not supported by the 4965 driver, but is a
- * requirement for establishing a new network for legal operation on channels
- * requiring RADAR detection or restricting ACTIVE scanning.
- *
- * NOTE:  "WIDE" flag does not indicate anything about "HT40" 40 MHz channels.
- *        It only indicates that 20 MHz channel use is supported; HT40 channel
- *        usage is indicated by a separate set of regulatory flags for each
- *        HT40 channel pair.
- *
- * NOTE:  Using a channel inappropriately will result in a uCode error!
- */
-#define IWL_NUM_TX_CALIB_GROUPS 5
-enum {
-       EEPROM_CHANNEL_VALID = (1 << 0),        /* usable for this SKU/geo */
-       EEPROM_CHANNEL_IBSS = (1 << 1),         /* usable as an IBSS channel */
-       /* Bit 2 Reserved */
-       EEPROM_CHANNEL_ACTIVE = (1 << 3),       /* active scanning allowed */
-       EEPROM_CHANNEL_RADAR = (1 << 4),        /* radar detection required */
-       EEPROM_CHANNEL_WIDE = (1 << 5),         /* 20 MHz channel okay */
-       /* Bit 6 Reserved (was Narrow Channel) */
-       EEPROM_CHANNEL_DFS = (1 << 7),  /* dynamic freq selection candidate */
-};
-
-/* SKU Capabilities */
-#define EEPROM_SKU_CAP_BAND_24GHZ                      (1 << 4)
-#define EEPROM_SKU_CAP_BAND_52GHZ                      (1 << 5)
-#define EEPROM_SKU_CAP_11N_ENABLE                      (1 << 6)
-#define EEPROM_SKU_CAP_AMT_ENABLE                      (1 << 7)
-#define EEPROM_SKU_CAP_IPAN_ENABLE                     (1 << 8)
-
-/* *regulatory* channel data format in eeprom, one for each channel.
- * There are separate entries for HT40 (40 MHz) vs. normal (20 MHz) channels. */
-struct iwl_eeprom_channel {
-       u8 flags;               /* EEPROM_CHANNEL_* flags copied from EEPROM */
-       s8 max_power_avg;       /* max power (dBm) on this chnl, limit 31 */
-} __packed;
-
-enum iwl_eeprom_enhanced_txpwr_flags {
-       IWL_EEPROM_ENH_TXP_FL_VALID             = BIT(0),
-       IWL_EEPROM_ENH_TXP_FL_BAND_52G          = BIT(1),
-       IWL_EEPROM_ENH_TXP_FL_OFDM              = BIT(2),
-       IWL_EEPROM_ENH_TXP_FL_40MHZ             = BIT(3),
-       IWL_EEPROM_ENH_TXP_FL_HT_AP             = BIT(4),
-       IWL_EEPROM_ENH_TXP_FL_RES1              = BIT(5),
-       IWL_EEPROM_ENH_TXP_FL_RES2              = BIT(6),
-       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE       = BIT(7),
-};
-
-/**
- * iwl_eeprom_enhanced_txpwr structure
- *    This structure presents the enhanced regulatory tx power limit layout
- *    in eeprom image
- *    Enhanced regulatory tx power portion of eeprom image can be broken down
- *    into individual structures; each one is 8 bytes in size and contain the
- *    following information
- * @flags: entry flags
- * @channel: channel number
- * @chain_a_max_pwr: chain a max power in 1/2 dBm
- * @chain_b_max_pwr: chain b max power in 1/2 dBm
- * @chain_c_max_pwr: chain c max power in 1/2 dBm
- * @delta_20_in_40: 20-in-40 deltas (hi/lo)
- * @mimo2_max_pwr: mimo2 max power in 1/2 dBm
- * @mimo3_max_pwr: mimo3 max power in 1/2 dBm
- *
- */
-struct iwl_eeprom_enhanced_txpwr {
-       u8 flags;
-       u8 channel;
-       s8 chain_a_max;
-       s8 chain_b_max;
-       s8 chain_c_max;
-       u8 delta_20_in_40;
-       s8 mimo2_max;
-       s8 mimo3_max;
-} __packed;
-
-/* calibration */
-struct iwl_eeprom_calib_hdr {
-       u8 version;
-       u8 pa_type;
-       __le16 voltage;
-} __packed;
-
-#define EEPROM_CALIB_ALL       (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
-#define EEPROM_XTAL            ((2*0x128) | EEPROM_CALIB_ALL)
-
-/* temperature */
-#define EEPROM_KELVIN_TEMPERATURE      ((2*0x12A) | EEPROM_CALIB_ALL)
-#define EEPROM_RAW_TEMPERATURE         ((2*0x12B) | EEPROM_CALIB_ALL)
-
-
-/* agn links */
-#define EEPROM_LINK_HOST             (2*0x64)
-#define EEPROM_LINK_GENERAL          (2*0x65)
-#define EEPROM_LINK_REGULATORY       (2*0x66)
-#define EEPROM_LINK_CALIBRATION      (2*0x67)
-#define EEPROM_LINK_PROCESS_ADJST    (2*0x68)
-#define EEPROM_LINK_OTHERS           (2*0x69)
-#define EEPROM_LINK_TXP_LIMIT        (2*0x6a)
-#define EEPROM_LINK_TXP_LIMIT_SIZE   (2*0x6b)
-
-/* agn regulatory - indirect access */
-#define EEPROM_REG_BAND_1_CHANNELS       ((0x08)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 28 bytes */
-#define EEPROM_REG_BAND_2_CHANNELS       ((0x26)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 26 bytes */
-#define EEPROM_REG_BAND_3_CHANNELS       ((0x42)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 24 bytes */
-#define EEPROM_REG_BAND_4_CHANNELS       ((0x5C)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22 bytes */
-#define EEPROM_REG_BAND_5_CHANNELS       ((0x74)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 12 bytes */
-#define EEPROM_REG_BAND_24_HT40_CHANNELS  ((0x82)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-#define EEPROM_REG_BAND_52_HT40_CHANNELS  ((0x92)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
-
-/* 6000 regulatory - indirect access */
-#define EEPROM_6000_REG_BAND_24_HT40_CHANNELS  ((0x80)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-/* 2.4 GHz */
-extern const u8 iwl_eeprom_band_1[14];
-
-#define ADDRESS_MSK                 0x0000FFFF
-#define INDIRECT_TYPE_MSK           0x000F0000
-#define INDIRECT_HOST               0x00010000
-#define INDIRECT_GENERAL            0x00020000
-#define INDIRECT_REGULATORY         0x00030000
-#define INDIRECT_CALIBRATION        0x00040000
-#define INDIRECT_PROCESS_ADJST      0x00050000
-#define INDIRECT_OTHERS             0x00060000
-#define INDIRECT_TXP_LIMIT          0x00070000
-#define INDIRECT_TXP_LIMIT_SIZE     0x00080000
-#define INDIRECT_ADDRESS            0x00100000
-
-/* General */
-#define EEPROM_DEVICE_ID                    (2*0x08)   /* 2 bytes */
-#define EEPROM_SUBSYSTEM_ID                (2*0x0A)    /* 2 bytes */
-#define EEPROM_MAC_ADDRESS                  (2*0x15)   /* 6  bytes */
-#define EEPROM_BOARD_REVISION               (2*0x35)   /* 2  bytes */
-#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1) /* 9  bytes */
-#define EEPROM_VERSION                      (2*0x44)   /* 2  bytes */
-#define EEPROM_SKU_CAP                      (2*0x45)   /* 2  bytes */
-#define EEPROM_OEM_MODE                     (2*0x46)   /* 2  bytes */
-#define EEPROM_RADIO_CONFIG                 (2*0x48)   /* 2  bytes */
-#define EEPROM_NUM_MAC_ADDRESS              (2*0x4C)   /* 2  bytes */
-
-/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
-#define EEPROM_RF_CFG_TYPE_MSK(x)   (x & 0x3)         /* bits 0-1   */
-#define EEPROM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
-#define EEPROM_RF_CFG_DASH_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
-#define EEPROM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
-#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
-#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
-
-#define EEPROM_RF_CONFIG_TYPE_MAX      0x3
-
-#define EEPROM_REGULATORY_BAND_NO_HT40                 (0)
-
-struct iwl_eeprom_ops {
-       const u32 regulatory_bands[7];
-       bool enhanced_txpower;
-};
-
-
-int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
-void iwl_eeprom_free(struct iwl_priv *priv);
-int iwl_eeprom_check_version(struct iwl_priv *priv);
-int iwl_eeprom_init_hw_params(struct iwl_priv *priv);
-u16 iwl_eeprom_calib_version(struct iwl_priv *priv);
-const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset);
-u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset);
-void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac);
-int iwl_init_channel_map(struct iwl_priv *priv);
-void iwl_free_channel_map(struct iwl_priv *priv);
-const struct iwl_channel_info *iwl_get_channel_info(
-               const struct iwl_priv *priv,
-               enum ieee80211_band band, u16 channel);
-void iwl_rf_config(struct iwl_priv *priv);
-
-#endif  /* __iwl_eeprom_h__ */
index 74bce97a860004b3fc8e921df2afef593379ebfb..80604664174722ca4c57703e7e86592b90949b86 100644 (file)
@@ -421,6 +421,8 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
                (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
 
 #define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98)
+#define FH_TX_TRB_REG(_chan)   (FH_MEM_LOWER_BOUND + 0x958 + (_chan) * 4)
+
 /* Instruct FH to increment the retry count of a packet when
  * it is brought from the memory to TX-FIFO
  */
index 081dd34d2387d1787ab575ebb2106c9d683ab119..66c873399abad9679093788fe29a22591430c532 100644 (file)
@@ -27,6 +27,7 @@
  *****************************************************************************/
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/export.h>
 
 #include "iwl-io.h"
 #include"iwl-csr.h"
@@ -52,6 +53,7 @@ void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
        __iwl_set_bit(trans, reg, mask);
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bit);
 
 void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -61,6 +63,25 @@ void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
        __iwl_clear_bit(trans, reg, mask);
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_clear_bit);
+
+void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
+{
+       unsigned long flags;
+       u32 v;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       WARN_ON_ONCE(value & ~mask);
+#endif
+
+       spin_lock_irqsave(&trans->reg_lock, flags);
+       v = iwl_read32(trans, reg);
+       v &= ~mask;
+       v |= value;
+       iwl_write32(trans, reg, v);
+       spin_unlock_irqrestore(&trans->reg_lock, flags);
+}
+EXPORT_SYMBOL_GPL(iwl_set_bits_mask);
 
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
                 u32 bits, u32 mask, int timeout)
@@ -76,6 +97,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
 
        return -ETIMEDOUT;
 }
+EXPORT_SYMBOL_GPL(iwl_poll_bit);
 
 int iwl_grab_nic_access_silent(struct iwl_trans *trans)
 {
@@ -117,6 +139,7 @@ int iwl_grab_nic_access_silent(struct iwl_trans *trans)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access_silent);
 
 bool iwl_grab_nic_access(struct iwl_trans *trans)
 {
@@ -130,6 +153,7 @@ bool iwl_grab_nic_access(struct iwl_trans *trans)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(iwl_grab_nic_access);
 
 void iwl_release_nic_access(struct iwl_trans *trans)
 {
@@ -144,6 +168,7 @@ void iwl_release_nic_access(struct iwl_trans *trans)
         */
        mmiowb();
 }
+EXPORT_SYMBOL_GPL(iwl_release_nic_access);
 
 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
@@ -158,6 +183,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 
        return value;
 }
+EXPORT_SYMBOL_GPL(iwl_read_direct32);
 
 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
 {
@@ -170,6 +196,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_write_direct32);
 
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
                        int timeout)
@@ -185,6 +212,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
 
        return -ETIMEDOUT;
 }
+EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
 
 static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 reg)
 {
@@ -211,6 +239,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 reg)
        spin_unlock_irqrestore(&trans->reg_lock, flags);
        return val;
 }
+EXPORT_SYMBOL_GPL(iwl_read_prph);
 
 void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
 {
@@ -223,6 +252,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 addr, u32 val)
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_write_prph);
 
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -236,6 +266,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
 
 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
                            u32 bits, u32 mask)
@@ -250,6 +281,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
 
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
 {
@@ -264,9 +296,10 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask)
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
 
-void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
-                             void *buf, int words)
+void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+                              void *buf, int dwords)
 {
        unsigned long flags;
        int offs;
@@ -275,24 +308,26 @@ void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
        spin_lock_irqsave(&trans->reg_lock, flags);
        if (likely(iwl_grab_nic_access(trans))) {
                iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
-               for (offs = 0; offs < words; offs++)
+               for (offs = 0; offs < dwords; offs++)
                        vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
                iwl_release_nic_access(trans);
        }
        spin_unlock_irqrestore(&trans->reg_lock, flags);
 }
+EXPORT_SYMBOL_GPL(_iwl_read_targ_mem_dwords);
 
 u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr)
 {
        u32 value;
 
-       _iwl_read_targ_mem_words(trans, addr, &value, 1);
+       _iwl_read_targ_mem_dwords(trans, addr, &value, 1);
 
        return value;
 }
+EXPORT_SYMBOL_GPL(iwl_read_targ_mem);
 
-int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
-                               void *buf, int words)
+int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+                              void *buf, int dwords)
 {
        unsigned long flags;
        int offs, result = 0;
@@ -301,7 +336,7 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
        spin_lock_irqsave(&trans->reg_lock, flags);
        if (likely(iwl_grab_nic_access(trans))) {
                iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
-               for (offs = 0; offs < words; offs++)
+               for (offs = 0; offs < dwords; offs++)
                        iwl_write32(trans, HBUS_TARG_MEM_WDAT, vals[offs]);
                iwl_release_nic_access(trans);
        } else
@@ -310,8 +345,10 @@ int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
 
        return result;
 }
+EXPORT_SYMBOL_GPL(_iwl_write_targ_mem_dwords);
 
 int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val)
 {
-       return _iwl_write_targ_mem_words(trans, addr, &val, 1);
+       return _iwl_write_targ_mem_dwords(trans, addr, &val, 1);
 }
+EXPORT_SYMBOL_GPL(iwl_write_targ_mem);
index abb3250164ba2109bfe3bdc73a2b1826e38d7964..50d3819739d12bd8296b3be9dec03425a488f45a 100644 (file)
@@ -54,6 +54,8 @@ static inline u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
 void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask);
 
+void iwl_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value);
+
 int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
                 u32 bits, u32 mask, int timeout);
 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
@@ -74,18 +76,18 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 reg,
                            u32 bits, u32 mask);
 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 reg, u32 mask);
 
-void _iwl_read_targ_mem_words(struct iwl_trans *trans, u32 addr,
-                             void *buf, int words);
+void _iwl_read_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+                              void *buf, int dwords);
 
-#define iwl_read_targ_mem_words(trans, addr, buf, bufsize)     \
+#define iwl_read_targ_mem_bytes(trans, addr, buf, bufsize)     \
        do {                                                    \
                BUILD_BUG_ON((bufsize) % sizeof(u32));          \
-               _iwl_read_targ_mem_words(trans, addr, buf,      \
-                                        (bufsize) / sizeof(u32));\
+               _iwl_read_targ_mem_dwords(trans, addr, buf,     \
+                                         (bufsize) / sizeof(u32));\
        } while (0)
 
-int _iwl_write_targ_mem_words(struct iwl_trans *trans, u32 addr,
-                             void *buf, int words);
+int _iwl_write_targ_mem_dwords(struct iwl_trans *trans, u32 addr,
+                              void *buf, int dwords);
 
 u32 iwl_read_targ_mem(struct iwl_trans *trans, u32 addr);
 int iwl_write_targ_mem(struct iwl_trans *trans, u32 addr, u32 val);
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
deleted file mode 100644 (file)
index 4700041..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-#include <asm/unaligned.h>
-
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/* Throughput          OFF time(ms)    ON time (ms)
- *     >300                    25              25
- *     >200 to 300             40              40
- *     >100 to 200             55              55
- *     >70 to 100              65              65
- *     >50 to 70               75              75
- *     >20 to 50               85              85
- *     >10 to 20               95              95
- *     >5 to 10                110             110
- *     >1 to 5                 130             130
- *     >0 to 1                 167             167
- *     <=0                                     SOLID ON
- */
-static const struct ieee80211_tpt_blink iwl_blink[] = {
-       { .throughput = 0, .blink_time = 334 },
-       { .throughput = 1 * 1024 - 1, .blink_time = 260 },
-       { .throughput = 5 * 1024 - 1, .blink_time = 220 },
-       { .throughput = 10 * 1024 - 1, .blink_time = 190 },
-       { .throughput = 20 * 1024 - 1, .blink_time = 170 },
-       { .throughput = 50 * 1024 - 1, .blink_time = 150 },
-       { .throughput = 70 * 1024 - 1, .blink_time = 130 },
-       { .throughput = 100 * 1024 - 1, .blink_time = 110 },
-       { .throughput = 200 * 1024 - 1, .blink_time = 80 },
-       { .throughput = 300 * 1024 - 1, .blink_time = 50 },
-};
-
-/* Set led register off */
-void iwlagn_led_enable(struct iwl_priv *priv)
-{
-       iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
-}
-
-/*
- * Adjust led blink rate to compensate on a MAC Clock difference on every HW
- * Led blink rate analysis showed an average deviation of 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)
-{
-       if (!compensation) {
-               IWL_ERR(priv, "undefined blink compensation: "
-                       "use pre-defined blinking time\n");
-               return time;
-       }
-
-       return (u8)((time * compensation) >> 6);
-}
-
-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,
-       };
-       u32 reg;
-
-       reg = iwl_read32(priv->trans, CSR_LED_REG);
-       if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
-               iwl_write32(priv->trans, CSR_LED_REG,
-                           reg & CSR_LED_BSM_CTRL_MSK);
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-/* Set led pattern command */
-static int iwl_led_cmd(struct iwl_priv *priv,
-                      unsigned long on,
-                      unsigned long off)
-{
-       struct iwl_led_cmd led_cmd = {
-               .id = IWL_LED_LINK,
-               .interval = IWL_DEF_LED_INTRVL
-       };
-       int ret;
-
-       if (!test_bit(STATUS_READY, &priv->status))
-               return -EBUSY;
-
-       if (priv->blink_on == on && priv->blink_off == off)
-               return 0;
-
-       if (off == 0) {
-               /* led is SOLID_ON */
-               on = IWL_LED_SOLID;
-       }
-
-       IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
-                       priv->cfg->base_params->led_compensation);
-       led_cmd.on = iwl_blink_compensation(priv, on,
-                               priv->cfg->base_params->led_compensation);
-       led_cmd.off = iwl_blink_compensation(priv, off,
-                               priv->cfg->base_params->led_compensation);
-
-       ret = iwl_send_led_cmd(priv, &led_cmd);
-       if (!ret) {
-               priv->blink_on = on;
-               priv->blink_off = off;
-       }
-       return ret;
-}
-
-static void iwl_led_brightness_set(struct led_classdev *led_cdev,
-                                  enum led_brightness brightness)
-{
-       struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
-       unsigned long on = 0;
-
-       if (brightness > 0)
-               on = IWL_LED_SOLID;
-
-       iwl_led_cmd(priv, on, 0);
-}
-
-static int iwl_led_blink_set(struct led_classdev *led_cdev,
-                            unsigned long *delay_on,
-                            unsigned long *delay_off)
-{
-       struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
-
-       return iwl_led_cmd(priv, *delay_on, *delay_off);
-}
-
-void iwl_leds_init(struct iwl_priv *priv)
-{
-       int mode = iwlwifi_mod_params.led_mode;
-       int ret;
-
-       if (mode == IWL_LED_DISABLE) {
-               IWL_INFO(priv, "Led disabled\n");
-               return;
-       }
-       if (mode == IWL_LED_DEFAULT)
-               mode = priv->cfg->led_mode;
-
-       priv->led.name = kasprintf(GFP_KERNEL, "%s-led",
-                                  wiphy_name(priv->hw->wiphy));
-       priv->led.brightness_set = iwl_led_brightness_set;
-       priv->led.blink_set = iwl_led_blink_set;
-       priv->led.max_brightness = 1;
-
-       switch (mode) {
-       case IWL_LED_DEFAULT:
-               WARN_ON(1);
-               break;
-       case IWL_LED_BLINK:
-               priv->led.default_trigger =
-                       ieee80211_create_tpt_led_trigger(priv->hw,
-                                       IEEE80211_TPT_LEDTRIG_FL_CONNECTED,
-                                       iwl_blink, ARRAY_SIZE(iwl_blink));
-               break;
-       case IWL_LED_RF_STATE:
-               priv->led.default_trigger =
-                       ieee80211_get_radio_led_name(priv->hw);
-               break;
-       }
-
-       ret = led_classdev_register(priv->trans->dev, &priv->led);
-       if (ret) {
-               kfree(priv->led.name);
-               return;
-       }
-
-       priv->led_registered = true;
-}
-
-void iwl_leds_exit(struct iwl_priv *priv)
-{
-       if (!priv->led_registered)
-               return;
-
-       led_classdev_unregister(&priv->led);
-       kfree(priv->led.name);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
deleted file mode 100644 (file)
index b02a853..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 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_leds_h__
-#define __iwl_leds_h__
-
-
-struct iwl_priv;
-
-#define IWL_LED_SOLID 11
-#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
-
-#define IWL_LED_ACTIVITY       (0<<1)
-#define IWL_LED_LINK           (1<<1)
-
-void iwlagn_led_enable(struct iwl_priv *priv);
-void iwl_leds_init(struct iwl_priv *priv);
-void iwl_leds_exit(struct iwl_priv *priv);
-
-#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
deleted file mode 100644 (file)
index 0136803..0000000
+++ /dev/null
@@ -1,1645 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-
-#include <net/mac80211.h>
-
-#include <asm/div64.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-calib.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-#include "iwl-op-mode.h"
-#include "iwl-modparams.h"
-
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_GO) |
-                        BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
-       },
-};
-
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_dualmode[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_sta_ap_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
-       },
-};
-
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_p2p[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_p2p_sta_go_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_p2p_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
-       },
-};
-
-/*
- * Not a mac80211 entry point function, but it fits in with all the
- * other mac80211 functions grouped here.
- */
-int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                             const struct iwl_ucode_capabilities *capa)
-{
-       int ret;
-       struct ieee80211_hw *hw = priv->hw;
-       struct iwl_rxon_context *ctx;
-
-       hw->rate_control_algorithm = "iwl-agn-rs";
-
-       /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_NEED_DTIM_PERIOD |
-                   IEEE80211_HW_SPECTRUM_MGMT |
-                   IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-                   IEEE80211_HW_QUEUE_CONTROL |
-                   IEEE80211_HW_SUPPORTS_PS |
-                   IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
-                   IEEE80211_HW_WANT_MONITOR_VIF |
-                   IEEE80211_HW_SCAN_WHILE_IDLE;
-
-       hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
-
-       /*
-        * Including the following line will crash some AP's.  This
-        * workaround removes the stimulus which causes the crash until
-        * the AP software can be fixed.
-       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-        */
-
-       if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)
-               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
-
-#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
-       /* enable 11w if the uCode advertise */
-       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
-               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-       hw->sta_data_size = sizeof(struct iwl_station_priv);
-       hw->vif_data_size = sizeof(struct iwl_vif_priv);
-
-       for_each_context(priv, ctx) {
-               hw->wiphy->interface_modes |= ctx->interface_modes;
-               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
-       }
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
-       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
-               hw->wiphy->iface_combinations =
-                       iwlagn_iface_combinations_dualmode;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
-       }
-
-       hw->wiphy->max_remain_on_channel_duration = 1000;
-
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
-
-#ifdef CONFIG_PM_SLEEP
-       if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
-           priv->trans->ops->wowlan_suspend &&
-           device_can_wakeup(priv->trans->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
-               if (!iwlwifi_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
-                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-
-               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len =
-                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len =
-                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
-       }
-#endif
-
-       if (iwlwifi_mod_params.power_save)
-               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
-       else
-               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
-       /* we create the 802.11 header and a max-length SSID element */
-       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
-
-       /*
-        * We don't use all queues: 4 and 9 are unused and any
-        * aggregation queue gets mapped down to the AC queue.
-        */
-       hw->queues = IWLAGN_FIRST_AMPDU_QUEUE;
-
-       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];
-
-       hw->wiphy->hw_version = priv->trans->hw_id;
-
-       iwl_leds_init(priv);
-
-       ret = ieee80211_register_hw(priv->hw);
-       if (ret) {
-               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
-               iwl_leds_exit(priv);
-               return ret;
-       }
-       priv->mac80211_registered = 1;
-
-       return 0;
-}
-
-void iwlagn_mac_unregister(struct iwl_priv *priv)
-{
-       if (!priv->mac80211_registered)
-               return;
-       iwl_leds_exit(priv);
-       ieee80211_unregister_hw(priv->hw);
-       priv->mac80211_registered = 0;
-}
-
-static int __iwl_up(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
-               return -EIO;
-       }
-
-       for_each_context(priv, ctx) {
-               ret = iwlagn_alloc_bcast_station(priv, ctx);
-               if (ret) {
-                       iwl_dealloc_bcast_stations(priv);
-                       return ret;
-               }
-       }
-
-       ret = iwl_run_init_ucode(priv);
-       if (ret) {
-               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
-       if (ret) {
-               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-       return 0;
-
- error:
-       set_bit(STATUS_EXIT_PENDING, &priv->status);
-       iwl_down(priv);
-       clear_bit(STATUS_EXIT_PENDING, &priv->status);
-
-       IWL_ERR(priv, "Unable to initialize device.\n");
-       return ret;
-}
-
-static int iwlagn_mac_start(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       /* we should be verifying the device is ready to be opened */
-       mutex_lock(&priv->mutex);
-       ret = __iwl_up(priv);
-       mutex_unlock(&priv->mutex);
-       if (ret)
-               return ret;
-
-       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
-
-       /* Now we should be done, and the READY bit should be set. */
-       if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
-               ret = -EIO;
-
-       iwlagn_led_enable(priv);
-
-       priv->is_open = 1;
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
-}
-
-void iwlagn_mac_stop(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (!priv->is_open)
-               return;
-
-       priv->is_open = 0;
-
-       mutex_lock(&priv->mutex);
-       iwl_down(priv);
-       mutex_unlock(&priv->mutex);
-
-       iwl_cancel_deferred_work(priv);
-
-       flush_workqueue(priv->workqueue);
-
-       /* User space software may expect getting rfkill changes
-        * even if interface is down, trans->down will leave the RF
-        * kill interrupt enabled
-        */
-       iwl_trans_stop_hw(priv->trans, false);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct cfg80211_gtk_rekey_data *data)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       if (iwlwifi_mod_params.sw_crypto)
-               return;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
-               goto out;
-
-       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
-       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
-       priv->replay_ctr =
-               cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
-       priv->have_rekey_data = true;
-
- out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       int ret;
-
-       if (WARN_ON(!wowlan))
-               return -EINVAL;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       /* Don't attempt WoWLAN when not associated, tear down instead. */
-       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
-           !iwl_is_associated_ctx(ctx)) {
-               ret = 1;
-               goto out;
-       }
-
-       ret = iwlagn_suspend(priv, wowlan);
-       if (ret)
-               goto error;
-
-       device_set_wakeup_enable(priv->trans->dev, true);
-
-       iwl_trans_wowlan_suspend(priv->trans);
-
-       goto out;
-
- error:
-       priv->wowlan = false;
-       iwlagn_prepare_restart(priv);
-       ieee80211_restart_hw(priv->hw);
- out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_resume(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct ieee80211_vif *vif;
-       unsigned long flags;
-       u32 base, status = 0xffffffff;
-       int ret = -EIO;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       base = priv->device_pointers.error_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               spin_lock_irqsave(&priv->trans->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(priv->trans);
-               if (likely(ret == 0)) {
-                       iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(priv->trans);
-               }
-               spin_unlock_irqrestore(&priv->trans->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               if (ret == 0) {
-                       const struct fw_img *img;
-
-                       img = &(priv->fw->img[IWL_UCODE_WOWLAN]);
-                       if (!priv->wowlan_sram) {
-                               priv->wowlan_sram =
-                                  kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len,
-                                               GFP_KERNEL);
-                       }
-
-                       if (priv->wowlan_sram)
-                               _iwl_read_targ_mem_words(
-                                     priv->trans, 0x800000,
-                                     priv->wowlan_sram,
-                                     img->sec[IWL_UCODE_SECTION_DATA].len / 4);
-               }
-#endif
-       }
-
-       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
-       vif = ctx->vif;
-
-       priv->wowlan = false;
-
-       device_set_wakeup_enable(priv->trans->dev, false);
-
-       iwlagn_prepare_restart(priv);
-
-       memset((void *)&ctx->active, 0, sizeof(ctx->active));
-       iwl_connection_init_rx_config(priv, ctx);
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       ieee80211_resume_disconnect(vif);
-
-       return 1;
-}
-
-#endif
-
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
-       if (iwlagn_tx_skb(priv, skb))
-               dev_kfree_skb_any(skb);
-}
-
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_key_conf *keyconf,
-                               struct ieee80211_sta *sta,
-                               u32 iv32, u16 *phase1key)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
-}
-
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-                      struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta,
-                      struct ieee80211_key_conf *key)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       bool is_default_wep_key = false;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (iwlwifi_mod_params.sw_crypto) {
-               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
-               return -EOPNOTSUPP;
-       }
-
-       switch (key->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-               /* fall through */
-       case WLAN_CIPHER_SUITE_CCMP:
-               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-               break;
-       default:
-               break;
-       }
-
-       /*
-        * We could program these keys into the hardware as well, but we
-        * don't expect much multicast traffic in IBSS and having keys
-        * for more stations is probably more useful.
-        *
-        * Mark key TX-only and return 0.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC &&
-           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-               key->hw_key_idx = WEP_INVALID_OFFSET;
-               return 0;
-       }
-
-       /* If they key was TX-only, accept deletion */
-       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
-               return 0;
-
-       mutex_lock(&priv->mutex);
-       iwl_scan_cancel_timeout(priv, 100);
-
-       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
-
-       /*
-        * If we are getting WEP group key and we didn't receive any key mapping
-        * so far, we are in legacy wep mode (group key only), otherwise we are
-        * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode.
-        */
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
-               if (cmd == SET_KEY)
-                       is_default_wep_key = !ctx->key_mapping_keys;
-               else
-                       is_default_wep_key =
-                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
-       }
-
-
-       switch (cmd) {
-       case SET_KEY:
-               if (is_default_wep_key) {
-                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
-                       break;
-               }
-               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
-               if (ret) {
-                       /*
-                        * can't add key for RX, but we don't need it
-                        * in the device for TX so still return 0
-                        */
-                       ret = 0;
-                       key->hw_key_idx = WEP_INVALID_OFFSET;
-               }
-
-               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
-               break;
-       case DISABLE_KEY:
-               if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, ctx, key);
-               else
-                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
-
-               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-                           struct ieee80211_vif *vif,
-                           enum ieee80211_ampdu_mlme_action action,
-                           struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                           u8 buf_size)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int ret = -EINVAL;
-       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-
-       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
-                    sta->addr, tid);
-
-       if (!(priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE))
-               return -EACCES;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       switch (action) {
-       case IEEE80211_AMPDU_RX_START:
-               if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
-                       break;
-               IWL_DEBUG_HT(priv, "start Rx\n");
-               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
-               break;
-       case IEEE80211_AMPDU_RX_STOP:
-               IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
-               break;
-       case IEEE80211_AMPDU_TX_START:
-               if (!priv->trans->ops->tx_agg_setup)
-                       break;
-               if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
-                       break;
-               IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
-               break;
-       case IEEE80211_AMPDU_TX_STOP:
-               IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
-               if ((ret == 0) && (priv->agg_tids_count > 0)) {
-                       priv->agg_tids_count--;
-                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                                    priv->agg_tids_count);
-               }
-               if (!priv->agg_tids_count &&
-                   priv->hw_params.use_rts_for_aggregation) {
-                       /*
-                        * switch off RTS/CTS if it was previously enabled
-                        */
-                       sta_priv->lq_sta.lq.general_params.flags &=
-                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-               }
-               break;
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
-               ret = iwlagn_tx_agg_oper(priv, vif, sta, tid, buf_size);
-               break;
-       }
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return ret;
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
-       int ret;
-       u8 sta_id;
-
-       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
-                       sta->addr);
-       sta_priv->sta_id = IWL_INVALID_STATION;
-
-       atomic_set(&sta_priv->pending_frames, 0);
-       if (vif->type == NL80211_IFTYPE_AP)
-               sta_priv->client = true;
-
-       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
-                                    is_ap, sta, &sta_id);
-       if (ret) {
-               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
-                       sta->addr, ret);
-               /* Should we return success if return code is EEXIST ? */
-               return ret;
-       }
-
-       sta_priv->sta_id = sta_id;
-
-       return 0;
-}
-
-static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int ret;
-
-       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
-
-       if (vif->type == NL80211_IFTYPE_STATION) {
-               /*
-                * Station will be removed from device when the RXON
-                * is set to unassociated -- just deactivate it here
-                * to avoid re-programming it.
-                */
-               ret = 0;
-               iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
-       } else {
-               ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
-               if (ret)
-                       IWL_DEBUG_QUIET_RFKILL(priv,
-                               "Error removing station %pM\n", sta->addr);
-       }
-       return ret;
-}
-
-int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
-                        struct ieee80211_vif *vif,
-                        struct ieee80211_sta *sta,
-                        enum ieee80211_sta_state old_state,
-                        enum ieee80211_sta_state new_state)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       enum {
-               NONE, ADD, REMOVE, HT_RATE_INIT, ADD_RATE_INIT,
-       } op = NONE;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "station %pM state change %d->%d\n",
-                          sta->addr, old_state, new_state);
-
-       mutex_lock(&priv->mutex);
-       if (vif->type == NL80211_IFTYPE_STATION) {
-               if (old_state == IEEE80211_STA_NOTEXIST &&
-                   new_state == IEEE80211_STA_NONE)
-                       op = ADD;
-               else if (old_state == IEEE80211_STA_NONE &&
-                        new_state == IEEE80211_STA_NOTEXIST)
-                       op = REMOVE;
-               else if (old_state == IEEE80211_STA_AUTH &&
-                        new_state == IEEE80211_STA_ASSOC)
-                       op = HT_RATE_INIT;
-       } else {
-               if (old_state == IEEE80211_STA_AUTH &&
-                   new_state == IEEE80211_STA_ASSOC)
-                       op = ADD_RATE_INIT;
-               else if (old_state == IEEE80211_STA_ASSOC &&
-                        new_state == IEEE80211_STA_AUTH)
-                       op = REMOVE;
-       }
-
-       switch (op) {
-       case ADD:
-               ret = iwlagn_mac_sta_add(hw, vif, sta);
-               if (ret)
-                       break;
-               /*
-                * Clear the in-progress flag, the AP station entry was added
-                * but we'll initialize LQ only when we've associated (which
-                * would also clear the in-progress flag). This is necessary
-                * in case we never initialize LQ because association fails.
-                */
-               spin_lock_bh(&priv->sta_lock);
-               priv->stations[iwl_sta_id(sta)].used &=
-                       ~IWL_STA_UCODE_INPROGRESS;
-               spin_unlock_bh(&priv->sta_lock);
-               break;
-       case REMOVE:
-               ret = iwlagn_mac_sta_remove(hw, vif, sta);
-               break;
-       case ADD_RATE_INIT:
-               ret = iwlagn_mac_sta_add(hw, vif, sta);
-               if (ret)
-                       break;
-               /* Initialize rate scaling */
-               IWL_DEBUG_INFO(priv,
-                              "Initializing rate scaling for station %pM\n",
-                              sta->addr);
-               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
-               ret = 0;
-               break;
-       case HT_RATE_INIT:
-               /* Initialize rate scaling */
-               ret = iwl_sta_update_ht(priv, vif_priv->ctx, sta);
-               if (ret)
-                       break;
-               IWL_DEBUG_INFO(priv,
-                              "Initializing rate scaling for station %pM\n",
-                              sta->addr);
-               iwl_rs_rate_init(priv, sta, iwl_sta_id(sta));
-               ret = 0;
-               break;
-       default:
-               ret = 0;
-               break;
-       }
-
-       /*
-        * mac80211 might WARN if we fail, but due the way we
-        * (badly) handle hard rfkill, we might fail here
-        */
-       if (iwl_is_rfkill(priv))
-               ret = 0;
-
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-                              struct ieee80211_channel_switch *ch_switch)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       const struct iwl_channel_info *ch_info;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_channel *channel = ch_switch->channel;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-       /*
-        * MULTI-FIXME
-        * When we add support for multiple interfaces, we need to
-        * revisit this. The channel switch command in the device
-        * only affects the BSS context, but what does that really
-        * mean? And what if we get a CSA on the second interface?
-        * This needs a lot of work.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u16 ch;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->mutex);
-
-       if (iwl_is_rfkill(priv))
-               goto out;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-           test_bit(STATUS_SCANNING, &priv->status) ||
-           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-               goto out;
-
-       if (!iwl_is_associated_ctx(ctx))
-               goto out;
-
-       if (!priv->lib->set_channel_switch)
-               goto out;
-
-       ch = channel->hw_value;
-       if (le16_to_cpu(ctx->active.channel) == ch)
-               goto out;
-
-       ch_info = iwl_get_channel_info(priv, channel->band, ch);
-       if (!is_channel_valid(ch_info)) {
-               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-               goto out;
-       }
-
-       priv->current_ht_config.smps = conf->smps_mode;
-
-       /* Configure HT40 channels */
-       ctx->ht.enabled = conf_is_ht(conf);
-       if (ctx->ht.enabled)
-               iwlagn_config_ht40(conf, ctx);
-       else
-               ctx->ht.is_40mhz = false;
-
-       if ((le16_to_cpu(ctx->staging.channel) != ch))
-               ctx->staging.flags = 0;
-
-       iwl_set_rxon_channel(priv, channel, ctx);
-       iwl_set_rxon_ht(priv, ht_conf);
-       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
-
-       /*
-        * at this point, staging_rxon has the
-        * configuration for channel switch
-        */
-       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
-       priv->switch_channel = cpu_to_le16(ch);
-       if (priv->lib->set_channel_switch(priv, ch_switch)) {
-               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
-               priv->switch_channel = 0;
-               ieee80211_chswitch_done(ctx->vif, false);
-       }
-
-out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
-{
-       /*
-        * MULTI-FIXME
-        * See iwlagn_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
-               ieee80211_chswitch_done(ctx->vif, is_success);
-}
-
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
-                            unsigned int changed_flags,
-                            unsigned int *total_flags,
-                            u64 multicast)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       __le32 filter_or = 0, filter_nand = 0;
-       struct iwl_rxon_context *ctx;
-
-#define CHK(test, flag)        do { \
-       if (*total_flags & (test))              \
-               filter_or |= (flag);            \
-       else                                    \
-               filter_nand |= (flag);          \
-       } while (0)
-
-       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
-                       changed_flags, *total_flags);
-
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
-       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
-       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
-
-#undef CHK
-
-       mutex_lock(&priv->mutex);
-
-       for_each_context(priv, ctx) {
-               ctx->staging.filter_flags &= ~filter_nand;
-               ctx->staging.filter_flags |= filter_or;
-
-               /*
-                * Not committing directly because hardware can perform a scan,
-                * but we'll eventually commit the filter flags change anyway.
-                */
-       }
-
-       mutex_unlock(&priv->mutex);
-
-       /*
-        * Receiving all multicast frames is always enabled by the
-        * default flags setup in iwl_connection_init_rx_config()
-        * since we currently do not support programming multicast
-        * filters into the device.
-        */
-       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
-                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
-}
-
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       mutex_lock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
-               goto done;
-       }
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
-               goto done;
-       }
-
-       /*
-        * mac80211 will not push any more frames for transmit
-        * until the flush is completed
-        */
-       if (drop) {
-               IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
-                       IWL_ERR(priv, "flush request fail\n");
-                       goto done;
-               }
-       }
-       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(priv->trans);
-done:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
-                                    struct ieee80211_channel *channel,
-                                    enum nl80211_channel_type channel_type,
-                                    int duration)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-       int err = 0;
-
-       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       priv->hw_roc_channel = channel;
-       priv->hw_roc_chantype = channel_type;
-       /* convert from ms to TU */
-       priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
-       priv->hw_roc_start_notified = false;
-       cancel_delayed_work(&priv->hw_roc_disable_work);
-
-       if (!ctx->is_active) {
-               static const struct iwl_qos_info default_qos_data = {
-                       .def_qos_parm = {
-                               .ac[0] = {
-                                       .cw_min = cpu_to_le16(3),
-                                       .cw_max = cpu_to_le16(7),
-                                       .aifsn = 2,
-                                       .edca_txop = cpu_to_le16(1504),
-                               },
-                               .ac[1] = {
-                                       .cw_min = cpu_to_le16(7),
-                                       .cw_max = cpu_to_le16(15),
-                                       .aifsn = 2,
-                                       .edca_txop = cpu_to_le16(3008),
-                               },
-                               .ac[2] = {
-                                       .cw_min = cpu_to_le16(15),
-                                       .cw_max = cpu_to_le16(1023),
-                                       .aifsn = 3,
-                               },
-                               .ac[3] = {
-                                       .cw_min = cpu_to_le16(15),
-                                       .cw_max = cpu_to_le16(1023),
-                                       .aifsn = 7,
-                               },
-                       },
-               };
-
-               ctx->is_active = true;
-               ctx->qos_data = default_qos_data;
-               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-               memcpy(ctx->staging.node_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               memcpy(ctx->staging.bssid_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err)
-                       goto out;
-               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
-                                            RXON_FILTER_PROMISC_MSK |
-                                            RXON_FILTER_CTL2HOST_MSK;
-
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err) {
-                       iwlagn_disable_roc(priv);
-                       goto out;
-               }
-               priv->hw_roc_setup = true;
-       }
-
-       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
-       if (err)
-               iwlagn_disable_roc(priv);
-
- out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
-
-int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
-void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-                             enum ieee80211_rssi_event rssi_event)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
-
-       if (priv->cfg->bt_params &&
-                       priv->cfg->bt_params->advanced_bt_coexist) {
-               if (rssi_event == RSSI_EVENT_LOW)
-                       priv->bt_enable_pspoll = true;
-               else if (rssi_event == RSSI_EVENT_HIGH)
-                       priv->bt_enable_pspoll = false;
-
-               iwlagn_send_advance_bt_config(priv);
-       } else {
-               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
-                               "ignoring RSSI callback\n");
-       }
-
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-                      struct ieee80211_sta *sta, bool set)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       queue_work(priv->workqueue, &priv->beacon_update);
-
-       return 0;
-}
-
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif, u16 queue,
-                      const struct ieee80211_tx_queue_params *params)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int q;
-
-       if (WARN_ON(!ctx))
-               return -EINVAL;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (!iwl_is_ready_rf(priv)) {
-               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-               return -EIO;
-       }
-
-       if (queue >= AC_NUM) {
-               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
-               return 0;
-       }
-
-       q = AC_NUM - 1 - queue;
-
-       mutex_lock(&priv->mutex);
-
-       ctx->qos_data.def_qos_parm.ac[q].cw_min =
-               cpu_to_le16(params->cw_min);
-       ctx->qos_data.def_qos_parm.ac[q].cw_max =
-               cpu_to_le16(params->cw_max);
-       ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-       ctx->qos_data.def_qos_parm.ac[q].edca_txop =
-                       cpu_to_le16((params->txop * 32));
-
-       ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-
-       mutex_unlock(&priv->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
-}
-
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-
-       return priv->ibss_manager == IWL_IBSS_MANAGER;
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       iwl_connection_init_rx_config(priv, ctx);
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       return iwlagn_commit_rxon(priv, ctx);
-}
-
-int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       struct ieee80211_vif *vif = ctx->vif;
-       int err, ac;
-
-       lockdep_assert_held(&priv->mutex);
-
-       /*
-        * This variable will be correct only when there's just
-        * a single context, but all code using it is for hardware
-        * that supports only one context.
-        */
-       priv->iw_mode = vif->type;
-
-       ctx->is_active = true;
-
-       err = iwl_set_mode(priv, ctx);
-       if (err) {
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-               return err;
-       }
-
-       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
-           vif->type == NL80211_IFTYPE_ADHOC) {
-               /*
-                * pretend to have high BT traffic as long as we
-                * are operating in IBSS mode, as this will cause
-                * the rate scaling etc. to behave as intended.
-                */
-               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-       }
-
-       /* set up queue mappings */
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               vif->hw_queue[ac] = ctx->ac_to_queue[ac];
-
-       if (vif->type == NL80211_IFTYPE_AP)
-               vif->cab_queue = ctx->mcast_queue;
-       else
-               vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
-
-       return 0;
-}
-
-static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                                   struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *tmp, *ctx = NULL;
-       int err;
-       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
-       bool reset = false;
-
-       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
-                          viftype, vif->addr);
-
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       mutex_lock(&priv->mutex);
-
-       iwlagn_disable_roc(priv);
-
-       if (!iwl_is_ready_rf(priv)) {
-               IWL_WARN(priv, "Try to add interface when device not ready\n");
-               err = -EINVAL;
-               goto out;
-       }
-
-       for_each_context(priv, tmp) {
-               u32 possible_modes =
-                       tmp->interface_modes | tmp->exclusive_interface_modes;
-
-               if (tmp->vif) {
-                       /* On reset we need to add the same interface again */
-                       if (tmp->vif == vif) {
-                               reset = true;
-                               ctx = tmp;
-                               break;
-                       }
-
-                       /* check if this busy context is exclusive */
-                       if (tmp->exclusive_interface_modes &
-                                               BIT(tmp->vif->type)) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       continue;
-               }
-
-               if (!(possible_modes & BIT(viftype)))
-                       continue;
-
-               /* have maybe usable context w/o interface */
-               ctx = tmp;
-               break;
-       }
-
-       if (!ctx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       vif_priv->ctx = ctx;
-       ctx->vif = vif;
-
-       err = iwl_setup_interface(priv, ctx);
-       if (!err || reset)
-               goto out;
-
-       ctx->vif = NULL;
-       priv->iw_mode = NL80211_IFTYPE_STATION;
- out:
-       mutex_unlock(&priv->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return err;
-}
-
-void iwl_teardown_interface(struct iwl_priv *priv,
-                           struct ieee80211_vif *vif,
-                           bool mode_change)
-{
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (priv->scan_vif == vif) {
-               iwl_scan_cancel_timeout(priv, 200);
-               iwl_force_scan_end(priv);
-       }
-
-       if (!mode_change) {
-               iwl_set_mode(priv, ctx);
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-       }
-
-       /*
-        * When removing the IBSS interface, overwrite the
-        * BT traffic load with the stored one from the last
-        * notification, if any. If this is a device that
-        * doesn't implement this, this has no effect since
-        * both values are the same and zero.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC)
-               priv->bt_traffic_load = priv->last_bt_traffic_load;
-}
-
-static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->mutex);
-
-       if (WARN_ON(ctx->vif != vif)) {
-               struct iwl_rxon_context *tmp;
-               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
-               for_each_context(priv, tmp)
-                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
-                               tmp->ctxid, tmp, tmp->vif);
-       }
-       ctx->vif = NULL;
-
-       iwl_teardown_interface(priv, vif, false);
-
-       mutex_unlock(&priv->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
-
-static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               enum nl80211_iftype newtype, bool newp2p)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_rxon_context *tmp;
-       enum nl80211_iftype newviftype = newtype;
-       u32 interface_modes;
-       int err;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       newtype = ieee80211_iftype_p2p(newtype, newp2p);
-
-       mutex_lock(&priv->mutex);
-
-       if (!ctx->vif || !iwl_is_ready_rf(priv)) {
-               /*
-                * Huh? But wait ... this can maybe happen when
-                * we're in the middle of a firmware restart!
-                */
-               err = -EBUSY;
-               goto out;
-       }
-
-       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
-
-       if (!(interface_modes & BIT(newtype))) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       /*
-        * Refuse a change that should be done by moving from the PAN
-        * context to the BSS context instead, if the BSS context is
-        * available and can support the new interface type.
-        */
-       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
-           (bss_ctx->interface_modes & BIT(newtype) ||
-            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
-               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-               err = -EBUSY;
-               goto out;
-       }
-
-       if (ctx->exclusive_interface_modes & BIT(newtype)) {
-               for_each_context(priv, tmp) {
-                       if (ctx == tmp)
-                               continue;
-
-                       if (!tmp->vif)
-                               continue;
-
-                       /*
-                        * The current mode switch would be exclusive, but
-                        * another context is active ... refuse the switch.
-                        */
-                       err = -EBUSY;
-                       goto out;
-               }
-       }
-
-       /* success */
-       iwl_teardown_interface(priv, vif, true);
-       vif->type = newviftype;
-       vif->p2p = newp2p;
-       err = iwl_setup_interface(priv, ctx);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
-       err = 0;
-
- out:
-       mutex_unlock(&priv->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
-
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif,
-                      struct cfg80211_scan_request *req)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (req->n_channels == 0)
-               return -EINVAL;
-
-       mutex_lock(&priv->mutex);
-
-       /*
-        * If an internal scan is in progress, just set
-        * up the scan_request as per above.
-        */
-       if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv,
-                              "SCAN request during internal scan - defer\n");
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               ret = 0;
-       } else {
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               /*
-                * mac80211 will only ask for one band at a time
-                * so using channels[0] here is ok
-                */
-               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
-                                       req->channels[0]->band);
-               if (ret) {
-                       priv->scan_request = NULL;
-                       priv->scan_vif = NULL;
-               }
-       }
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       mutex_unlock(&priv->mutex);
-
-       return ret;
-}
-
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-       struct iwl_addsta_cmd cmd = {
-               .mode = STA_CONTROL_MODIFY_MSK,
-               .station_flags_msk = STA_FLG_PWR_SAVE_MSK,
-               .sta.sta_id = sta_id,
-       };
-
-       iwl_send_add_sta(priv, &cmd, CMD_ASYNC);
-}
-
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       switch (cmd) {
-       case STA_NOTIFY_SLEEP:
-               WARN_ON(!sta_priv->client);
-               sta_priv->asleep = true;
-               if (atomic_read(&sta_priv->pending_frames) > 0)
-                       ieee80211_sta_block_awake(hw, sta, true);
-               break;
-       case STA_NOTIFY_AWAKE:
-               WARN_ON(!sta_priv->client);
-               if (!sta_priv->asleep)
-                       break;
-               sta_priv->asleep = false;
-               sta_id = iwl_sta_id(sta);
-               if (sta_id != IWL_INVALID_STATION)
-                       iwl_sta_modify_ps_wake(priv, sta_id);
-               break;
-       default:
-               break;
-       }
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-struct ieee80211_ops iwlagn_hw_ops = {
-       .tx = iwlagn_mac_tx,
-       .start = iwlagn_mac_start,
-       .stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM_SLEEP
-       .suspend = iwlagn_mac_suspend,
-       .resume = iwlagn_mac_resume,
-#endif
-       .add_interface = iwlagn_mac_add_interface,
-       .remove_interface = iwlagn_mac_remove_interface,
-       .change_interface = iwlagn_mac_change_interface,
-       .config = iwlagn_mac_config,
-       .configure_filter = iwlagn_configure_filter,
-       .set_key = iwlagn_mac_set_key,
-       .update_tkip_key = iwlagn_mac_update_tkip_key,
-       .set_rekey_data = iwlagn_mac_set_rekey_data,
-       .conf_tx = iwlagn_mac_conf_tx,
-       .bss_info_changed = iwlagn_bss_info_changed,
-       .ampdu_action = iwlagn_mac_ampdu_action,
-       .hw_scan = iwlagn_mac_hw_scan,
-       .sta_notify = iwlagn_mac_sta_notify,
-       .sta_state = iwlagn_mac_sta_state,
-       .channel_switch = iwlagn_mac_channel_switch,
-       .flush = iwlagn_mac_flush,
-       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
-       .remain_on_channel = iwlagn_mac_remain_on_channel,
-       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
-       .rssi_callback = iwlagn_mac_rssi_callback,
-       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
-       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
-       .set_tim = iwlagn_mac_set_tim,
-};
-
-/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(void)
-{
-       struct iwl_priv *priv;
-       struct iwl_op_mode *op_mode;
-       /* mac80211 allocates memory for this device instance, including
-        *   space for this driver's private structure */
-       struct ieee80211_hw *hw;
-
-       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv) +
-                               sizeof(struct iwl_op_mode), &iwlagn_hw_ops);
-       if (!hw)
-               goto out;
-
-       op_mode = hw->priv;
-       priv = IWL_OP_MODE_GET_DVM(op_mode);
-       priv->hw = hw;
-
-out:
-       return hw;
-}
index 0066b899fe5cffe39ae526b73987e75026632ec5..c61f2070f15a0fab26d6f6caf20de846ca328010 100644 (file)
@@ -61,6 +61,7 @@
  *
  *****************************************************************************/
 #include <linux/sched.h>
+#include <linux/export.h>
 
 #include "iwl-notif-wait.h"
 
@@ -71,6 +72,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
        INIT_LIST_HEAD(&notif_wait->notif_waits);
        init_waitqueue_head(&notif_wait->notif_waitq);
 }
+EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
 
 void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
                                  struct iwl_rx_packet *pkt)
@@ -115,20 +117,20 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
        if (triggered)
                wake_up_all(&notif_wait->notif_waitq);
 }
+EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
 
 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
 {
-       unsigned long flags;
        struct iwl_notification_wait *wait_entry;
 
-       spin_lock_irqsave(&notif_wait->notif_wait_lock, flags);
+       spin_lock(&notif_wait->notif_wait_lock);
        list_for_each_entry(wait_entry, &notif_wait->notif_waits, list)
                wait_entry->aborted = true;
-       spin_unlock_irqrestore(&notif_wait->notif_wait_lock, flags);
+       spin_unlock(&notif_wait->notif_wait_lock);
 
        wake_up_all(&notif_wait->notif_waitq);
 }
-
+EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
 
 void
 iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@@ -152,6 +154,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
        list_add(&wait_entry->list, &notif_wait->notif_waits);
        spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
+EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
 
 int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
                          struct iwl_notification_wait *wait_entry,
@@ -175,6 +178,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
                return -ETIMEDOUT;
        return 0;
 }
+EXPORT_SYMBOL_GPL(iwl_wait_notification);
 
 void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
                             struct iwl_notification_wait *wait_entry)
@@ -183,3 +187,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
        list_del(&wait_entry->list);
        spin_unlock_bh(&notif_wait->notif_wait_lock);
 }
+EXPORT_SYMBOL_GPL(iwl_remove_notification);
index 4ef742b28e0839ebe787c0aeee40f43152b825f5..64886f95664f996b370f621c97c14998b0c27171 100644 (file)
@@ -111,22 +111,25 @@ struct iwl_cfg;
  *     May sleep
  * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
  *     HCMD the this Rx responds to.
- *     Must be atomic.
+ *     Must be atomic and called with BH disabled.
  * @queue_full: notifies that a HW queue is full.
- *     Must be atomic
+ *     Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
- *     Must be atomic
+ *     Must be atomic and called with BH disabled.
  * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that
  *     the radio is killed. Must be atomic.
  * @free_skb: allows the transport layer to free skbs that haven't been
  *     reclaimed by the op_mode. This can happen when the driver is freed and
  *     there are Tx packets pending in the transport layer.
  *     Must be atomic
- * @nic_error: error notification. Must be atomic
- * @cmd_queue_full: Called when the command queue gets full. Must be atomic.
+ * @nic_error: error notification. Must be atomic and must be called with BH
+ *     disabled.
+ * @cmd_queue_full: Called when the command queue gets full. Must be atomic and
+ *     called with BH disabled.
  * @nic_config: configure NIC, called before firmware is started.
  *     May sleep
- * @wimax_active: invoked when WiMax becomes active.  Must be atomic.
+ * @wimax_active: invoked when WiMax becomes active.  Must be atomic and called
+ *     with BH disabled.
  */
 struct iwl_op_mode_ops {
        struct iwl_op_mode *(*start)(struct iwl_trans *trans,
@@ -145,6 +148,9 @@ struct iwl_op_mode_ops {
        void (*wimax_active)(struct iwl_op_mode *op_mode);
 };
 
+int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
+void iwl_opmode_deregister(const char *name);
+
 /**
  * struct iwl_op_mode - operational mode
  *
@@ -162,7 +168,6 @@ struct iwl_op_mode {
 static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
 {
        might_sleep();
-
        op_mode->ops->stop(op_mode);
 }
 
@@ -218,9 +223,4 @@ static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode)
        op_mode->ops->wimax_active(op_mode);
 }
 
-/*****************************************************
-* Op mode layers implementations
-******************************************************/
-extern const struct iwl_op_mode_ops iwl_dvm_ops;
-
 #endif /* __iwl_op_mode_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
deleted file mode 100644 (file)
index 0c8a1c2..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
-
-#include "iwl-trans.h"
-#include "iwl-cfg.h"
-#include "iwl-drv.h"
-#include "iwl-trans.h"
-#include "iwl-trans-pcie-int.h"
-
-#define IWL_PCI_DEVICE(dev, subdev, cfg) \
-       .vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
-       .subvendor = PCI_ANY_ID, .subdevice = (subdev), \
-       .driver_data = (kernel_ulong_t)&(cfg)
-
-/* Hardware specific file defines the PCI IDs table for that hardware module */
-static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
-       {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
-
-/* 5300 Series WiFi */
-       {IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
-
-/* 5350 Series WiFi/WiMax */
-       {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
-
-/* 5150 Series Wifi/WiMax */
-       {IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
-
-       {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
-       {IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
-       {IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
-
-/* 6x00 Series */
-       {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)},
-
-/* 6x05 Series */
-       {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
-       {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
-       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
-       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
-
-/* 6x30 Series */
-       {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
-       {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
-       {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
-
-/* 6x50 WiFi/WiMax Series */
-       {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(0x0089, 0x1311, iwl6050_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
-
-/* 6150 WiFi/WiMax Series */
-       {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
-
-/* 1000 Series WiFi */
-       {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)},
-
-/* 100 Series WiFi */
-       {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
-       {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
-       {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
-
-/* 130 Series WiFi */
-       {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
-
-/* 2x00 Series */
-       {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
-
-/* 2x30 Series */
-       {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
-
-/* 6x35 Series */
-       {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
-
-/* 105 Series */
-       {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
-
-/* 135 Series */
-       {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
-
-       {0}
-};
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT  0x041
-
-#ifndef CONFIG_IWLWIFI_IDI
-
-static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
-       struct iwl_trans *iwl_trans;
-       struct iwl_trans_pcie *trans_pcie;
-
-       iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
-       if (iwl_trans == NULL)
-               return -ENOMEM;
-
-       pci_set_drvdata(pdev, iwl_trans);
-
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
-       trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
-       if (!trans_pcie->drv)
-               goto out_free_trans;
-
-       return 0;
-
-out_free_trans:
-       iwl_trans_pcie_free(iwl_trans);
-       pci_set_drvdata(pdev, NULL);
-       return -EFAULT;
-}
-
-static void __devexit iwl_pci_remove(struct pci_dev *pdev)
-{
-       struct iwl_trans *trans = pci_get_drvdata(pdev);
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_drv_stop(trans_pcie->drv);
-       iwl_trans_pcie_free(trans);
-
-       pci_set_drvdata(pdev, NULL);
-}
-
-#endif /* CONFIG_IWLWIFI_IDI */
-
-#ifdef CONFIG_PM_SLEEP
-
-static int iwl_pci_suspend(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
-
-       /* Before you put code here, think about WoWLAN. You cannot check here
-        * whether WoWLAN is enabled or not, and your code will run even if
-        * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
-        */
-
-       return iwl_trans_suspend(iwl_trans);
-}
-
-static int iwl_pci_resume(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
-
-       /* Before you put code here, think about WoWLAN. You cannot check here
-        * whether WoWLAN is enabled or not, and your code will run even if
-        * WoWLAN is enabled - the NIC may be alive.
-        */
-
-       /*
-        * We disable the RETRY_TIMEOUT register (0x41) to keep
-        * PCI Tx retries from interfering with C3 CPU state.
-        */
-       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
-
-       return iwl_trans_resume(iwl_trans);
-}
-
-static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
-
-#define IWL_PM_OPS     (&iwl_dev_pm_ops)
-
-#else
-
-#define IWL_PM_OPS     NULL
-
-#endif
-
-#ifdef CONFIG_IWLWIFI_IDI
-/*
- * Defined externally in iwl-idi.c
- */
-int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-void __devexit iwl_pci_remove(struct pci_dev *pdev);
-
-#endif /* CONFIG_IWLWIFI_IDI */
-
-static struct pci_driver iwl_pci_driver = {
-       .name = DRV_NAME,
-       .id_table = iwl_hw_card_ids,
-       .probe = iwl_pci_probe,
-       .remove = __devexit_p(iwl_pci_remove),
-       .driver.pm = IWL_PM_OPS,
-};
-
-int __must_check iwl_pci_register_driver(void)
-{
-       int ret;
-       ret = pci_register_driver(&iwl_pci_driver);
-       if (ret)
-               pr_err("Unable to initialize PCI module\n");
-
-       return ret;
-}
-
-void iwl_pci_unregister_driver(void)
-{
-       pci_unregister_driver(&iwl_pci_driver);
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
deleted file mode 100644 (file)
index 544ddf1..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-#include "iwl-commands.h"
-#include "iwl-debug.h"
-#include "iwl-power.h"
-#include "iwl-trans.h"
-#include "iwl-modparams.h"
-
-/*
- * Setting power level allows the card to go to sleep when not busy.
- *
- * We calculate a sleep command based on the required latency, which
- * we get from mac80211. In order to handle thermal throttling, we can
- * also use pre-defined power levels.
- */
-
-/*
- * This defines the old power levels. They are still used by default
- * (level 1) and for thermal throttle (levels 3 through 5)
- */
-
-struct iwl_power_vec_entry {
-       struct iwl_powertable_cmd cmd;
-       u8 no_dtim;     /* number of skip dtim */
-};
-
-#define IWL_DTIM_RANGE_0_MAX   2
-#define IWL_DTIM_RANGE_1_MAX   10
-
-#define NOSLP cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define ASLP (IWL_POWER_POWER_SAVE_ENA_MSK |   \
-               IWL_POWER_POWER_MANAGEMENT_ENA_MSK | \
-               IWL_POWER_ADVANCE_PM_ENA_MSK)
-#define ASLP_TOUT(T) cpu_to_le32(T)
-#define TU_TO_USEC 1024
-#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
-                                    cpu_to_le32(X1), \
-                                    cpu_to_le32(X2), \
-                                    cpu_to_le32(X3), \
-                                    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, 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},
-       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
-};
-
-
-/* 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, 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},
-       {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
-       {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
-       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
-};
-
-/* advance power management */
-/* DTIM 0 - 2 */
-static const struct iwl_power_vec_entry apm_range_0[IWL_POWER_NUM] = {
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
-};
-
-
-/* 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 apm_range_1[IWL_POWER_NUM] = {
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 6, 8, 0xFF), 0}, 2}
-};
-
-/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
-/* DTIM 11 - */
-static const struct iwl_power_vec_entry apm_range_2[IWL_POWER_NUM] = {
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 4, 6, 0xFF), 0}, 0},
-       {{ASLP, 0, 0, ASLP_TOUT(50), ASLP_TOUT(50),
-               SLP_VEC(1, 2, 6, 8, 0xFF), ASLP_TOUT(2)}, 2}
-};
-
-static void iwl_static_sleep_cmd(struct iwl_priv *priv,
-                                struct iwl_powertable_cmd *cmd,
-                                enum iwl_power_level lvl, int period)
-{
-       const struct iwl_power_vec_entry *table;
-       int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
-       int i;
-       u8 skip;
-       u32 slp_itrvl;
-
-       if (priv->cfg->adv_pm) {
-               table = apm_range_2;
-               if (period <= IWL_DTIM_RANGE_1_MAX)
-                       table = apm_range_1;
-               if (period <= IWL_DTIM_RANGE_0_MAX)
-                       table = apm_range_0;
-       } else {
-               table = range_2;
-               if (period <= IWL_DTIM_RANGE_1_MAX)
-                       table = range_1;
-               if (period <= IWL_DTIM_RANGE_0_MAX)
-                       table = range_0;
-       }
-
-       if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
-               memset(cmd, 0, sizeof(*cmd));
-       else
-               *cmd = table[lvl].cmd;
-
-       if (period == 0) {
-               skip = 0;
-               period = 1;
-               for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
-                       max_sleep[i] =  1;
-
-       } else {
-               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;
-       }
-
-       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
-               cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
-
-       if (priv->cfg->base_params->shadow_reg_enable)
-               cmd->flags |= IWL_POWER_SHADOW_REG_ENA;
-       else
-               cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA;
-
-       if (iwl_advanced_bt_coexist(priv)) {
-               if (!priv->cfg->bt_params->bt_sco_disable)
-                       cmd->flags |= IWL_POWER_BT_SCO_ENA;
-               else
-                       cmd->flags &= ~IWL_POWER_BT_SCO_ENA;
-       }
-
-
-       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.bus_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);
-       /* The power level here is 0-4 (used as array index), but user expects
-       to see 1-5 (according to spec). */
-       IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
-}
-
-static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
-                                   struct iwl_powertable_cmd *cmd)
-{
-       memset(cmd, 0, sizeof(*cmd));
-
-       if (priv->power_data.bus_pm)
-               cmd->flags |= IWL_POWER_PCI_PM_MSK;
-
-       IWL_DEBUG_POWER(priv, "Sleep command for CAM\n");
-}
-
-static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
-{
-       IWL_DEBUG_POWER(priv, "Sending power/sleep command\n");
-       IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags);
-       IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
-       IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
-       IWL_DEBUG_POWER(priv, "Sleep interval vector = { %d , %d , %d , %d , %d }\n",
-                       le32_to_cpu(cmd->sleep_interval[0]),
-                       le32_to_cpu(cmd->sleep_interval[1]),
-                       le32_to_cpu(cmd->sleep_interval[2]),
-                       le32_to_cpu(cmd->sleep_interval[3]),
-                       le32_to_cpu(cmd->sleep_interval[4]));
-
-       return iwl_dvm_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
-                               sizeof(struct iwl_powertable_cmd), cmd);
-}
-
-static void iwl_power_build_cmd(struct iwl_priv *priv,
-                               struct iwl_powertable_cmd *cmd)
-{
-       bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
-       int dtimper;
-
-       dtimper = priv->hw->conf.ps_dtim_period ?: 1;
-
-       if (priv->wowlan)
-               iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper);
-       else if (!priv->cfg->base_params->no_idle_support &&
-                priv->hw->conf.flags & IEEE80211_CONF_IDLE)
-               iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
-       else if (iwl_tt_is_low_power_state(priv)) {
-               /* in thermal throttling low power state */
-               iwl_static_sleep_cmd(priv, cmd,
-                   iwl_tt_current_power_mode(priv), dtimper);
-       } else if (!enabled)
-               iwl_power_sleep_cam_cmd(priv, cmd);
-       else if (priv->power_data.debug_sleep_level_override >= 0)
-               iwl_static_sleep_cmd(priv, cmd,
-                                    priv->power_data.debug_sleep_level_override,
-                                    dtimper);
-       else {
-               /* Note that the user parameter is 1-5 (according to spec),
-               but we pass 0-4 because it acts as an array index. */
-               if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
-                   iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
-                       iwl_static_sleep_cmd(priv, cmd,
-                               iwlwifi_mod_params.power_level - 1, dtimper);
-               else
-                       iwl_static_sleep_cmd(priv, cmd,
-                               IWL_POWER_INDEX_1, dtimper);
-       }
-}
-
-int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
-                      bool force)
-{
-       int ret;
-       bool update_chains;
-
-       lockdep_assert_held(&priv->mutex);
-
-       /* Don't update the RX chain when chain noise calibration is running */
-       update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
-                       priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
-
-       if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force)
-               return 0;
-
-       if (!iwl_is_ready_rf(priv))
-               return -EIO;
-
-       /* scan complete use sleep_power_next, need to be updated */
-       memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd));
-       if (test_bit(STATUS_SCANNING, &priv->status) && !force) {
-               IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n");
-               return 0;
-       }
-
-       if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)
-               iwl_dvm_set_pmi(priv, true);
-
-       ret = iwl_set_power(priv, cmd);
-       if (!ret) {
-               if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
-                       iwl_dvm_set_pmi(priv, false);
-
-               if (update_chains)
-                       iwl_update_chain_flags(priv);
-               else
-                       IWL_DEBUG_POWER(priv,
-                                       "Cannot update the power, chain noise "
-                                       "calibration running: %d\n",
-                                       priv->chain_noise_data.state);
-
-               memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd));
-       } else
-               IWL_ERR(priv, "set power fail, ret = %d", ret);
-
-       return ret;
-}
-
-int iwl_power_update_mode(struct iwl_priv *priv, bool force)
-{
-       struct iwl_powertable_cmd cmd;
-
-       iwl_power_build_cmd(priv, &cmd);
-       return iwl_power_set_mode(priv, &cmd, force);
-}
-
-/* initialize to default */
-void iwl_power_initialize(struct iwl_priv *priv)
-{
-       priv->power_data.bus_pm = priv->trans->pm_support;
-
-       priv->power_data.debug_sleep_level_override = -1;
-
-       memset(&priv->power_data.sleep_cmd, 0,
-               sizeof(priv->power_data.sleep_cmd));
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
deleted file mode 100644 (file)
index 21afc92..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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_power_setting_h__
-#define __iwl_power_setting_h__
-
-#include "iwl-commands.h"
-
-struct iwl_power_mgr {
-       struct iwl_powertable_cmd sleep_cmd;
-       struct iwl_powertable_cmd sleep_cmd_next;
-       int debug_sleep_level_override;
-       bool bus_pm;
-};
-
-int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
-                      bool force);
-int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-void iwl_power_initialize(struct iwl_priv *priv);
-
-extern bool no_sleep_autoadjust;
-
-#endif  /* __iwl_power_setting_h__ */
index dfd54662e3e675bc2c560894cd47d002cbf5ff76..9253ef1dba72d005f407b34c1bfb2665fb9b4be6 100644 (file)
 #define SCD_QUEUE_STTS_REG_POS_ACTIVE  (3)
 #define SCD_QUEUE_STTS_REG_POS_WSL     (4)
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
-#define SCD_QUEUE_STTS_REG_MSK         (0x00FF0000)
+#define SCD_QUEUE_STTS_REG_MSK         (0x017F0000)
 
 #define SCD_QUEUE_CTX_REG1_CREDIT_POS          (8)
 #define SCD_QUEUE_CTX_REG1_CREDIT_MSK          (0x00FFFF00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
deleted file mode 100644 (file)
index 031d8e2..0000000
+++ /dev/null
@@ -1,1160 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-trans.h"
-
-/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
- * sending probe req.  This should be set long enough to hear probe responses
- * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (20)
-
-#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
-#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
-
-/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
- * Must be set longer than active dwell time.
- * For the most reliable scan, set > AP beacon interval (typically 100msec). */
-#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
-#define IWL_PASSIVE_DWELL_TIME_52   (10)
-#define IWL_PASSIVE_DWELL_BASE      (100)
-#define IWL_CHANNEL_TUNE_TIME       5
-#define MAX_SCAN_CHANNEL           50
-
-static int iwl_send_scan_abort(struct iwl_priv *priv)
-{
-       int ret;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SCAN_ABORT_CMD,
-               .flags = CMD_SYNC | CMD_WANT_SKB,
-       };
-       __le32 *status;
-
-       /* Exit instantly with error when device is not ready
-        * to receive scan abort command or it does not perform
-        * hardware scan currently */
-       if (!test_bit(STATUS_READY, &priv->status) ||
-           !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
-           !test_bit(STATUS_SCAN_HW, &priv->status) ||
-           test_bit(STATUS_FW_ERROR, &priv->status))
-               return -EIO;
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-       if (ret)
-               return ret;
-
-       status = (void *)cmd.resp_pkt->data;
-       if (*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_SCAN(priv, "SCAN_ABORT ret %d.\n",
-                              le32_to_cpu(*status));
-               ret = -EIO;
-       }
-
-       iwl_free_resp(&cmd);
-       return ret;
-}
-
-static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
-{
-       /* check if scan was requested from mac80211 */
-       if (priv->scan_request) {
-               IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
-               ieee80211_scan_completed(priv->hw, aborted);
-       }
-
-       if (priv->scan_type == IWL_SCAN_ROC) {
-               ieee80211_remain_on_channel_expired(priv->hw);
-               priv->hw_roc_channel = NULL;
-               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-       }
-
-       priv->scan_type = IWL_SCAN_NORMAL;
-       priv->scan_vif = NULL;
-       priv->scan_request = NULL;
-}
-
-static void iwl_process_scan_complete(struct iwl_priv *priv)
-{
-       bool aborted;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status))
-               return;
-
-       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
-
-       cancel_delayed_work(&priv->scan_check);
-
-       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-       if (aborted)
-               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
-
-       if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
-               goto out_settings;
-       }
-
-       if (priv->scan_type == IWL_SCAN_ROC) {
-               ieee80211_remain_on_channel_expired(priv->hw);
-               priv->hw_roc_channel = NULL;
-               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-       }
-
-       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
-               int err;
-
-               /* Check if mac80211 requested scan during our internal scan */
-               if (priv->scan_request == NULL)
-                       goto out_complete;
-
-               /* If so request a new scan */
-               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
-                                       priv->scan_request->channels[0]->band);
-               if (err) {
-                       IWL_DEBUG_SCAN(priv,
-                               "failed to initiate pending scan: %d\n", err);
-                       aborted = true;
-                       goto out_complete;
-               }
-
-               return;
-       }
-
-out_complete:
-       iwl_complete_scan(priv, aborted);
-
-out_settings:
-       /* Can we still talk to firmware ? */
-       if (!iwl_is_ready_rf(priv))
-               return;
-
-       iwlagn_post_scan(priv);
-}
-
-void iwl_force_scan_end(struct iwl_priv *priv)
-{
-       lockdep_assert_held(&priv->mutex);
-
-       if (!test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n");
-               return;
-       }
-
-       IWL_DEBUG_SCAN(priv, "Forcing scan end\n");
-       clear_bit(STATUS_SCANNING, &priv->status);
-       clear_bit(STATUS_SCAN_HW, &priv->status);
-       clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-       clear_bit(STATUS_SCAN_COMPLETE, &priv->status);
-       iwl_complete_scan(priv, true);
-}
-
-static void iwl_do_scan_abort(struct iwl_priv *priv)
-{
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (!test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
-               return;
-       }
-
-       if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
-               return;
-       }
-
-       ret = iwl_send_scan_abort(priv);
-       if (ret) {
-               IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
-               iwl_force_scan_end(priv);
-       } else
-               IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n");
-}
-
-/**
- * iwl_scan_cancel - Cancel any currently executing HW scan
- */
-int iwl_scan_cancel(struct iwl_priv *priv)
-{
-       IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
-       queue_work(priv->workqueue, &priv->abort_scan);
-       return 0;
-}
-
-/**
- * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
- * @ms: amount of time to wait (in milliseconds) for scan to abort
- *
- */
-void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(ms);
-
-       lockdep_assert_held(&priv->mutex);
-
-       IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
-
-       iwl_do_scan_abort(priv);
-
-       while (time_before_eq(jiffies, timeout)) {
-               if (!test_bit(STATUS_SCAN_HW, &priv->status))
-                       goto finished;
-               msleep(20);
-       }
-
-       return;
-
- finished:
-       /*
-        * Now STATUS_SCAN_HW is clear. This means that the
-        * device finished, but the background work is going
-        * to execute at best as soon as we release the mutex.
-        * Since we need to be able to issue a new scan right
-        * after this function returns, run the complete here.
-        * The STATUS_SCAN_COMPLETE bit will then be cleared
-        * and prevent the background work from "completing"
-        * a possible new scan.
-        */
-       iwl_process_scan_complete(priv);
-}
-
-/* Service response to REPLY_SCAN_CMD (0x80) */
-static int iwl_rx_reply_scan(struct iwl_priv *priv,
-                             struct iwl_rx_cmd_buffer *rxb,
-                             struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanreq_notification *notif = (void *)pkt->data;
-
-       IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
-#endif
-       return 0;
-}
-
-/* Service SCAN_START_NOTIFICATION (0x82) */
-static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_cmd_buffer *rxb,
-                                   struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanstart_notification *notif = (void *)pkt->data;
-
-       priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
-       IWL_DEBUG_SCAN(priv, "Scan start: "
-                      "%d [802.11%s] "
-                      "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
-                      notif->channel,
-                      notif->band ? "bg" : "a",
-                      le32_to_cpu(notif->tsf_high),
-                      le32_to_cpu(notif->tsf_low),
-                      notif->status, notif->beacon_timer);
-
-       if (priv->scan_type == IWL_SCAN_ROC &&
-           !priv->hw_roc_start_notified) {
-               ieee80211_ready_on_channel(priv->hw);
-               priv->hw_roc_start_notified = true;
-       }
-
-       return 0;
-}
-
-/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_cmd_buffer *rxb,
-                                     struct iwl_device_cmd *cmd)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scanresults_notification *notif = (void *)pkt->data;
-
-       IWL_DEBUG_SCAN(priv, "Scan ch.res: "
-                      "%d [802.11%s] "
-                      "probe status: %u:%u "
-                      "(TSF: 0x%08X:%08X) - %d "
-                      "elapsed=%lu usec\n",
-                      notif->channel,
-                      notif->band ? "bg" : "a",
-                      notif->probe_status, notif->num_probe_not_sent,
-                      le32_to_cpu(notif->tsf_high),
-                      le32_to_cpu(notif->tsf_low),
-                      le32_to_cpu(notif->statistics[0]),
-                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
-#endif
-       return 0;
-}
-
-/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_cmd_buffer *rxb,
-                                      struct iwl_device_cmd *cmd)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data;
-
-       IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
-                      scan_notif->scanned_channels,
-                      scan_notif->tsf_low,
-                      scan_notif->tsf_high, scan_notif->status);
-
-       IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
-                      (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
-                      jiffies_to_msecs(jiffies - priv->scan_start));
-
-       /*
-        * When aborting, we run the scan completed background work inline
-        * and the background work must then do nothing. The SCAN_COMPLETE
-        * bit helps implement that logic and thus needs to be set before
-        * queueing the work. Also, since the scan abort waits for SCAN_HW
-        * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
-        * to avoid a race there.
-        */
-       set_bit(STATUS_SCAN_COMPLETE, &priv->status);
-       clear_bit(STATUS_SCAN_HW, &priv->status);
-       queue_work(priv->workqueue, &priv->scan_completed);
-
-       if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
-           iwl_advanced_bt_coexist(priv) &&
-           priv->bt_status != scan_notif->bt_status) {
-               if (scan_notif->bt_status) {
-                       /* BT on */
-                       if (!priv->bt_ch_announce)
-                               priv->bt_traffic_load =
-                                       IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-                       /*
-                        * otherwise, no traffic load information provided
-                        * no changes made
-                        */
-               } else {
-                       /* BT off */
-                       priv->bt_traffic_load =
-                               IWL_BT_COEX_TRAFFIC_LOAD_NONE;
-               }
-               priv->bt_status = scan_notif->bt_status;
-               queue_work(priv->workqueue,
-                          &priv->bt_traffic_change_work);
-       }
-       return 0;
-}
-
-void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
-{
-       /* scan handlers */
-       priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
-       priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
-       priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-                                       iwl_rx_scan_results_notif;
-       priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-                                       iwl_rx_scan_complete_notif;
-}
-
-static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-                                    enum ieee80211_band band, u8 n_probes)
-{
-       if (band == IEEE80211_BAND_5GHZ)
-               return IWL_ACTIVE_DWELL_TIME_52 +
-                       IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
-       else
-               return IWL_ACTIVE_DWELL_TIME_24 +
-                       IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
-}
-
-static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
-{
-       struct iwl_rxon_context *ctx;
-
-       /*
-        * If we're associated, we clamp the dwell time 98%
-        * of the smallest beacon interval (minus 2 * channel
-        * tune time)
-        */
-       for_each_context(priv, ctx) {
-               u16 value;
-
-               switch (ctx->staging.dev_type) {
-               case RXON_DEV_TYPE_P2P:
-                       /* no timing constraints */
-                       continue;
-               case RXON_DEV_TYPE_ESS:
-               default:
-                       /* timing constraints if associated */
-                       if (!iwl_is_associated_ctx(ctx))
-                               continue;
-                       break;
-               case RXON_DEV_TYPE_CP:
-               case RXON_DEV_TYPE_2STA:
-                       /*
-                        * These seem to always have timers for TBTT
-                        * active in uCode even when not associated yet.
-                        */
-                       break;
-               }
-
-               value = ctx->beacon_int;
-               if (!value)
-                       value = IWL_PASSIVE_DWELL_BASE;
-               value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
-               dwell_time = min(value, dwell_time);
-       }
-
-       return dwell_time;
-}
-
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                                     enum ieee80211_band band)
-{
-       u16 passive = (band == IEEE80211_BAND_2GHZ) ?
-           IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
-           IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
-
-       return iwl_limit_dwell(priv, passive);
-}
-
-/* Return valid, unused, channel for a passive scan to reset the RF */
-static u8 iwl_get_single_channel_number(struct iwl_priv *priv,
-                                enum ieee80211_band band)
-{
-       const struct iwl_channel_info *ch_info;
-       int i;
-       u8 channel = 0;
-       u8 min, max;
-       struct iwl_rxon_context *ctx;
-
-       if (band == IEEE80211_BAND_5GHZ) {
-               min = 14;
-               max = priv->channel_count;
-       } else {
-               min = 0;
-               max = 14;
-       }
-
-       for (i = min; i < max; i++) {
-               bool busy = false;
-
-               for_each_context(priv, ctx) {
-                       busy = priv->channel_info[i].channel ==
-                               le16_to_cpu(ctx->staging.channel);
-                       if (busy)
-                               break;
-               }
-
-               if (busy)
-                       continue;
-
-               channel = priv->channel_info[i].channel;
-               ch_info = iwl_get_channel_info(priv, band, channel);
-               if (is_channel_valid(ch_info))
-                       break;
-       }
-
-       return channel;
-}
-
-static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
-                                          struct ieee80211_vif *vif,
-                                          enum ieee80211_band band,
-                                          struct iwl_scan_channel *scan_ch)
-{
-       const struct ieee80211_supported_band *sband;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added = 0;
-       u16 channel = 0;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband) {
-               IWL_ERR(priv, "invalid band\n");
-               return added;
-       }
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       channel = iwl_get_single_channel_number(priv, band);
-       if (channel) {
-               scan_ch->channel = cpu_to_le16(channel);
-               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-               added++;
-       } else
-               IWL_ERR(priv, "no valid channel found\n");
-       return added;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
-                                    struct ieee80211_vif *vif,
-                                    enum ieee80211_band band,
-                                    u8 is_active, u8 n_probes,
-                                    struct iwl_scan_channel *scan_ch)
-{
-       struct ieee80211_channel *chan;
-       const struct ieee80211_supported_band *sband;
-       const struct iwl_channel_info *ch_info;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added, i;
-       u16 channel;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband)
-               return 0;
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
-               chan = priv->scan_request->channels[i];
-
-               if (chan->band != band)
-                       continue;
-
-               channel = chan->hw_value;
-               scan_ch->channel = cpu_to_le16(channel);
-
-               ch_info = iwl_get_channel_info(priv, band, channel);
-               if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN(priv,
-                                      "Channel %d is INVALID for this band.\n",
-                                      channel);
-                       continue;
-               }
-
-               if (!is_active || is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
-                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
-
-               if (n_probes)
-                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-
-               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                * power level:
-                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                */
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
-                              channel, le32_to_cpu(scan_ch->type),
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                               "ACTIVE" : "PASSIVE",
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                              active_dwell : passive_dwell);
-
-               scan_ch++;
-               added++;
-       }
-
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
-       return added;
-}
-
-/**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
- */
-
-static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
-                             const u8 *ies, int ie_len, const u8 *ssid,
-                             u8 ssid_len, int left)
-{
-       int len = 0;
-       u8 *pos = NULL;
-
-       /* Make sure there is enough space for the probe request,
-        * two mandatory IEs and the data */
-       left -= 24;
-       if (left < 0)
-               return 0;
-
-       frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-       memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-       memcpy(frame->sa, ta, ETH_ALEN);
-       memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
-       frame->seq_ctrl = 0;
-
-       len += 24;
-
-       /* ...next IE... */
-       pos = &frame->u.probe_req.variable[0];
-
-       /* fill in our SSID IE */
-       left -= ssid_len + 2;
-       if (left < 0)
-               return 0;
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = ssid_len;
-       if (ssid && ssid_len) {
-               memcpy(pos, ssid, ssid_len);
-               pos += ssid_len;
-       }
-
-       len += ssid_len + 2;
-
-       if (WARN_ON(left < ie_len))
-               return len;
-
-       if (ies && ie_len) {
-               memcpy(pos, ies, ie_len);
-               len += ie_len;
-       }
-
-       return (u16)len;
-}
-
-static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SCAN_CMD,
-               .len = { sizeof(struct iwl_scan_cmd), },
-               .flags = CMD_SYNC,
-       };
-       struct iwl_scan_cmd *scan;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u32 rate_flags = 0;
-       u16 cmd_len = 0;
-       u16 rx_chain = 0;
-       enum ieee80211_band band;
-       u8 n_probes = 0;
-       u8 rx_ant = priv->hw_params.valid_rx_ant;
-       u8 rate;
-       bool is_active = false;
-       int  chan_mod;
-       u8 active_chains;
-       u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
-       int ret;
-       int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
-                           MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
-                           priv->fw->ucode_capa.max_probe_length;
-       const u8 *ssid = NULL;
-       u8 ssid_len = 0;
-
-       if (WARN_ON_ONCE(priv->scan_request &&
-                        priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
-               return -EINVAL;
-
-       lockdep_assert_held(&priv->mutex);
-
-       if (vif)
-               ctx = iwl_rxon_ctx_from_vif(vif);
-
-       if (!priv->scan_cmd) {
-               priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
-               if (!priv->scan_cmd) {
-                       IWL_DEBUG_SCAN(priv,
-                                      "fail to allocate memory for scan\n");
-                       return -ENOMEM;
-               }
-       }
-       scan = priv->scan_cmd;
-       memset(scan, 0, scan_cmd_size);
-
-       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
-       if (priv->scan_type != IWL_SCAN_ROC &&
-           iwl_is_any_associated(priv)) {
-               u16 interval = 0;
-               u32 extra;
-               u32 suspend_time = 100;
-               u32 scan_suspend_time = 100;
-
-               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-               switch (priv->scan_type) {
-               case IWL_SCAN_ROC:
-                       WARN_ON(1);
-                       break;
-               case IWL_SCAN_RADIO_RESET:
-                       interval = 0;
-                       break;
-               case IWL_SCAN_NORMAL:
-                       interval = vif->bss_conf.beacon_int;
-                       break;
-               }
-
-               scan->suspend_time = 0;
-               scan->max_out_time = cpu_to_le32(200 * 1024);
-               if (!interval)
-                       interval = suspend_time;
-
-               extra = (suspend_time / interval) << 22;
-               scan_suspend_time = (extra |
-                   ((suspend_time % interval) * 1024));
-               scan->suspend_time = cpu_to_le32(scan_suspend_time);
-               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
-                              scan_suspend_time, interval);
-       } else if (priv->scan_type == IWL_SCAN_ROC) {
-               scan->suspend_time = 0;
-               scan->max_out_time = 0;
-               scan->quiet_time = 0;
-               scan->quiet_plcp_th = 0;
-       }
-
-       switch (priv->scan_type) {
-       case IWL_SCAN_RADIO_RESET:
-               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
-               break;
-       case IWL_SCAN_NORMAL:
-               if (priv->scan_request->n_ssids) {
-                       int i, p = 0;
-                       IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
-                       /*
-                        * The highest priority SSID is inserted to the
-                        * probe request template.
-                        */
-                       ssid_len = priv->scan_request->ssids[0].ssid_len;
-                       ssid = priv->scan_request->ssids[0].ssid;
-
-                       /*
-                        * Invert the order of ssids, the firmware will invert
-                        * it back.
-                        */
-                       for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
-                               scan->direct_scan[p].id = WLAN_EID_SSID;
-                               scan->direct_scan[p].len =
-                                       priv->scan_request->ssids[i].ssid_len;
-                               memcpy(scan->direct_scan[p].ssid,
-                                      priv->scan_request->ssids[i].ssid,
-                                      priv->scan_request->ssids[i].ssid_len);
-                               n_probes++;
-                               p++;
-                       }
-                       is_active = true;
-               } else
-                       IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
-               break;
-       case IWL_SCAN_ROC:
-               IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
-               break;
-       }
-
-       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
-       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-       switch (priv->scan_band) {
-       case IEEE80211_BAND_2GHZ:
-               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               chan_mod = le32_to_cpu(
-                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
-                                               RXON_FLG_CHANNEL_MODE_MSK)
-                                      >> RXON_FLG_CHANNEL_MODE_POS;
-               if ((priv->scan_request && priv->scan_request->no_cck) ||
-                   chan_mod == CHANNEL_MODE_PURE_40) {
-                       rate = IWL_RATE_6M_PLCP;
-               } else {
-                       rate = IWL_RATE_1M_PLCP;
-                       rate_flags = RATE_MCS_CCK_MSK;
-               }
-               /*
-                * Internal scans are passive, so we can indiscriminately set
-                * the BT ignore flag on 2.4 GHz since it applies to TX only.
-                */
-               if (priv->cfg->bt_params &&
-                   priv->cfg->bt_params->advanced_bt_coexist)
-                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
-               break;
-       case IEEE80211_BAND_5GHZ:
-               rate = IWL_RATE_6M_PLCP;
-               break;
-       default:
-               IWL_WARN(priv, "Invalid scan band\n");
-               return -EIO;
-       }
-
-       /*
-        * If active scanning is requested but a certain channel is
-        * marked passive, we can do active scanning if we detect
-        * transmissions.
-        *
-        * There is an issue with some firmware versions that triggers
-        * a sysassert on a "good CRC threshold" of zero (== disabled),
-        * on a radar channel even though this means that we should NOT
-        * send probes.
-        *
-        * The "good CRC threshold" is the number of frames that we
-        * need to receive during our dwell time on a channel before
-        * sending out probes -- setting this to a huge value will
-        * mean we never reach it, but at the same time work around
-        * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
-        * here instead of IWL_GOOD_CRC_TH_DISABLED.
-        *
-        * This was fixed in later versions along with some other
-        * scan changes, and the threshold behaves as a flag in those
-        * versions.
-        */
-       if (priv->new_scan_threshold_behaviour)
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-                                               IWL_GOOD_CRC_TH_DISABLED;
-       else
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-                                               IWL_GOOD_CRC_TH_NEVER;
-
-       band = priv->scan_band;
-
-       if (band == IEEE80211_BAND_2GHZ &&
-           priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               /* transmit 2.4 GHz probes only on first antenna */
-               scan_tx_antennas = first_antenna(scan_tx_antennas);
-       }
-
-       priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv,
-                                                   priv->scan_tx_ant[band],
-                                                   scan_tx_antennas);
-       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
-       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
-
-       /*
-        * In power save mode while associated use one chain,
-        * otherwise use all chains
-        */
-       if (test_bit(STATUS_POWER_PMI, &priv->status) &&
-           !(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
-               /* rx_ant has been set to all valid chains previously */
-               active_chains = rx_ant &
-                               ((u8)(priv->chain_noise_data.active_chains));
-               if (!active_chains)
-                       active_chains = rx_ant;
-
-               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
-                               priv->chain_noise_data.active_chains);
-
-               rx_ant = first_antenna(active_chains);
-       }
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist &&
-           priv->bt_full_concurrent) {
-               /* operated as 1x1 in full concurrency mode */
-               rx_ant = first_antenna(rx_ant);
-       }
-
-       /* MIMO is not used here, but value is required */
-       rx_chain |=
-               priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
-       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
-       scan->rx_chain = cpu_to_le16(rx_chain);
-       switch (priv->scan_type) {
-       case IWL_SCAN_NORMAL:
-               cmd_len = iwl_fill_probe_req(
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       vif->addr,
-                                       priv->scan_request->ie,
-                                       priv->scan_request->ie_len,
-                                       ssid, ssid_len,
-                                       scan_cmd_size - sizeof(*scan));
-               break;
-       case IWL_SCAN_RADIO_RESET:
-       case IWL_SCAN_ROC:
-               /* use bcast addr, will not be transmitted but must be valid */
-               cmd_len = iwl_fill_probe_req(
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       iwl_bcast_addr, NULL, 0,
-                                       NULL, 0,
-                                       scan_cmd_size - sizeof(*scan));
-               break;
-       default:
-               BUG();
-       }
-       scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
-       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
-                              RXON_FILTER_BCON_AWARE_MSK);
-
-       switch (priv->scan_type) {
-       case IWL_SCAN_RADIO_RESET:
-               scan->channel_count =
-                       iwl_get_single_channel_for_scan(priv, vif, band,
-                               (void *)&scan->data[cmd_len]);
-               break;
-       case IWL_SCAN_NORMAL:
-               scan->channel_count =
-                       iwl_get_channels_for_scan(priv, vif, band,
-                               is_active, n_probes,
-                               (void *)&scan->data[cmd_len]);
-               break;
-       case IWL_SCAN_ROC: {
-               struct iwl_scan_channel *scan_ch;
-               int n_chan, i;
-               u16 dwell;
-
-               dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
-               n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
-
-               scan->channel_count = n_chan;
-
-               scan_ch = (void *)&scan->data[cmd_len];
-
-               for (i = 0; i < n_chan; i++) {
-                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-                       scan_ch->channel =
-                               cpu_to_le16(priv->hw_roc_channel->hw_value);
-
-                       if (i == n_chan - 1)
-                               dwell = priv->hw_roc_duration - i * dwell;
-
-                       scan_ch->active_dwell =
-                       scan_ch->passive_dwell = cpu_to_le16(dwell);
-
-                       /* Set txpower levels to defaults */
-                       scan_ch->dsp_atten = 110;
-
-                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                        * power level:
-                        * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                        */
-                       if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
-                               scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-                       else
-                               scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-                       scan_ch++;
-               }
-               }
-
-               break;
-       }
-
-       if (scan->channel_count == 0) {
-               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
-               return -EIO;
-       }
-
-       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
-           scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data[0] = scan;
-       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-       scan->len = cpu_to_le16(cmd.len[0]);
-
-       /* set scan bit here for PAN params */
-       set_bit(STATUS_SCAN_HW, &priv->status);
-
-       ret = iwlagn_set_pan_params(priv);
-       if (ret)
-               return ret;
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-       if (ret) {
-               clear_bit(STATUS_SCAN_HW, &priv->status);
-               iwlagn_set_pan_params(priv);
-       }
-
-       return ret;
-}
-
-void iwl_init_scan_params(struct iwl_priv *priv)
-{
-       u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
-       if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
-               priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
-       if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
-               priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
-}
-
-int __must_check iwl_scan_initiate(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif,
-                                  enum iwl_scan_type scan_type,
-                                  enum ieee80211_band band)
-{
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       cancel_delayed_work(&priv->scan_check);
-
-       if (!iwl_is_ready_rf(priv)) {
-               IWL_WARN(priv, "Request scan called when driver not ready.\n");
-               return -EIO;
-       }
-
-       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-               IWL_DEBUG_SCAN(priv,
-                       "Multiple concurrent scan requests in parallel.\n");
-               return -EBUSY;
-       }
-
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n");
-               return -EBUSY;
-       }
-
-       IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
-                       scan_type == IWL_SCAN_NORMAL ? "" :
-                       scan_type == IWL_SCAN_ROC ? "remain-on-channel " :
-                       "internal short ");
-
-       set_bit(STATUS_SCANNING, &priv->status);
-       priv->scan_type = scan_type;
-       priv->scan_start = jiffies;
-       priv->scan_band = band;
-
-       ret = iwlagn_request_scan(priv, vif);
-       if (ret) {
-               clear_bit(STATUS_SCANNING, &priv->status);
-               priv->scan_type = IWL_SCAN_NORMAL;
-               return ret;
-       }
-
-       queue_delayed_work(priv->workqueue, &priv->scan_check,
-                          IWL_SCAN_CHECK_WATCHDOG);
-
-       return 0;
-}
-
-
-/*
- * internal short scan, this function should only been called while associated.
- * It will reset and tune the radio to prevent possible RF related problem
- */
-void iwl_internal_short_hw_scan(struct iwl_priv *priv)
-{
-       queue_work(priv->workqueue, &priv->start_internal_scan);
-}
-
-static void iwl_bg_start_internal_scan(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, start_internal_scan);
-
-       IWL_DEBUG_SCAN(priv, "Start internal scan\n");
-
-       mutex_lock(&priv->mutex);
-
-       if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
-               IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
-               goto unlock;
-       }
-
-       if (test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-               goto unlock;
-       }
-
-       if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
-               IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
- unlock:
-       mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_scan_check(struct work_struct *data)
-{
-       struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, scan_check.work);
-
-       IWL_DEBUG_SCAN(priv, "Scan check work\n");
-
-       /* Since we are here firmware does not finish scan and
-        * most likely is in bad shape, so we don't bother to
-        * send abort command, just force scan complete to mac80211 */
-       mutex_lock(&priv->mutex);
-       iwl_force_scan_end(priv);
-       mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_abort_scan(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
-
-       IWL_DEBUG_SCAN(priv, "Abort scan work\n");
-
-       /* We keep scan_check work queued in case when firmware will not
-        * report back scan completed notification */
-       mutex_lock(&priv->mutex);
-       iwl_scan_cancel_timeout(priv, 200);
-       mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_scan_completed(struct work_struct *work)
-{
-       struct iwl_priv *priv =
-               container_of(work, struct iwl_priv, scan_completed);
-
-       mutex_lock(&priv->mutex);
-       iwl_process_scan_complete(priv);
-       mutex_unlock(&priv->mutex);
-}
-
-void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
-{
-       INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-       INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
-       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
-       INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
-}
-
-void iwl_cancel_scan_deferred_work(struct iwl_priv *priv)
-{
-       cancel_work_sync(&priv->start_internal_scan);
-       cancel_work_sync(&priv->abort_scan);
-       cancel_work_sync(&priv->scan_completed);
-
-       if (cancel_delayed_work_sync(&priv->scan_check)) {
-               mutex_lock(&priv->mutex);
-               iwl_force_scan_end(priv);
-               mutex_unlock(&priv->mutex);
-       }
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
new file mode 100644 (file)
index 0000000..81e8c71
--- /dev/null
@@ -0,0 +1,856 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <linux/export.h>
+#include <net/netlink.h>
+
+#include "iwl-io.h"
+#include "iwl-fh.h"
+#include "iwl-prph.h"
+#include "iwl-trans.h"
+#include "iwl-test.h"
+#include "iwl-csr.h"
+#include "iwl-testmode.h"
+
+/*
+ * Periphery registers absolute lower bound. This is used in order to
+ * differentiate registery access through HBUS_TARG_PRPH_* and
+ * HBUS_TARG_MEM_* accesses.
+ */
+#define IWL_ABS_PRPH_START (0xA00000)
+
+/*
+ * The TLVs used in the gnl message policy between the kernel module and
+ * user space application. iwl_testmode_gnl_msg_policy is to be carried
+ * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
+ * See iwl-testmode.h
+ */
+static
+struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
+       [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
+       [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
+       [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
+
+       [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
+       [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
+
+       [IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
+};
+
+static inline void iwl_test_trace_clear(struct iwl_test *tst)
+{
+       memset(&tst->trace, 0, sizeof(struct iwl_test_trace));
+}
+
+static void iwl_test_trace_stop(struct iwl_test *tst)
+{
+       if (!tst->trace.enabled)
+               return;
+
+       if (tst->trace.cpu_addr && tst->trace.dma_addr)
+               dma_free_coherent(tst->trans->dev,
+                                 tst->trace.tsize,
+                                 tst->trace.cpu_addr,
+                                 tst->trace.dma_addr);
+
+       iwl_test_trace_clear(tst);
+}
+
+static inline void iwl_test_mem_clear(struct iwl_test *tst)
+{
+       memset(&tst->mem, 0, sizeof(struct iwl_test_mem));
+}
+
+static inline void iwl_test_mem_stop(struct iwl_test *tst)
+{
+       if (!tst->mem.in_read)
+               return;
+
+       iwl_test_mem_clear(tst);
+}
+
+/*
+ * Initializes the test object
+ * During the lifetime of the test object it is assumed that the transport is
+ * started. The test object should be stopped before the transport is stopped.
+ */
+void iwl_test_init(struct iwl_test *tst, struct iwl_trans *trans,
+                  struct iwl_test_ops *ops)
+{
+       tst->trans = trans;
+       tst->ops = ops;
+
+       iwl_test_trace_clear(tst);
+       iwl_test_mem_clear(tst);
+}
+EXPORT_SYMBOL_GPL(iwl_test_init);
+
+/*
+ * Stop the test object
+ */
+void iwl_test_free(struct iwl_test *tst)
+{
+       iwl_test_mem_stop(tst);
+       iwl_test_trace_stop(tst);
+}
+EXPORT_SYMBOL_GPL(iwl_test_free);
+
+static inline int iwl_test_send_cmd(struct iwl_test *tst,
+                                   struct iwl_host_cmd *cmd)
+{
+       return tst->ops->send_cmd(tst->trans->op_mode, cmd);
+}
+
+static inline bool iwl_test_valid_hw_addr(struct iwl_test *tst, u32 addr)
+{
+       return tst->ops->valid_hw_addr(addr);
+}
+
+static inline u32 iwl_test_fw_ver(struct iwl_test *tst)
+{
+       return tst->ops->get_fw_ver(tst->trans->op_mode);
+}
+
+static inline struct sk_buff*
+iwl_test_alloc_reply(struct iwl_test *tst, int len)
+{
+       return tst->ops->alloc_reply(tst->trans->op_mode, len);
+}
+
+static inline int iwl_test_reply(struct iwl_test *tst, struct sk_buff *skb)
+{
+       return tst->ops->reply(tst->trans->op_mode, skb);
+}
+
+static inline struct sk_buff*
+iwl_test_alloc_event(struct iwl_test *tst, int len)
+{
+       return tst->ops->alloc_event(tst->trans->op_mode, len);
+}
+
+static inline void
+iwl_test_event(struct iwl_test *tst, struct sk_buff *skb)
+{
+       return tst->ops->event(tst->trans->op_mode, skb);
+}
+
+/*
+ * This function handles the user application commands to the fw. The fw
+ * commands are sent in a synchronuous manner. In case that the user requested
+ * to get commands response, it is send to the user.
+ */
+static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
+{
+       struct iwl_host_cmd cmd;
+       struct iwl_rx_packet *pkt;
+       struct sk_buff *skb;
+       void *reply_buf;
+       u32 reply_len;
+       int ret;
+       bool cmd_want_skb;
+
+       memset(&cmd, 0, sizeof(struct iwl_host_cmd));
+
+       if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
+           !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
+               IWL_ERR(tst->trans, "Missing fw command mandatory fields\n");
+               return -ENOMSG;
+       }
+
+       cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
+       cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
+       if (cmd_want_skb)
+               cmd.flags |= CMD_WANT_SKB;
+
+       cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
+       cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       IWL_DEBUG_INFO(tst->trans, "test fw cmd=0x%x, flags 0x%x, len %d\n",
+                      cmd.id, cmd.flags, cmd.len[0]);
+
+       ret = iwl_test_send_cmd(tst, &cmd);
+       if (ret) {
+               IWL_ERR(tst->trans, "Failed to send hcmd\n");
+               return ret;
+       }
+       if (!cmd_want_skb)
+               return ret;
+
+       /* Handling return of SKB to the user */
+       pkt = cmd.resp_pkt;
+       if (!pkt) {
+               IWL_ERR(tst->trans, "HCMD received a null response packet\n");
+               return ret;
+       }
+
+       reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       skb = iwl_test_alloc_reply(tst, reply_len + 20);
+       reply_buf = kmalloc(reply_len, GFP_KERNEL);
+       if (!skb || !reply_buf) {
+               kfree_skb(skb);
+               kfree(reply_buf);
+               return -ENOMEM;
+       }
+
+       /* The reply is in a page, that we cannot send to user space. */
+       memcpy(reply_buf, &(pkt->hdr), reply_len);
+       iwl_free_resp(&cmd);
+
+       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+                       IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
+           nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf))
+               goto nla_put_failure;
+       return iwl_test_reply(tst, skb);
+
+nla_put_failure:
+       IWL_DEBUG_INFO(tst->trans, "Failed creating NL attributes\n");
+       kfree(reply_buf);
+       kfree_skb(skb);
+       return -ENOMSG;
+}
+
+/*
+ * Handles the user application commands for register access.
+ */
+static int iwl_test_reg(struct iwl_test *tst, struct nlattr **tb)
+{
+       u32 ofs, val32, cmd;
+       u8 val8;
+       struct sk_buff *skb;
+       int status = 0;
+       struct iwl_trans *trans = tst->trans;
+
+       if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
+               IWL_ERR(trans, "Missing reg offset\n");
+               return -ENOMSG;
+       }
+
+       ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
+       IWL_DEBUG_INFO(trans, "test reg access cmd offset=0x%x\n", ofs);
+
+       cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+
+       /*
+        * Allow access only to FH/CSR/HBUS in direct mode.
+        * Since we don't have the upper bounds for the CSR and HBUS segments,
+        * we will use only the upper bound of FH for sanity check.
+        */
+       if (ofs >= FH_MEM_UPPER_BOUND) {
+               IWL_ERR(trans, "offset out of segment (0x0 - 0x%x)\n",
+                       FH_MEM_UPPER_BOUND);
+               return -EINVAL;
+       }
+
+       switch (cmd) {
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+               val32 = iwl_read_direct32(tst->trans, ofs);
+               IWL_DEBUG_INFO(trans, "32 value to read 0x%x\n", val32);
+
+               skb = iwl_test_alloc_reply(tst, 20);
+               if (!skb) {
+                       IWL_ERR(trans, "Memory allocation fail\n");
+                       return -ENOMEM;
+               }
+               if (nla_put_u32(skb, IWL_TM_ATTR_REG_VALUE32, val32))
+                       goto nla_put_failure;
+               status = iwl_test_reply(tst, skb);
+               if (status < 0)
+                       IWL_ERR(trans, "Error sending msg : %d\n", status);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+               if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
+                       IWL_ERR(trans, "Missing value to write\n");
+                       return -ENOMSG;
+               } else {
+                       val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
+                       IWL_DEBUG_INFO(trans, "32b write val=0x%x\n", val32);
+                       iwl_write_direct32(tst->trans, ofs, val32);
+               }
+               break;
+
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+               if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
+                       IWL_ERR(trans, "Missing value to write\n");
+                       return -ENOMSG;
+               } else {
+                       val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
+                       IWL_DEBUG_INFO(trans, "8b write val=0x%x\n", val8);
+                       iwl_write8(tst->trans, ofs, val8);
+               }
+               break;
+
+       default:
+               IWL_ERR(trans, "Unknown test register cmd ID\n");
+               return -ENOMSG;
+       }
+
+       return status;
+
+nla_put_failure:
+       kfree_skb(skb);
+       return -EMSGSIZE;
+}
+
+/*
+ * Handles the request to start FW tracing. Allocates of the trace buffer
+ * and sends a reply to user space with the address of the allocated buffer.
+ */
+static int iwl_test_trace_begin(struct iwl_test *tst, struct nlattr **tb)
+{
+       struct sk_buff *skb;
+       int status = 0;
+
+       if (tst->trace.enabled)
+               return -EBUSY;
+
+       if (!tb[IWL_TM_ATTR_TRACE_SIZE])
+               tst->trace.size = TRACE_BUFF_SIZE_DEF;
+       else
+               tst->trace.size =
+                       nla_get_u32(tb[IWL_TM_ATTR_TRACE_SIZE]);
+
+       if (!tst->trace.size)
+               return -EINVAL;
+
+       if (tst->trace.size < TRACE_BUFF_SIZE_MIN ||
+           tst->trace.size > TRACE_BUFF_SIZE_MAX)
+               return -EINVAL;
+
+       tst->trace.tsize = tst->trace.size + TRACE_BUFF_PADD;
+       tst->trace.cpu_addr = dma_alloc_coherent(tst->trans->dev,
+                                                tst->trace.tsize,
+                                                &tst->trace.dma_addr,
+                                                GFP_KERNEL);
+       if (!tst->trace.cpu_addr)
+               return -ENOMEM;
+
+       tst->trace.enabled = true;
+       tst->trace.trace_addr = (u8 *)PTR_ALIGN(tst->trace.cpu_addr, 0x100);
+
+       memset(tst->trace.trace_addr, 0x03B, tst->trace.size);
+
+       skb = iwl_test_alloc_reply(tst, sizeof(tst->trace.dma_addr) + 20);
+       if (!skb) {
+               IWL_ERR(tst->trans, "Memory allocation fail\n");
+               iwl_test_trace_stop(tst);
+               return -ENOMEM;
+       }
+
+       if (nla_put(skb, IWL_TM_ATTR_TRACE_ADDR,
+                   sizeof(tst->trace.dma_addr),
+                   (u64 *)&tst->trace.dma_addr))
+               goto nla_put_failure;
+
+       status = iwl_test_reply(tst, skb);
+       if (status < 0)
+               IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+       tst->trace.nchunks = DIV_ROUND_UP(tst->trace.size,
+                                         DUMP_CHUNK_SIZE);
+
+       return status;
+
+nla_put_failure:
+       kfree_skb(skb);
+       if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
+           IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
+               iwl_test_trace_stop(tst);
+       return -EMSGSIZE;
+}
+
+/*
+ * Handles indirect read from the periphery or the SRAM. The read is performed
+ * to a temporary buffer. The user space application should later issue a dump
+ */
+static int iwl_test_indirect_read(struct iwl_test *tst, u32 addr, u32 size)
+{
+       struct iwl_trans *trans = tst->trans;
+       unsigned long flags;
+       int i;
+
+       if (size & 0x3)
+               return -EINVAL;
+
+       tst->mem.size = size;
+       tst->mem.addr = kmalloc(tst->mem.size, GFP_KERNEL);
+       if (tst->mem.addr == NULL)
+               return -ENOMEM;
+
+       /* Hard-coded periphery absolute address */
+       if (IWL_ABS_PRPH_START <= addr &&
+           addr < IWL_ABS_PRPH_START + PRPH_END) {
+                       spin_lock_irqsave(&trans->reg_lock, flags);
+                       iwl_grab_nic_access(trans);
+                       iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
+                                   addr | (3 << 24));
+                       for (i = 0; i < size; i += 4)
+                               *(u32 *)(tst->mem.addr + i) =
+                                       iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
+                       iwl_release_nic_access(trans);
+                       spin_unlock_irqrestore(&trans->reg_lock, flags);
+       } else { /* target memory (SRAM) */
+               _iwl_read_targ_mem_dwords(trans, addr,
+                                         tst->mem.addr,
+                                         tst->mem.size / 4);
+       }
+
+       tst->mem.nchunks =
+               DIV_ROUND_UP(tst->mem.size, DUMP_CHUNK_SIZE);
+       tst->mem.in_read = true;
+       return 0;
+
+}
+
+/*
+ * Handles indirect write to the periphery or SRAM. The  is performed to a
+ * temporary buffer.
+ */
+static int iwl_test_indirect_write(struct iwl_test *tst, u32 addr,
+       u32 size, unsigned char *buf)
+{
+       struct iwl_trans *trans = tst->trans;
+       u32 val, i;
+       unsigned long flags;
+
+       if (IWL_ABS_PRPH_START <= addr &&
+           addr < IWL_ABS_PRPH_START + PRPH_END) {
+                       /* Periphery writes can be 1-3 bytes long, or DWORDs */
+                       if (size < 4) {
+                               memcpy(&val, buf, size);
+                               spin_lock_irqsave(&trans->reg_lock, flags);
+                               iwl_grab_nic_access(trans);
+                               iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
+                                           (addr & 0x0000FFFF) |
+                                           ((size - 1) << 24));
+                               iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
+                               iwl_release_nic_access(trans);
+                               /* needed after consecutive writes w/o read */
+                               mmiowb();
+                               spin_unlock_irqrestore(&trans->reg_lock, flags);
+                       } else {
+                               if (size % 4)
+                                       return -EINVAL;
+                               for (i = 0; i < size; i += 4)
+                                       iwl_write_prph(trans, addr+i,
+                                                      *(u32 *)(buf+i));
+                       }
+       } else if (iwl_test_valid_hw_addr(tst, addr)) {
+               _iwl_write_targ_mem_dwords(trans, addr, buf, size / 4);
+       } else {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Handles the user application commands for indirect read/write
+ * to/from the periphery or the SRAM.
+ */
+static int iwl_test_indirect_mem(struct iwl_test *tst, struct nlattr **tb)
+{
+       u32 addr, size, cmd;
+       unsigned char *buf;
+
+       /* Both read and write should be blocked, for atomicity */
+       if (tst->mem.in_read)
+               return -EBUSY;
+
+       cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
+       if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
+               IWL_ERR(tst->trans, "Error finding memory offset address\n");
+               return -ENOMSG;
+       }
+       addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
+       if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
+               IWL_ERR(tst->trans, "Error finding size for memory reading\n");
+               return -ENOMSG;
+       }
+       size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
+
+       if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ) {
+               return iwl_test_indirect_read(tst, addr,  size);
+       } else {
+               if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
+                       return -EINVAL;
+               buf = (unsigned char *)nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
+               return iwl_test_indirect_write(tst, addr, size, buf);
+       }
+}
+
+/*
+ * Enable notifications to user space
+ */
+static int iwl_test_notifications(struct iwl_test *tst,
+                                 struct nlattr **tb)
+{
+       tst->notify = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
+       return 0;
+}
+
+/*
+ * Handles the request to get the device id
+ */
+static int iwl_test_get_dev_id(struct iwl_test *tst, struct nlattr **tb)
+{
+       u32 devid = tst->trans->hw_id;
+       struct sk_buff *skb;
+       int status;
+
+       IWL_DEBUG_INFO(tst->trans, "hw version: 0x%x\n", devid);
+
+       skb = iwl_test_alloc_reply(tst, 20);
+       if (!skb) {
+               IWL_ERR(tst->trans, "Memory allocation fail\n");
+               return -ENOMEM;
+       }
+
+       if (nla_put_u32(skb, IWL_TM_ATTR_DEVICE_ID, devid))
+               goto nla_put_failure;
+       status = iwl_test_reply(tst, skb);
+       if (status < 0)
+               IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+       return 0;
+
+nla_put_failure:
+       kfree_skb(skb);
+       return -EMSGSIZE;
+}
+
+/*
+ * Handles the request to get the FW version
+ */
+static int iwl_test_get_fw_ver(struct iwl_test *tst, struct nlattr **tb)
+{
+       struct sk_buff *skb;
+       int status;
+       u32 ver = iwl_test_fw_ver(tst);
+
+       IWL_DEBUG_INFO(tst->trans, "uCode version raw: 0x%x\n", ver);
+
+       skb = iwl_test_alloc_reply(tst, 20);
+       if (!skb) {
+               IWL_ERR(tst->trans, "Memory allocation fail\n");
+               return -ENOMEM;
+       }
+
+       if (nla_put_u32(skb, IWL_TM_ATTR_FW_VERSION, ver))
+               goto nla_put_failure;
+
+       status = iwl_test_reply(tst, skb);
+       if (status < 0)
+               IWL_ERR(tst->trans, "Error sending msg : %d\n", status);
+
+       return 0;
+
+nla_put_failure:
+       kfree_skb(skb);
+       return -EMSGSIZE;
+}
+
+/*
+ * Parse the netlink message and validate that the IWL_TM_ATTR_CMD exists
+ */
+int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
+                  void *data, int len)
+{
+       int result;
+
+       result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
+                       iwl_testmode_gnl_msg_policy);
+       if (result) {
+               IWL_ERR(tst->trans, "Fail parse gnl msg: %d\n", result);
+               return result;
+       }
+
+       /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
+       if (!tb[IWL_TM_ATTR_COMMAND]) {
+               IWL_ERR(tst->trans, "Missing testmode command type\n");
+               return -ENOMSG;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iwl_test_parse);
+
+/*
+ * Handle test commands.
+ * Returns 1 for unknown commands (not handled by the test object); negative
+ * value in case of error.
+ */
+int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb)
+{
+       int result;
+
+       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+       case IWL_TM_CMD_APP2DEV_UCODE:
+               IWL_DEBUG_INFO(tst->trans, "test cmd to uCode\n");
+               result = iwl_test_fw_cmd(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
+       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
+               IWL_DEBUG_INFO(tst->trans, "test cmd to register\n");
+               result = iwl_test_reg(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+               IWL_DEBUG_INFO(tst->trans, "test uCode trace cmd to driver\n");
+               result = iwl_test_trace_begin(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+               iwl_test_trace_stop(tst);
+               result = 0;
+               break;
+
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
+               IWL_DEBUG_INFO(tst->trans, "test indirect memory cmd\n");
+               result = iwl_test_indirect_mem(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
+               IWL_DEBUG_INFO(tst->trans, "test notifications cmd\n");
+               result = iwl_test_notifications(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
+               IWL_DEBUG_INFO(tst->trans, "test get FW ver cmd\n");
+               result = iwl_test_get_fw_ver(tst, tb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
+               IWL_DEBUG_INFO(tst->trans, "test Get device ID cmd\n");
+               result = iwl_test_get_dev_id(tst, tb);
+               break;
+
+       default:
+               IWL_DEBUG_INFO(tst->trans, "Unknown test command\n");
+               result = 1;
+               break;
+       }
+       return result;
+}
+EXPORT_SYMBOL_GPL(iwl_test_handle_cmd);
+
+static int iwl_test_trace_dump(struct iwl_test *tst, struct sk_buff *skb,
+                              struct netlink_callback *cb)
+{
+       int idx, length;
+
+       if (!tst->trace.enabled || !tst->trace.trace_addr)
+               return -EFAULT;
+
+       idx = cb->args[4];
+       if (idx >= tst->trace.nchunks)
+               return -ENOENT;
+
+       length = DUMP_CHUNK_SIZE;
+       if (((idx + 1) == tst->trace.nchunks) &&
+           (tst->trace.size % DUMP_CHUNK_SIZE))
+               length = tst->trace.size %
+                       DUMP_CHUNK_SIZE;
+
+       if (nla_put(skb, IWL_TM_ATTR_TRACE_DUMP, length,
+                   tst->trace.trace_addr + (DUMP_CHUNK_SIZE * idx)))
+               goto nla_put_failure;
+
+       cb->args[4] = ++idx;
+       return 0;
+
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
+static int iwl_test_buffer_dump(struct iwl_test *tst, struct sk_buff *skb,
+                               struct netlink_callback *cb)
+{
+       int idx, length;
+
+       if (!tst->mem.in_read)
+               return -EFAULT;
+
+       idx = cb->args[4];
+       if (idx >= tst->mem.nchunks) {
+               iwl_test_mem_stop(tst);
+               return -ENOENT;
+       }
+
+       length = DUMP_CHUNK_SIZE;
+       if (((idx + 1) == tst->mem.nchunks) &&
+           (tst->mem.size % DUMP_CHUNK_SIZE))
+               length = tst->mem.size % DUMP_CHUNK_SIZE;
+
+       if (nla_put(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
+                   tst->mem.addr + (DUMP_CHUNK_SIZE * idx)))
+               goto nla_put_failure;
+
+       cb->args[4] = ++idx;
+       return 0;
+
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
+/*
+ * Handle dump commands.
+ * Returns 1 for unknown commands (not handled by the test object); negative
+ * value in case of error.
+ */
+int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
+                 struct netlink_callback *cb)
+{
+       int result;
+
+       switch (cmd) {
+       case IWL_TM_CMD_APP2DEV_READ_TRACE:
+               IWL_DEBUG_INFO(tst->trans, "uCode trace cmd\n");
+               result = iwl_test_trace_dump(tst, skb, cb);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
+               IWL_DEBUG_INFO(tst->trans, "testmode sram dump cmd\n");
+               result = iwl_test_buffer_dump(tst, skb, cb);
+               break;
+
+       default:
+               result = 1;
+               break;
+       }
+       return result;
+}
+EXPORT_SYMBOL_GPL(iwl_test_dump);
+
+/*
+ * Multicast a spontaneous messages from the device to the user space.
+ */
+static void iwl_test_send_rx(struct iwl_test *tst,
+                            struct iwl_rx_cmd_buffer *rxb)
+{
+       struct sk_buff *skb;
+       struct iwl_rx_packet *data;
+       int length;
+
+       data = rxb_addr(rxb);
+       length = le32_to_cpu(data->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+
+       /* the length doesn't include len_n_flags field, so add it manually */
+       length += sizeof(__le32);
+
+       skb = iwl_test_alloc_event(tst, length + 20);
+       if (skb == NULL) {
+               IWL_ERR(tst->trans, "Out of memory for message to user\n");
+               return;
+       }
+
+       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
+                       IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
+           nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data))
+               goto nla_put_failure;
+
+       iwl_test_event(tst, skb);
+       return;
+
+nla_put_failure:
+       kfree_skb(skb);
+       IWL_ERR(tst->trans, "Ouch, overran buffer, check allocation!\n");
+}
+
+/*
+ * Called whenever a Rx frames is recevied from the device. If notifications to
+ * the user space are requested, sends the frames to the user.
+ */
+void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb)
+{
+       if (tst->notify)
+               iwl_test_send_rx(tst, rxb);
+}
+EXPORT_SYMBOL_GPL(iwl_test_rx);
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h
new file mode 100644 (file)
index 0000000..e13ffa8
--- /dev/null
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __IWL_TEST_H__
+#define __IWL_TEST_H__
+
+#include <linux/types.h>
+#include "iwl-trans.h"
+
+struct iwl_test_trace {
+       u32 size;
+       u32 tsize;
+       u32 nchunks;
+       u8 *cpu_addr;
+       u8 *trace_addr;
+       dma_addr_t dma_addr;
+       bool enabled;
+};
+
+struct iwl_test_mem {
+       u32 size;
+       u32 nchunks;
+       u8 *addr;
+       bool in_read;
+};
+
+/*
+ * struct iwl_test_ops: callback to the op mode
+ *
+ * The structure defines the callbacks that the op_mode should handle,
+ * inorder to handle logic that is out of the scope of iwl_test. The
+ * op_mode must set all the callbacks.
+
+ * @send_cmd: handler that is used by the test object to request the
+ *  op_mode to send a command to the fw.
+ *
+ * @valid_hw_addr: handler that is used by the test object to request the
+ *  op_mode to check if the given address is a valid address.
+ *
+ * @get_fw_ver: handler used to get the FW version.
+ *
+ * @alloc_reply: handler used by the test object to request the op_mode
+ *  to allocate an skb for sending a reply to the user, and initialize
+ *  the skb. It is assumed that the test object only fills the required
+ *  attributes.
+ *
+ * @reply: handler used by the test object to request the op_mode to reply
+ *  to a request. The skb is an skb previously allocated by the the
+ *  alloc_reply callback.
+ I
+ * @alloc_event: handler used by the test object to request the op_mode
+ *  to allocate an skb for sending an event, and initialize
+ *  the skb. It is assumed that the test object only fills the required
+ *  attributes.
+ *
+ * @reply: handler used by the test object to request the op_mode to send
+ *  an event. The skb is an skb previously allocated by the the
+ *  alloc_event callback.
+ */
+struct iwl_test_ops {
+       int (*send_cmd)(struct iwl_op_mode *op_modes,
+                       struct iwl_host_cmd *cmd);
+       bool (*valid_hw_addr)(u32 addr);
+       u32 (*get_fw_ver)(struct iwl_op_mode *op_mode);
+
+       struct sk_buff *(*alloc_reply)(struct iwl_op_mode *op_mode, int len);
+       int (*reply)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+       struct sk_buff* (*alloc_event)(struct iwl_op_mode *op_mode, int len);
+       void (*event)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
+};
+
+struct iwl_test {
+       struct iwl_trans *trans;
+       struct iwl_test_ops *ops;
+       struct iwl_test_trace trace;
+       struct iwl_test_mem mem;
+       bool notify;
+};
+
+void iwl_test_init(struct iwl_test *tst, struct iwl_trans *trans,
+                  struct iwl_test_ops *ops);
+
+void iwl_test_free(struct iwl_test *tst);
+
+int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
+                  void *data, int len);
+
+int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb);
+
+int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
+                 struct netlink_callback *cb);
+
+void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb);
+
+static inline void iwl_test_enable_notifications(struct iwl_test *tst,
+                                                bool enable)
+{
+       tst->notify = enable;
+}
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
deleted file mode 100644 (file)
index 060aac3..0000000
+++ /dev/null
@@ -1,1114 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2010 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2010 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <net/net_namespace.h>
-#include <linux/netdevice.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#include <net/netlink.h>
-
-#include "iwl-dev.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-agn.h"
-#include "iwl-testmode.h"
-#include "iwl-trans.h"
-#include "iwl-fh.h"
-#include "iwl-prph.h"
-
-
-/* Periphery registers absolute lower bound. This is used in order to
- * differentiate registery access through HBUS_TARG_PRPH_* and
- * HBUS_TARG_MEM_* accesses.
- */
-#define IWL_TM_ABS_PRPH_START (0xA00000)
-
-/* The TLVs used in the gnl message policy between the kernel module and
- * user space application. iwl_testmode_gnl_msg_policy is to be carried
- * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
- * See iwl-testmode.h
- */
-static
-struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
-       [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
-
-       [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
-       [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
-
-       [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
-       [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
-
-       [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
-       [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
-
-       [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
-
-       [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
-       [IWL_TM_ATTR_TRACE_DUMP] = { .type = NLA_UNSPEC, },
-       [IWL_TM_ATTR_TRACE_SIZE] = { .type = NLA_U32, },
-
-       [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
-
-       [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
-
-       [IWL_TM_ATTR_MEM_ADDR] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_BUFFER_SIZE] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_BUFFER_DUMP] = { .type = NLA_UNSPEC, },
-
-       [IWL_TM_ATTR_FW_VERSION] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_DEVICE_ID] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_FW_TYPE] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_FW_INST_SIZE] = { .type = NLA_U32, },
-       [IWL_TM_ATTR_FW_DATA_SIZE] = { .type = NLA_U32, },
-
-       [IWL_TM_ATTR_ENABLE_NOTIFICATION] = {.type = NLA_FLAG, },
-};
-
-/*
- * See the struct iwl_rx_packet in iwl-commands.h for the format of the
- * received events from the device
- */
-static inline int get_event_length(struct iwl_rx_cmd_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       if (pkt)
-               return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       else
-               return 0;
-}
-
-
-/*
- * This function multicasts the spontaneous messages from the device to the
- * user space. It is invoked whenever there is a received messages
- * from the device. This function is called within the ISR of the rx handlers
- * in iwlagn driver.
- *
- * The parsing of the message content is left to the user space application,
- * The message content is treated as unattacked raw data and is encapsulated
- * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
- *
- * @priv: the instance of iwlwifi device
- * @rxb: pointer to rx data content received by the ISR
- *
- * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
- * For the messages multicasting to the user application, the mandatory
- * TLV fields are :
- *     IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
- *     IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
- */
-
-static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
-                                     struct iwl_rx_cmd_buffer *rxb)
-{
-       struct ieee80211_hw *hw = priv->hw;
-       struct sk_buff *skb;
-       void *data;
-       int length;
-
-       data = (void *)rxb_addr(rxb);
-       length = get_event_length(rxb);
-
-       if (!data || length == 0)
-               return;
-
-       skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
-                                                               GFP_ATOMIC);
-       if (skb == NULL) {
-               IWL_ERR(priv,
-                        "Run out of memory for messages to user space ?\n");
-               return;
-       }
-       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
-           /* the length doesn't include len_n_flags field, so add it manually */
-           nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, length + sizeof(__le32), data))
-               goto nla_put_failure;
-       cfg80211_testmode_event(skb, GFP_ATOMIC);
-       return;
-
-nla_put_failure:
-       kfree_skb(skb);
-       IWL_ERR(priv, "Ouch, overran buffer, check allocation!\n");
-}
-
-void iwl_testmode_init(struct iwl_priv *priv)
-{
-       priv->pre_rx_handler = NULL;
-       priv->testmode_trace.trace_enabled = false;
-       priv->testmode_mem.read_in_progress = false;
-}
-
-static void iwl_mem_cleanup(struct iwl_priv *priv)
-{
-       if (priv->testmode_mem.read_in_progress) {
-               kfree(priv->testmode_mem.buff_addr);
-               priv->testmode_mem.buff_addr = NULL;
-               priv->testmode_mem.buff_size = 0;
-               priv->testmode_mem.num_chunks = 0;
-               priv->testmode_mem.read_in_progress = false;
-       }
-}
-
-static void iwl_trace_cleanup(struct iwl_priv *priv)
-{
-       if (priv->testmode_trace.trace_enabled) {
-               if (priv->testmode_trace.cpu_addr &&
-                   priv->testmode_trace.dma_addr)
-                       dma_free_coherent(priv->trans->dev,
-                                       priv->testmode_trace.total_size,
-                                       priv->testmode_trace.cpu_addr,
-                                       priv->testmode_trace.dma_addr);
-               priv->testmode_trace.trace_enabled = false;
-               priv->testmode_trace.cpu_addr = NULL;
-               priv->testmode_trace.trace_addr = NULL;
-               priv->testmode_trace.dma_addr = 0;
-               priv->testmode_trace.buff_size = 0;
-               priv->testmode_trace.total_size = 0;
-       }
-}
-
-
-void iwl_testmode_cleanup(struct iwl_priv *priv)
-{
-       iwl_trace_cleanup(priv);
-       iwl_mem_cleanup(priv);
-}
-
-
-/*
- * This function handles the user application commands to the ucode.
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
- * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
- * host command to the ucode.
- *
- * If any mandatory field is missing, -ENOMSG is replied to the user space
- * application; otherwise, waits for the host command to be sent and checks
- * the return code. In case or error, it is returned, otherwise a reply is
- * allocated and the reply RX packet
- * is returned.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_host_cmd cmd;
-       struct iwl_rx_packet *pkt;
-       struct sk_buff *skb;
-       void *reply_buf;
-       u32 reply_len;
-       int ret;
-       bool cmd_want_skb;
-
-       memset(&cmd, 0, sizeof(struct iwl_host_cmd));
-
-       if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
-           !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
-               IWL_ERR(priv, "Missing ucode command mandatory fields\n");
-               return -ENOMSG;
-       }
-
-       cmd.flags = CMD_ON_DEMAND | CMD_SYNC;
-       cmd_want_skb = nla_get_flag(tb[IWL_TM_ATTR_UCODE_CMD_SKB]);
-       if (cmd_want_skb)
-               cmd.flags |= CMD_WANT_SKB;
-
-       cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
-       cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-       cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-       IWL_DEBUG_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
-                               " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
-
-       ret = iwl_dvm_send_cmd(priv, &cmd);
-       if (ret) {
-               IWL_ERR(priv, "Failed to send hcmd\n");
-               return ret;
-       }
-       if (!cmd_want_skb)
-               return ret;
-
-       /* Handling return of SKB to the user */
-       pkt = cmd.resp_pkt;
-       if (!pkt) {
-               IWL_ERR(priv, "HCMD received a null response packet\n");
-               return ret;
-       }
-
-       reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, reply_len + 20);
-       reply_buf = kmalloc(reply_len, GFP_KERNEL);
-       if (!skb || !reply_buf) {
-               kfree_skb(skb);
-               kfree(reply_buf);
-               return -ENOMEM;
-       }
-
-       /* The reply is in a page, that we cannot send to user space. */
-       memcpy(reply_buf, &(pkt->hdr), reply_len);
-       iwl_free_resp(&cmd);
-
-       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) ||
-           nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf))
-               goto nla_put_failure;
-       return cfg80211_testmode_reply(skb);
-
-nla_put_failure:
-       IWL_DEBUG_INFO(priv, "Failed creating NL attributes\n");
-       return -ENOMSG;
-}
-
-
-/*
- * This function handles the user application commands for register access.
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
- * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
- * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
- * the success of the command execution.
- *
- * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
- * value is returned with IWL_TM_ATTR_REG_VALUE32.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       u32 ofs, val32, cmd;
-       u8 val8;
-       struct sk_buff *skb;
-       int status = 0;
-
-       if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
-               IWL_ERR(priv, "Missing register offset\n");
-               return -ENOMSG;
-       }
-       ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
-       IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
-
-       /* Allow access only to FH/CSR/HBUS in direct mode.
-       Since we don't have the upper bounds for the CSR and HBUS segments,
-       we will use only the upper bound of FH for sanity check. */
-       cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-       if ((cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32 ||
-               cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32 ||
-               cmd == IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8) &&
-               (ofs >= FH_MEM_UPPER_BOUND)) {
-               IWL_ERR(priv, "offset out of segment (0x0 - 0x%x)\n",
-                       FH_MEM_UPPER_BOUND);
-               return -EINVAL;
-       }
-
-       switch (cmd) {
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
-               val32 = iwl_read_direct32(priv->trans, ofs);
-               IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
-
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       return -ENOMEM;
-               }
-               if (nla_put_u32(skb, IWL_TM_ATTR_REG_VALUE32, val32))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               break;
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
-               if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
-                       IWL_ERR(priv, "Missing value to write\n");
-                       return -ENOMSG;
-               } else {
-                       val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
-                       IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
-                       iwl_write_direct32(priv->trans, ofs, val32);
-               }
-               break;
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-               if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
-                       IWL_ERR(priv, "Missing value to write\n");
-                       return -ENOMSG;
-               } else {
-                       val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
-                       IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
-                       iwl_write8(priv->trans, ofs, val8);
-               }
-               break;
-       default:
-               IWL_ERR(priv, "Unknown testmode register command ID\n");
-               return -ENOSYS;
-       }
-
-       return status;
-
-nla_put_failure:
-       kfree_skb(skb);
-       return -EMSGSIZE;
-}
-
-
-static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
-{
-       struct iwl_notification_wait calib_wait;
-       static const u8 calib_complete[] = {
-               CALIBRATION_COMPLETE_NOTIFICATION
-       };
-       int ret;
-
-       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
-                                  calib_complete, ARRAY_SIZE(calib_complete),
-                                  NULL, NULL);
-       ret = iwl_init_alive_start(priv);
-       if (ret) {
-               IWL_ERR(priv, "Fail init calibration: %d\n", ret);
-               goto cfg_init_calib_error;
-       }
-
-       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
-       if (ret)
-               IWL_ERR(priv, "Error detecting"
-                       " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
-       return ret;
-
-cfg_init_calib_error:
-       iwl_remove_notification(&priv->notif_wait, &calib_wait);
-       return ret;
-}
-
-/*
- * This function handles the user application commands for driver.
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
- * value of the actual command execution is replied to the user application.
- *
- * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
- * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
- * IWL_TM_CMD_DEV2APP_SYNC_RSP.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct iwl_trans *trans = priv->trans;
-       struct sk_buff *skb;
-       unsigned char *rsp_data_ptr = NULL;
-       int status = 0, rsp_data_len = 0;
-       u32 devid, inst_size = 0, data_size = 0;
-       const struct fw_img *img;
-
-       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-       case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
-               rsp_data_ptr = (unsigned char *)priv->cfg->name;
-               rsp_data_len = strlen(priv->cfg->name);
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-                                                       rsp_data_len + 20);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       return -ENOMEM;
-               }
-               if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
-                               IWL_TM_CMD_DEV2APP_SYNC_RSP) ||
-                   nla_put(skb, IWL_TM_ATTR_SYNC_RSP,
-                           rsp_data_len, rsp_data_ptr))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
-               if (status)
-                       IWL_ERR(priv, "Error loading init ucode: %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
-               iwl_testmode_cfg_init_calib(priv);
-               priv->ucode_loaded = false;
-               iwl_trans_stop_device(trans);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
-               if (status) {
-                       IWL_ERR(priv,
-                               "Error loading runtime ucode: %d\n", status);
-                       break;
-               }
-               status = iwl_alive_start(priv);
-               if (status)
-                       IWL_ERR(priv,
-                               "Error starting the device: %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
-               iwl_scan_cancel_timeout(priv, 200);
-               priv->ucode_loaded = false;
-               iwl_trans_stop_device(trans);
-               status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
-               if (status) {
-                       IWL_ERR(priv,
-                               "Error loading WOWLAN ucode: %d\n", status);
-                       break;
-               }
-               status = iwl_alive_start(priv);
-               if (status)
-                       IWL_ERR(priv,
-                               "Error starting the device: %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
-               if (priv->eeprom) {
-                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-                               priv->cfg->base_params->eeprom_size + 20);
-                       if (!skb) {
-                               IWL_ERR(priv, "Memory allocation fail\n");
-                               return -ENOMEM;
-                       }
-                       if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
-                                       IWL_TM_CMD_DEV2APP_EEPROM_RSP) ||
-                           nla_put(skb, IWL_TM_ATTR_EEPROM,
-                                   priv->cfg->base_params->eeprom_size,
-                                   priv->eeprom))
-                               goto nla_put_failure;
-                       status = cfg80211_testmode_reply(skb);
-                       if (status < 0)
-                               IWL_ERR(priv, "Error sending msg : %d\n",
-                                       status);
-               } else
-                       return -EFAULT;
-               break;
-
-       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
-               if (!tb[IWL_TM_ATTR_FIXRATE]) {
-                       IWL_ERR(priv, "Missing fixrate setting\n");
-                       return -ENOMSG;
-               }
-               priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-               IWL_INFO(priv, "uCode version raw: 0x%x\n",
-                        priv->fw->ucode_ver);
-
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       return -ENOMEM;
-               }
-               if (nla_put_u32(skb, IWL_TM_ATTR_FW_VERSION,
-                               priv->fw->ucode_ver))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
-               devid = priv->trans->hw_id;
-               IWL_INFO(priv, "hw version: 0x%x\n", devid);
-
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       return -ENOMEM;
-               }
-               if (nla_put_u32(skb, IWL_TM_ATTR_DEVICE_ID, devid))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       return -ENOMEM;
-               }
-               if (!priv->ucode_loaded) {
-                       IWL_ERR(priv, "No uCode has not been loaded\n");
-                       return -EINVAL;
-               } else {
-                       img = &priv->fw->img[priv->cur_ucode];
-                       inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
-                       data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
-               }
-               if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) ||
-                   nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) ||
-                   nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0)
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               break;
-
-       default:
-               IWL_ERR(priv, "Unknown testmode driver command ID\n");
-               return -ENOSYS;
-       }
-       return status;
-
-nla_put_failure:
-       kfree_skb(skb);
-       return -EMSGSIZE;
-}
-
-
-/*
- * This function handles the user application commands for uCode trace
- *
- * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
- * handlers respectively.
- *
- * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
- * value of the actual command execution is replied to the user application.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       struct sk_buff *skb;
-       int status = 0;
-       struct device *dev = priv->trans->dev;
-
-       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
-               if (priv->testmode_trace.trace_enabled)
-                       return -EBUSY;
-
-               if (!tb[IWL_TM_ATTR_TRACE_SIZE])
-                       priv->testmode_trace.buff_size = TRACE_BUFF_SIZE_DEF;
-               else
-                       priv->testmode_trace.buff_size =
-                               nla_get_u32(tb[IWL_TM_ATTR_TRACE_SIZE]);
-               if (!priv->testmode_trace.buff_size)
-                       return -EINVAL;
-               if (priv->testmode_trace.buff_size < TRACE_BUFF_SIZE_MIN ||
-                   priv->testmode_trace.buff_size > TRACE_BUFF_SIZE_MAX)
-                       return -EINVAL;
-
-               priv->testmode_trace.total_size =
-                       priv->testmode_trace.buff_size + TRACE_BUFF_PADD;
-               priv->testmode_trace.cpu_addr =
-                       dma_alloc_coherent(dev,
-                                          priv->testmode_trace.total_size,
-                                          &priv->testmode_trace.dma_addr,
-                                          GFP_KERNEL);
-               if (!priv->testmode_trace.cpu_addr)
-                       return -ENOMEM;
-               priv->testmode_trace.trace_enabled = true;
-               priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
-                       priv->testmode_trace.cpu_addr, 0x100);
-               memset(priv->testmode_trace.trace_addr, 0x03B,
-                       priv->testmode_trace.buff_size);
-               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
-                       sizeof(priv->testmode_trace.dma_addr) + 20);
-               if (!skb) {
-                       IWL_ERR(priv, "Memory allocation fail\n");
-                       iwl_trace_cleanup(priv);
-                       return -ENOMEM;
-               }
-               if (nla_put(skb, IWL_TM_ATTR_TRACE_ADDR,
-                           sizeof(priv->testmode_trace.dma_addr),
-                           (u64 *)&priv->testmode_trace.dma_addr))
-                       goto nla_put_failure;
-               status = cfg80211_testmode_reply(skb);
-               if (status < 0) {
-                       IWL_ERR(priv, "Error sending msg : %d\n", status);
-               }
-               priv->testmode_trace.num_chunks =
-                       DIV_ROUND_UP(priv->testmode_trace.buff_size,
-                                    DUMP_CHUNK_SIZE);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_END_TRACE:
-               iwl_trace_cleanup(priv);
-               break;
-       default:
-               IWL_ERR(priv, "Unknown testmode mem command ID\n");
-               return -ENOSYS;
-       }
-       return status;
-
-nla_put_failure:
-       kfree_skb(skb);
-       if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
-           IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
-               iwl_trace_cleanup(priv);
-       return -EMSGSIZE;
-}
-
-static int iwl_testmode_trace_dump(struct ieee80211_hw *hw,
-                                  struct sk_buff *skb,
-                                  struct netlink_callback *cb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int idx, length;
-
-       if (priv->testmode_trace.trace_enabled &&
-           priv->testmode_trace.trace_addr) {
-               idx = cb->args[4];
-               if (idx >= priv->testmode_trace.num_chunks)
-                       return -ENOENT;
-               length = DUMP_CHUNK_SIZE;
-               if (((idx + 1) == priv->testmode_trace.num_chunks) &&
-                   (priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE))
-                       length = priv->testmode_trace.buff_size %
-                               DUMP_CHUNK_SIZE;
-
-               if (nla_put(skb, IWL_TM_ATTR_TRACE_DUMP, length,
-                           priv->testmode_trace.trace_addr +
-                           (DUMP_CHUNK_SIZE * idx)))
-                       goto nla_put_failure;
-               idx++;
-               cb->args[4] = idx;
-               return 0;
-       } else
-               return -EFAULT;
-
- nla_put_failure:
-       return -ENOBUFS;
-}
-
-/*
- * This function handles the user application switch ucode ownership.
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
- * decide who the current owner of the uCode
- *
- * If the current owner is OWNERSHIP_TM, then the only host command
- * can deliver to uCode is from testmode, all the other host commands
- * will dropped.
- *
- * default driver is the owner of uCode in normal operational mode
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       u8 owner;
-
-       if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
-               IWL_ERR(priv, "Missing ucode owner\n");
-               return -ENOMSG;
-       }
-
-       owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
-       if (owner == IWL_OWNERSHIP_DRIVER) {
-               priv->ucode_owner = owner;
-               priv->pre_rx_handler = NULL;
-       } else if (owner == IWL_OWNERSHIP_TM) {
-               priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
-               priv->ucode_owner = owner;
-       } else {
-               IWL_ERR(priv, "Invalid owner\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size)
-{
-       struct iwl_trans *trans = priv->trans;
-       unsigned long flags;
-       int i;
-
-       if (size & 0x3)
-               return -EINVAL;
-       priv->testmode_mem.buff_size = size;
-       priv->testmode_mem.buff_addr =
-               kmalloc(priv->testmode_mem.buff_size, GFP_KERNEL);
-       if (priv->testmode_mem.buff_addr == NULL)
-               return -ENOMEM;
-
-       /* Hard-coded periphery absolute address */
-       if (IWL_TM_ABS_PRPH_START <= addr &&
-               addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
-                       spin_lock_irqsave(&trans->reg_lock, flags);
-                       iwl_grab_nic_access(trans);
-                       iwl_write32(trans, HBUS_TARG_PRPH_RADDR,
-                               addr | (3 << 24));
-                       for (i = 0; i < size; i += 4)
-                               *(u32 *)(priv->testmode_mem.buff_addr + i) =
-                                       iwl_read32(trans, HBUS_TARG_PRPH_RDAT);
-                       iwl_release_nic_access(trans);
-                       spin_unlock_irqrestore(&trans->reg_lock, flags);
-       } else { /* target memory (SRAM) */
-               _iwl_read_targ_mem_words(trans, addr,
-                       priv->testmode_mem.buff_addr,
-                       priv->testmode_mem.buff_size / 4);
-       }
-
-       priv->testmode_mem.num_chunks =
-               DIV_ROUND_UP(priv->testmode_mem.buff_size, DUMP_CHUNK_SIZE);
-       priv->testmode_mem.read_in_progress = true;
-       return 0;
-
-}
-
-static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr,
-       u32 size, unsigned char *buf)
-{
-       struct iwl_trans *trans = priv->trans;
-       u32 val, i;
-       unsigned long flags;
-
-       if (IWL_TM_ABS_PRPH_START <= addr &&
-               addr < IWL_TM_ABS_PRPH_START + PRPH_END) {
-                       /* Periphery writes can be 1-3 bytes long, or DWORDs */
-                       if (size < 4) {
-                               memcpy(&val, buf, size);
-                               spin_lock_irqsave(&trans->reg_lock, flags);
-                               iwl_grab_nic_access(trans);
-                               iwl_write32(trans, HBUS_TARG_PRPH_WADDR,
-                                           (addr & 0x0000FFFF) |
-                                           ((size - 1) << 24));
-                               iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val);
-                               iwl_release_nic_access(trans);
-                               /* needed after consecutive writes w/o read */
-                               mmiowb();
-                               spin_unlock_irqrestore(&trans->reg_lock, flags);
-                       } else {
-                               if (size % 4)
-                                       return -EINVAL;
-                               for (i = 0; i < size; i += 4)
-                                       iwl_write_prph(trans, addr+i,
-                                               *(u32 *)(buf+i));
-                       }
-       } else if (iwlagn_hw_valid_rtc_data_addr(addr) ||
-               (IWLAGN_RTC_INST_LOWER_BOUND <= addr &&
-               addr < IWLAGN_RTC_INST_UPPER_BOUND)) {
-                       _iwl_write_targ_mem_words(trans, addr, buf, size/4);
-       } else
-               return -EINVAL;
-       return 0;
-}
-
-/*
- * This function handles the user application commands for SRAM data dump
- *
- * It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and
- * IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading
- *
- * Several error will be retured, -EBUSY if the SRAM data retrieved by
- * previous command has not been delivered to userspace, or -ENOMSG if
- * the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE)
- * are missing, or -ENOMEM if the buffer allocation fails.
- *
- * Otherwise 0 is replied indicating the success of the SRAM reading.
- *
- * @hw: ieee80211_hw object that represents the device
- * @tb: gnl message fields from the user space
- */
-static int iwl_testmode_indirect_mem(struct ieee80211_hw *hw,
-       struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       u32 addr, size, cmd;
-       unsigned char *buf;
-
-       /* Both read and write should be blocked, for atomicity */
-       if (priv->testmode_mem.read_in_progress)
-               return -EBUSY;
-
-       cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-       if (!tb[IWL_TM_ATTR_MEM_ADDR]) {
-               IWL_ERR(priv, "Error finding memory offset address\n");
-               return -ENOMSG;
-       }
-       addr = nla_get_u32(tb[IWL_TM_ATTR_MEM_ADDR]);
-       if (!tb[IWL_TM_ATTR_BUFFER_SIZE]) {
-               IWL_ERR(priv, "Error finding size for memory reading\n");
-               return -ENOMSG;
-       }
-       size = nla_get_u32(tb[IWL_TM_ATTR_BUFFER_SIZE]);
-
-       if (cmd == IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ)
-               return iwl_testmode_indirect_read(priv, addr,  size);
-       else {
-               if (!tb[IWL_TM_ATTR_BUFFER_DUMP])
-                       return -EINVAL;
-               buf = (unsigned char *) nla_data(tb[IWL_TM_ATTR_BUFFER_DUMP]);
-               return iwl_testmode_indirect_write(priv, addr, size, buf);
-       }
-}
-
-static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw,
-                                   struct sk_buff *skb,
-                                   struct netlink_callback *cb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int idx, length;
-
-       if (priv->testmode_mem.read_in_progress) {
-               idx = cb->args[4];
-               if (idx >= priv->testmode_mem.num_chunks) {
-                       iwl_mem_cleanup(priv);
-                       return -ENOENT;
-               }
-               length = DUMP_CHUNK_SIZE;
-               if (((idx + 1) == priv->testmode_mem.num_chunks) &&
-                   (priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE))
-                       length = priv->testmode_mem.buff_size %
-                               DUMP_CHUNK_SIZE;
-
-               if (nla_put(skb, IWL_TM_ATTR_BUFFER_DUMP, length,
-                           priv->testmode_mem.buff_addr +
-                           (DUMP_CHUNK_SIZE * idx)))
-                       goto nla_put_failure;
-               idx++;
-               cb->args[4] = idx;
-               return 0;
-       } else
-               return -EFAULT;
-
- nla_put_failure:
-       return -ENOBUFS;
-}
-
-static int iwl_testmode_notifications(struct ieee80211_hw *hw,
-       struct nlattr **tb)
-{
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       bool enable;
-
-       enable = nla_get_flag(tb[IWL_TM_ATTR_ENABLE_NOTIFICATION]);
-       if (enable)
-               priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
-       else
-               priv->pre_rx_handler = NULL;
-       return 0;
-}
-
-
-/* The testmode gnl message handler that takes the gnl message from the
- * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
- * invoke the corresponding handlers.
- *
- * This function is invoked when there is user space application sending
- * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
- * by nl80211.
- *
- * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
- * dispatching it to the corresponding handler.
- *
- * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
- * -ENOSYS is replied to the user application if the command is unknown;
- * Otherwise, the command is dispatched to the respective handler.
- *
- * @hw: ieee80211_hw object that represents the device
- * @data: pointer to user space message
- * @len: length in byte of @data
- */
-int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
-{
-       struct nlattr *tb[IWL_TM_ATTR_MAX];
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int result;
-
-       result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
-                       iwl_testmode_gnl_msg_policy);
-       if (result != 0) {
-               IWL_ERR(priv, "Error parsing the gnl message : %d\n", result);
-               return result;
-       }
-
-       /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
-       if (!tb[IWL_TM_ATTR_COMMAND]) {
-               IWL_ERR(priv, "Missing testmode command type\n");
-               return -ENOMSG;
-       }
-       /* in case multiple accesses to the device happens */
-       mutex_lock(&priv->mutex);
-
-       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
-       case IWL_TM_CMD_APP2DEV_UCODE:
-               IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
-               result = iwl_testmode_ucode(hw, tb);
-               break;
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32:
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE32:
-       case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8:
-               IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
-               result = iwl_testmode_reg(hw, tb);
-               break;
-       case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
-       case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-       case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
-       case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
-       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
-       case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
-       case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
-       case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
-       case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
-               IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
-               result = iwl_testmode_driver(hw, tb);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
-       case IWL_TM_CMD_APP2DEV_END_TRACE:
-       case IWL_TM_CMD_APP2DEV_READ_TRACE:
-               IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
-               result = iwl_testmode_trace(hw, tb);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_OWNERSHIP:
-               IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
-               result = iwl_testmode_ownership(hw, tb);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_READ:
-       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_WRITE:
-               IWL_DEBUG_INFO(priv, "testmode indirect memory cmd "
-                       "to driver\n");
-               result = iwl_testmode_indirect_mem(hw, tb);
-               break;
-
-       case IWL_TM_CMD_APP2DEV_NOTIFICATIONS:
-               IWL_DEBUG_INFO(priv, "testmode notifications cmd "
-                       "to driver\n");
-               result = iwl_testmode_notifications(hw, tb);
-               break;
-
-       default:
-               IWL_ERR(priv, "Unknown testmode command\n");
-               result = -ENOSYS;
-               break;
-       }
-
-       mutex_unlock(&priv->mutex);
-       return result;
-}
-
-int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     struct netlink_callback *cb,
-                     void *data, int len)
-{
-       struct nlattr *tb[IWL_TM_ATTR_MAX];
-       struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
-       int result;
-       u32 cmd;
-
-       if (cb->args[3]) {
-               /* offset by 1 since commands start at 0 */
-               cmd = cb->args[3] - 1;
-       } else {
-               result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
-                               iwl_testmode_gnl_msg_policy);
-               if (result) {
-                       IWL_ERR(priv,
-                               "Error parsing the gnl message : %d\n", result);
-                       return result;
-               }
-
-               /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
-               if (!tb[IWL_TM_ATTR_COMMAND]) {
-                       IWL_ERR(priv, "Missing testmode command type\n");
-                       return -ENOMSG;
-               }
-               cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]);
-               cb->args[3] = cmd + 1;
-       }
-
-       /* in case multiple accesses to the device happens */
-       mutex_lock(&priv->mutex);
-       switch (cmd) {
-       case IWL_TM_CMD_APP2DEV_READ_TRACE:
-               IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n");
-               result = iwl_testmode_trace_dump(hw, skb, cb);
-               break;
-       case IWL_TM_CMD_APP2DEV_INDIRECT_BUFFER_DUMP:
-               IWL_DEBUG_INFO(priv, "testmode sram dump cmd to driver\n");
-               result = iwl_testmode_buffer_dump(hw, skb, cb);
-               break;
-       default:
-               result = -EINVAL;
-               break;
-       }
-
-       mutex_unlock(&priv->mutex);
-       return result;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
deleted file mode 100644 (file)
index e959207..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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_trans_int_pcie_h__
-#define __iwl_trans_int_pcie_h__
-
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <linux/pci.h>
-#include <linux/timer.h>
-
-#include "iwl-fh.h"
-#include "iwl-csr.h"
-#include "iwl-trans.h"
-#include "iwl-debug.h"
-#include "iwl-io.h"
-#include "iwl-op-mode.h"
-
-struct iwl_host_cmd;
-
-/*This file includes the declaration that are internal to the
- * trans_pcie layer */
-
-struct iwl_rx_mem_buffer {
-       dma_addr_t page_dma;
-       struct page *page;
-       struct list_head list;
-};
-
-/**
- * struct isr_statistics - interrupt statistics
- *
- */
-struct isr_statistics {
-       u32 hw;
-       u32 sw;
-       u32 err_code;
-       u32 sch;
-       u32 alive;
-       u32 rfkill;
-       u32 ctkill;
-       u32 wakeup;
-       u32 rx;
-       u32 tx;
-       u32 unhandled;
-};
-
-/**
- * struct iwl_rx_queue - Rx queue
- * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
- * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
- * @pool:
- * @queue:
- * @read: Shared index to newest available Rx buffer
- * @write: Shared index to oldest written Rx packet
- * @free_count: Number of pre-allocated buffers in rx_free
- * @write_actual:
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
- * @need_update: flag to indicate we need to update read/write index
- * @rb_stts: driver's pointer to receive buffer status
- * @rb_stts_dma: bus address of receive buffer status
- * @lock:
- *
- * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
- */
-struct iwl_rx_queue {
-       __le32 *bd;
-       dma_addr_t bd_dma;
-       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
-       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
-       u32 read;
-       u32 write;
-       u32 free_count;
-       u32 write_actual;
-       struct list_head rx_free;
-       struct list_head rx_used;
-       int need_update;
-       struct iwl_rb_status *rb_stts;
-       dma_addr_t rb_stts_dma;
-       spinlock_t lock;
-};
-
-struct iwl_dma_ptr {
-       dma_addr_t dma;
-       void *addr;
-       size_t size;
-};
-
-/**
- * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
-{
-       return ++index & (n_bd - 1);
-}
-
-/**
- * iwl_queue_dec_wrap - decrement queue index, wrap back to end
- * @index -- current index
- * @n_bd -- total number of entries in queue (must be power of 2)
- */
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
-{
-       return --index & (n_bd - 1);
-}
-
-struct iwl_cmd_meta {
-       /* only for SYNC commands, iff the reply skb is wanted */
-       struct iwl_host_cmd *source;
-
-       DEFINE_DMA_UNMAP_ADDR(mapping);
-       DEFINE_DMA_UNMAP_LEN(len);
-
-       u32 flags;
-};
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues.
- *
- * Note the difference between n_bd and n_window: the hardware
- * always assumes 256 descriptors, so n_bd is always 256 (unless
- * there might be HW changes in the future). For the normal TX
- * queues, n_window, which is the size of the software queue data
- * is also 256; however, for the command queue, n_window is only
- * 32 since we don't need so many commands pending. Since the HW
- * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
- * the software buffers (in the variables @meta, @txb in struct
- * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
- * in the same struct) have 256.
- * This means that we end up with the following:
- *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
- *  SW entries:           | 0      | ... | 31          |
- * where N is a number between 0 and 7. This means that the SW
- * data is a window overlayed over the HW queue.
- */
-struct iwl_queue {
-       int n_bd;              /* number of BDs in this queue */
-       int write_ptr;       /* 1-st empty entry (index) host_w*/
-       int read_ptr;         /* last used entry (index) host_r*/
-       /* use for monitoring and recovering the stuck queue */
-       dma_addr_t dma_addr;   /* physical addr for BD's */
-       int n_window;          /* safe queue window */
-       u32 id;
-       int low_mark;          /* low watermark, resume queue if free
-                               * space more than this */
-       int high_mark;         /* high watermark, stop queue if free
-                               * space less than this */
-};
-
-#define TFD_TX_CMD_SLOTS 256
-#define TFD_CMD_SLOTS 32
-
-struct iwl_pcie_tx_queue_entry {
-       struct iwl_device_cmd *cmd;
-       struct sk_buff *skb;
-       struct iwl_cmd_meta meta;
-};
-
-/**
- * struct iwl_tx_queue - Tx Queue for DMA
- * @q: generic Rx/Tx queue descriptor
- * @tfds: transmit frame descriptors (DMA memory)
- * @entries: transmit entries (driver state)
- * @lock: queue lock
- * @stuck_timer: timer that fires if queue gets stuck
- * @trans_pcie: pointer back to transport (for timer)
- * @need_update: indicates need to update read/write index
- * @active: stores if queue is active
- *
- * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
- * descriptors) and required locking structures.
- */
-struct iwl_tx_queue {
-       struct iwl_queue q;
-       struct iwl_tfd *tfds;
-       struct iwl_pcie_tx_queue_entry *entries;
-       spinlock_t lock;
-       struct timer_list stuck_timer;
-       struct iwl_trans_pcie *trans_pcie;
-       u8 need_update;
-       u8 active;
-};
-
-/**
- * struct iwl_trans_pcie - PCIe transport specific data
- * @rxq: all the RX queue data
- * @rx_replenish: work that will be called when buffers need to be allocated
- * @drv - pointer to iwl_drv
- * @trans: pointer to the generic transport area
- * @irq - the irq number for the device
- * @irq_requested: true when the irq has been requested
- * @scd_base_addr: scheduler sram base address in SRAM
- * @scd_bc_tbls: pointer to the byte count table of the scheduler
- * @kw: keep warm address
- * @pci_dev: basic pci-network driver stuff
- * @hw_base: pci hardware address support
- * @ucode_write_complete: indicates that the ucode has been copied.
- * @ucode_write_waitq: wait queue for uCode load
- * @status - transport specific status flags
- * @cmd_queue - command queue number
- * @rx_buf_size_8k: 8 kB RX buffer size
- * @rx_page_order: page order for receive buffer size
- * @wd_timeout: queue watchdog timeout (jiffies)
- */
-struct iwl_trans_pcie {
-       struct iwl_rx_queue rxq;
-       struct work_struct rx_replenish;
-       struct iwl_trans *trans;
-       struct iwl_drv *drv;
-
-       /* INT ICT Table */
-       __le32 *ict_tbl;
-       dma_addr_t ict_tbl_dma;
-       int ict_index;
-       u32 inta;
-       bool use_ict;
-       bool irq_requested;
-       struct tasklet_struct irq_tasklet;
-       struct isr_statistics isr_stats;
-
-       unsigned int irq;
-       spinlock_t irq_lock;
-       u32 inta_mask;
-       u32 scd_base_addr;
-       struct iwl_dma_ptr scd_bc_tbls;
-       struct iwl_dma_ptr kw;
-
-       struct iwl_tx_queue *txq;
-       unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-       unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
-
-       /* PCI bus related data */
-       struct pci_dev *pci_dev;
-       void __iomem *hw_base;
-
-       bool ucode_write_complete;
-       wait_queue_head_t ucode_write_waitq;
-       unsigned long status;
-       u8 cmd_queue;
-       u8 n_no_reclaim_cmds;
-       u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
-       u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES];
-       u8 n_q_to_fifo;
-
-       bool rx_buf_size_8k;
-       u32 rx_page_order;
-
-       const char **command_names;
-
-       /* queue watchdog */
-       unsigned long wd_timeout;
-};
-
-/*****************************************************
-* DRIVER STATUS FUNCTIONS
-******************************************************/
-#define STATUS_HCMD_ACTIVE     0
-#define STATUS_DEVICE_ENABLED  1
-#define STATUS_TPOWER_PMI      2
-#define STATUS_INT_ENABLED     3
-
-#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
-       ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
-
-static inline struct iwl_trans *
-iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
-{
-       return container_of((void *)trans_pcie, struct iwl_trans,
-                           trans_specific);
-}
-
-struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent,
-                                      const struct iwl_cfg *cfg);
-void iwl_trans_pcie_free(struct iwl_trans *trans);
-
-/*****************************************************
-* RX
-******************************************************/
-void iwl_bg_rx_replenish(struct work_struct *data);
-void iwl_irq_tasklet(struct iwl_trans *trans);
-void iwlagn_rx_replenish(struct iwl_trans *trans);
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-                       struct iwl_rx_queue *q);
-
-/*****************************************************
-* ICT
-******************************************************/
-void iwl_reset_ict(struct iwl_trans *trans);
-void iwl_disable_ict(struct iwl_trans *trans);
-int iwl_alloc_isr_ict(struct iwl_trans *trans);
-void iwl_free_isr_ict(struct iwl_trans *trans);
-irqreturn_t iwl_isr_ict(int irq, void *data);
-
-/*****************************************************
-* TX / HCMD
-******************************************************/
-void iwl_txq_update_write_ptr(struct iwl_trans *trans,
-                       struct iwl_tx_queue *txq);
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len, u8 reset);
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
-void iwl_tx_cmd_complete(struct iwl_trans *trans,
-                        struct iwl_rx_cmd_buffer *rxb, int handler_status);
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-                                          struct iwl_tx_queue *txq,
-                                          u16 byte_cnt);
-void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int queue);
-void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index);
-void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
-                                  struct iwl_tx_queue *txq,
-                                  int tx_fifo_id, bool active);
-void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo,
-                                int sta_id, int tid, int frame_limit, u16 ssn);
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                        enum dma_data_direction dma_dir);
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-                        struct sk_buff_head *skbs);
-int iwl_queue_space(const struct iwl_queue *q);
-
-/*****************************************************
-* Error handling
-******************************************************/
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
-void iwl_dump_csr(struct iwl_trans *trans);
-
-/*****************************************************
-* Helpers
-******************************************************/
-static inline void iwl_disable_interrupts(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-
-       /* disable interrupts from uCode/NIC to host */
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(trans, CSR_INT, 0xffffffff);
-       iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
-       IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
-}
-
-static inline void iwl_enable_interrupts(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
-}
-
-static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
-{
-       IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
-}
-
-static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (test_and_clear_bit(txq->q.id, trans_pcie->queue_stopped)) {
-               IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->q.id);
-               iwl_op_mode_queue_not_full(trans->op_mode, txq->q.id);
-       }
-}
-
-static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (!test_and_set_bit(txq->q.id, trans_pcie->queue_stopped)) {
-               iwl_op_mode_queue_full(trans->op_mode, txq->q.id);
-               IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->q.id);
-       } else
-               IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n",
-                                   txq->q.id);
-}
-
-static inline int iwl_queue_used(const struct iwl_queue *q, int i)
-{
-       return q->write_ptr >= q->read_ptr ?
-               (i >= q->read_ptr && i < q->write_ptr) :
-               !(i < q->read_ptr && i >= q->write_ptr);
-}
-
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
-{
-       return index & (q->n_window - 1);
-}
-
-static inline const char *
-trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd)
-{
-       if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
-               return "UNKNOWN";
-       return trans_pcie->command_names[cmd];
-}
-
-static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
-{
-       return !(iwl_read32(trans, CSR_GP_CNTRL) &
-               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
-}
-
-#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
deleted file mode 100644 (file)
index 08517d3..0000000
+++ /dev/null
@@ -1,1069 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/sched.h>
-#include <linux/wait.h>
-#include <linux/gfp.h>
-
-#include "iwl-prph.h"
-#include "iwl-io.h"
-#include "iwl-trans-pcie-int.h"
-#include "iwl-op-mode.h"
-
-#ifdef CONFIG_IWLWIFI_IDI
-#include "iwl-amfh.h"
-#endif
-
-/******************************************************************************
- *
- * RX path functions
- *
- ******************************************************************************/
-
-/*
- * Rx theory of operation
- *
- * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
- * each of which point to Receive Buffers to be filled by the NIC.  These get
- * used not only for Rx frames, but for any command response or notification
- * from the NIC.  The driver and NIC manage the Rx buffers by means
- * of indexes into the circular buffer.
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization, the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer, it will advance the READ index
- * and fire the RX interrupt.  The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
- *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replenish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
- *   iwl->rxq is replenished and the READ INDEX is updated (updating the
- *   'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl_rx_queue_alloc()   Allocates rx_free
- * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
- *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
- *                            READ INDEX, detaching the SKB from the pool.
- *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
- *                            slots.
- * ...
- *
- */
-
-/**
- * iwl_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
-{
-       int s = q->read - q->write;
-       if (s <= 0)
-               s += RX_QUEUE_SIZE;
-       /* keep some buffer to not confuse full and empty queue */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
-}
-
-/**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- */
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-                       struct iwl_rx_queue *q)
-{
-       unsigned long flags;
-       u32 reg;
-
-       spin_lock_irqsave(&q->lock, flags);
-
-       if (q->need_update == 0)
-               goto exit_unlock;
-
-       if (trans->cfg->base_params->shadow_reg_enable) {
-               /* shadow register enabled */
-               /* Device expects a multiple of 8 */
-               q->write_actual = (q->write & ~0x7);
-               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual);
-       } else {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(trans);
-
-               /* If power-saving is in use, make sure device is awake */
-               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
-                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                               IWL_DEBUG_INFO(trans,
-                                       "Rx queue requesting wakeup,"
-                                       " GP1 = 0x%x\n", reg);
-                               iwl_set_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                               goto exit_unlock;
-                       }
-
-                       q->write_actual = (q->write & ~0x7);
-                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-                                       q->write_actual);
-
-               /* Else device is assumed to be awake */
-               } else {
-                       /* Device expects a multiple of 8 */
-                       q->write_actual = (q->write & ~0x7);
-                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
-                               q->write_actual);
-               }
-       }
-       q->need_update = 0;
-
- exit_unlock:
-       spin_unlock_irqrestore(&q->lock, flags);
-}
-
-/**
- * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
-{
-       return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-               /* The overwritten rxb must be a used one */
-               rxb = rxq->queue[rxq->write];
-               BUG_ON(rxb && rxb->page);
-
-               /* Get next free Rx buffer, remove from free list */
-               element = rxq->rx_free.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
-               rxq->queue[rxq->write] = rxb;
-               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
-               rxq->free_count--;
-       }
-       spin_unlock_irqrestore(&rxq->lock, flags);
-       /* If the pre-allocated buffer pool is dropping low, schedule to
-        * refill it */
-       if (rxq->free_count <= RX_LOW_WATERMARK)
-               schedule_work(&trans_pcie->rx_replenish);
-
-
-       /* If we've added more space for the firmware to place data, tell it.
-        * Increment device's write pointer in multiples of 8. */
-       if (rxq->write_actual != (rxq->write & ~0x7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
-               iwl_rx_queue_update_write_ptr(trans, rxq);
-       }
-}
-
-/**
- * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       struct page *page;
-       unsigned long flags;
-       gfp_t gfp_mask = priority;
-
-       while (1) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       return;
-               }
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               if (rxq->free_count > RX_LOW_WATERMARK)
-                       gfp_mask |= __GFP_NOWARN;
-
-               if (trans_pcie->rx_page_order > 0)
-                       gfp_mask |= __GFP_COMP;
-
-               /* Alloc a new receive buffer */
-               page = alloc_pages(gfp_mask,
-                                 trans_pcie->rx_page_order);
-               if (!page) {
-                       if (net_ratelimit())
-                               IWL_DEBUG_INFO(trans, "alloc_pages failed, "
-                                          "order: %d\n",
-                                          trans_pcie->rx_page_order);
-
-                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
-                           net_ratelimit())
-                               IWL_CRIT(trans, "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 */
-                       return;
-               }
-
-               spin_lock_irqsave(&rxq->lock, flags);
-
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       __free_pages(page, trans_pcie->rx_page_order);
-                       return;
-               }
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               BUG_ON(rxb->page);
-               rxb->page = page;
-               /* Get physical address of the RB */
-               rxb->page_dma = dma_map_page(trans->dev, page, 0,
-                               PAGE_SIZE << trans_pcie->rx_page_order,
-                               DMA_FROM_DEVICE);
-               /* dma address must be no more than 36 bits */
-               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-               /* and also 256 byte aligned! */
-               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++;
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-       }
-}
-
-void iwlagn_rx_replenish(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
-
-       iwlagn_rx_allocate(trans, GFP_KERNEL);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwlagn_rx_queue_restock(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
-{
-       iwlagn_rx_allocate(trans, GFP_ATOMIC);
-
-       iwlagn_rx_queue_restock(trans);
-}
-
-void iwl_bg_rx_replenish(struct work_struct *data)
-{
-       struct iwl_trans_pcie *trans_pcie =
-           container_of(data, struct iwl_trans_pcie, rx_replenish);
-
-       iwlagn_rx_replenish(trans_pcie->trans);
-}
-
-static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-       unsigned long flags;
-       bool page_stolen = false;
-       int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
-       u32 offset = 0;
-
-       if (WARN_ON(!rxb))
-               return;
-
-       dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE);
-
-       while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {
-               struct iwl_rx_packet *pkt;
-               struct iwl_device_cmd *cmd;
-               u16 sequence;
-               bool reclaim;
-               int index, cmd_index, err, len;
-               struct iwl_rx_cmd_buffer rxcb = {
-                       ._offset = offset,
-                       ._page = rxb->page,
-                       ._page_stolen = false,
-                       .truesize = max_len,
-               };
-
-               pkt = rxb_addr(&rxcb);
-
-               if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
-                       break;
-
-               IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
-                       rxcb._offset,
-                       trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd),
-                       pkt->hdr.cmd);
-
-               len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-               len += sizeof(u32); /* account for status word */
-               trace_iwlwifi_dev_rx(trans->dev, pkt, len);
-
-               /* Reclaim a command buffer only if this packet is a response
-                *   to a (driver-originated) command.
-                * If the packet (e.g. Rx frame) originated from uCode,
-                *   there is no command buffer to reclaim.
-                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-                *   but apparently a few don't get set; catch them here. */
-               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
-               if (reclaim) {
-                       int i;
-
-                       for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
-                               if (trans_pcie->no_reclaim_cmds[i] ==
-                                                       pkt->hdr.cmd) {
-                                       reclaim = false;
-                                       break;
-                               }
-                       }
-               }
-
-               sequence = le16_to_cpu(pkt->hdr.sequence);
-               index = SEQ_TO_INDEX(sequence);
-               cmd_index = get_cmd_index(&txq->q, index);
-
-               if (reclaim)
-                       cmd = txq->entries[cmd_index].cmd;
-               else
-                       cmd = NULL;
-
-               err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
-
-               /*
-                * After here, we should always check rxcb._page_stolen,
-                * if it is true then one of the handlers took the page.
-                */
-
-               if (reclaim) {
-                       /* Invoke any callbacks, transfer the buffer to caller,
-                        * and fire off the (possibly) blocking
-                        * iwl_trans_send_cmd()
-                        * as we reclaim the driver command queue */
-                       if (!rxcb._page_stolen)
-                               iwl_tx_cmd_complete(trans, &rxcb, err);
-                       else
-                               IWL_WARN(trans, "Claim null rxb?\n");
-               }
-
-               page_stolen |= rxcb._page_stolen;
-               offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN);
-       }
-
-       /* page was stolen from us -- free our reference */
-       if (page_stolen) {
-               __free_pages(rxb->page, trans_pcie->rx_page_order);
-               rxb->page = 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);
-       if (rxb->page != NULL) {
-               rxb->page_dma =
-                       dma_map_page(trans->dev, rxb->page, 0,
-                               PAGE_SIZE << trans_pcie->rx_page_order,
-                               DMA_FROM_DEVICE);
-               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);
-}
-
-/**
- * iwl_rx_handle - Main entry function for receiving responses from uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers, including command responses,
- * frame-received notifications, and other notifications.
- */
-static void iwl_rx_handle(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       u32 r, i;
-       u8 fill_rx = 0;
-       u32 count = 8;
-       int total_empty;
-
-       /* uCode's read index (stored in shared DRAM) indicates the last Rx
-        * buffer that the driver may process (last buffer filled by ucode). */
-       r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
-       i = rxq->read;
-
-       /* Rx interrupt, but nothing sent from uCode */
-       if (i == r)
-               IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i);
-
-       /* calculate total frames need to be restock after handling RX */
-       total_empty = r - rxq->write_actual;
-       if (total_empty < 0)
-               total_empty += RX_QUEUE_SIZE;
-
-       if (total_empty > (RX_QUEUE_SIZE / 2))
-               fill_rx = 1;
-
-       while (i != r) {
-               struct iwl_rx_mem_buffer *rxb;
-
-               rxb = rxq->queue[i];
-               rxq->queue[i] = NULL;
-
-               IWL_DEBUG_RX(trans, "rxbuf: r = %d, i = %d (%p)\n", rxb);
-
-               iwl_rx_handle_rxbuf(trans, rxb);
-
-               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) {
-                               rxq->read = i;
-                               iwlagn_rx_replenish_now(trans);
-                               count = 0;
-                       }
-               }
-       }
-
-       /* Backtrack one entry */
-       rxq->read = i;
-       if (fill_rx)
-               iwlagn_rx_replenish_now(trans);
-       else
-               iwlagn_rx_queue_restock(trans);
-}
-
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-static void iwl_irq_handle_error(struct iwl_trans *trans)
-{
-       /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
-       if (trans->cfg->internal_wimax_coex &&
-           (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
-                       APMS_CLK_VAL_MRB_FUNC_MODE) ||
-            (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
-                       APMG_PS_CTRL_VAL_RESET_REQ))) {
-               struct iwl_trans_pcie *trans_pcie;
-
-               trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-               iwl_op_mode_wimax_active(trans->op_mode);
-               wake_up(&trans->wait_command_queue);
-               return;
-       }
-
-       iwl_dump_csr(trans);
-       iwl_dump_fh(trans, NULL, false);
-
-       iwl_op_mode_nic_error(trans->op_mode);
-}
-
-/* tasklet for iwlagn interrupt */
-void iwl_irq_tasklet(struct iwl_trans *trans)
-{
-       u32 inta = 0;
-       u32 handled = 0;
-       unsigned long flags;
-       u32 i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       u32 inta_mask;
-#endif
-
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Ack/clear/reset pending uCode interrupts.
-        * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
-        */
-       /* There is a hardware bug in the interrupt mask function that some
-        * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
-        * they are disabled in the CSR_INT_MASK register. Furthermore the
-        * ICT interrupt handling mechanism has another bug that might cause
-        * these unmasked interrupts fail to be detected. We workaround the
-        * hardware bugs here by ACKing all the possible interrupts so that
-        * interrupt coalescing can still be achieved.
-        */
-       iwl_write32(trans, CSR_INT,
-               trans_pcie->inta | ~trans_pcie->inta_mask);
-
-       inta = trans_pcie->inta;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_have_debug_level(IWL_DL_ISR)) {
-               /* just for debug */
-               inta_mask = iwl_read32(trans, CSR_INT_MASK);
-               IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
-                               inta, inta_mask);
-       }
-#endif
-
-       /* saved interrupt in inta variable now we can reset trans_pcie->inta */
-       trans_pcie->inta = 0;
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       /* Now service all interrupt bits discovered above. */
-       if (inta & CSR_INT_BIT_HW_ERR) {
-               IWL_ERR(trans, "Hardware error detected.  Restarting.\n");
-
-               /* Tell the device to stop sending interrupts */
-               iwl_disable_interrupts(trans);
-
-               isr_stats->hw++;
-               iwl_irq_handle_error(trans);
-
-               handled |= CSR_INT_BIT_HW_ERR;
-
-               return;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_have_debug_level(IWL_DL_ISR)) {
-               /* NIC fires this, but we don't use it, redundant with WAKEUP */
-               if (inta & CSR_INT_BIT_SCD) {
-                       IWL_DEBUG_ISR(trans, "Scheduler finished to transmit "
-                                     "the frame/frames.\n");
-                       isr_stats->sch++;
-               }
-
-               /* Alive notification via Rx interrupt will do the real work */
-               if (inta & CSR_INT_BIT_ALIVE) {
-                       IWL_DEBUG_ISR(trans, "Alive interrupt\n");
-                       isr_stats->alive++;
-               }
-       }
-#endif
-       /* Safely ignore these bits for debug checks below */
-       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
-
-       /* HW RF KILL switch toggled */
-       if (inta & CSR_INT_BIT_RF_KILL) {
-               bool hw_rfkill;
-
-               hw_rfkill = iwl_is_rfkill_set(trans);
-               IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
-                               hw_rfkill ? "disable radio" : "enable radio");
-
-               isr_stats->rfkill++;
-
-               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-               handled |= CSR_INT_BIT_RF_KILL;
-       }
-
-       /* Chip got too hot and stopped itself */
-       if (inta & CSR_INT_BIT_CT_KILL) {
-               IWL_ERR(trans, "Microcode CT kill error detected.\n");
-               isr_stats->ctkill++;
-               handled |= CSR_INT_BIT_CT_KILL;
-       }
-
-       /* Error detected by uCode */
-       if (inta & CSR_INT_BIT_SW_ERR) {
-               IWL_ERR(trans, "Microcode SW error detected. "
-                       " Restarting 0x%X.\n", inta);
-               isr_stats->sw++;
-               iwl_irq_handle_error(trans);
-               handled |= CSR_INT_BIT_SW_ERR;
-       }
-
-       /* uCode wakes up after power-down sleep */
-       if (inta & CSR_INT_BIT_WAKEUP) {
-               IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
-               iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
-               for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
-                       iwl_txq_update_write_ptr(trans,
-                                                &trans_pcie->txq[i]);
-
-               isr_stats->wakeup++;
-
-               handled |= CSR_INT_BIT_WAKEUP;
-       }
-
-       /* All uCode command responses, including Tx command responses,
-        * Rx "responses" (frame-received notification), and other
-        * notifications from uCode come through here*/
-       if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
-                       CSR_INT_BIT_RX_PERIODIC)) {
-               IWL_DEBUG_ISR(trans, "Rx interrupt\n");
-               if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-                       handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
-                       iwl_write32(trans, CSR_FH_INT_STATUS,
-                                       CSR_FH_INT_RX_MASK);
-               }
-               if (inta & CSR_INT_BIT_RX_PERIODIC) {
-                       handled |= CSR_INT_BIT_RX_PERIODIC;
-                       iwl_write32(trans,
-                               CSR_INT, CSR_INT_BIT_RX_PERIODIC);
-               }
-               /* Sending RX interrupt require many steps to be done in the
-                * the device:
-                * 1- write interrupt to current index in ICT table.
-                * 2- dma RX frame.
-                * 3- update RX shared data to indicate last write index.
-                * 4- send interrupt.
-                * This could lead to RX race, driver could receive RX interrupt
-                * but the shared data changes does not reflect this;
-                * periodic interrupt will detect any dangling Rx activity.
-                */
-
-               /* Disable periodic interrupt; we use it as just a one-shot. */
-               iwl_write8(trans, CSR_INT_PERIODIC_REG,
-                           CSR_INT_PERIODIC_DIS);
-#ifdef CONFIG_IWLWIFI_IDI
-               iwl_amfh_rx_handler();
-#else
-               iwl_rx_handle(trans);
-#endif
-               /*
-                * Enable periodic interrupt in 8 msec only if we received
-                * real RX interrupt (instead of just periodic int), to catch
-                * any dangling Rx interrupt.  If it was just the periodic
-                * interrupt, there was no dangling Rx activity, and no need
-                * to extend the periodic interrupt; one-shot is enough.
-                */
-               if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
-                       iwl_write8(trans, CSR_INT_PERIODIC_REG,
-                                   CSR_INT_PERIODIC_ENA);
-
-               isr_stats->rx++;
-       }
-
-       /* This "Tx" DMA channel is used only for loading uCode */
-       if (inta & CSR_INT_BIT_FH_TX) {
-               iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
-               IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
-               isr_stats->tx++;
-               handled |= CSR_INT_BIT_FH_TX;
-               /* Wake up uCode load routine, now that load is complete */
-               trans_pcie->ucode_write_complete = true;
-               wake_up(&trans_pcie->ucode_write_waitq);
-       }
-
-       if (inta & ~handled) {
-               IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
-               isr_stats->unhandled++;
-       }
-
-       if (inta & ~(trans_pcie->inta_mask)) {
-               IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n",
-                        inta & ~trans_pcie->inta_mask);
-       }
-
-       /* Re-enable all interrupts */
-       /* only Re-enable if disabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
-               iwl_enable_interrupts(trans);
-       /* Re-enable RF_KILL if it occurred */
-       else if (handled & CSR_INT_BIT_RF_KILL)
-               iwl_enable_rfkill_int(trans);
-}
-
-/******************************************************************************
- *
- * ICT functions
- *
- ******************************************************************************/
-
-/* a device (PCI-E) page is 4096 bytes long */
-#define ICT_SHIFT      12
-#define ICT_SIZE       (1 << ICT_SHIFT)
-#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
-
-/* Free dram table */
-void iwl_free_isr_ict(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (trans_pcie->ict_tbl) {
-               dma_free_coherent(trans->dev, ICT_SIZE,
-                                 trans_pcie->ict_tbl,
-                                 trans_pcie->ict_tbl_dma);
-               trans_pcie->ict_tbl = NULL;
-               trans_pcie->ict_tbl_dma = 0;
-       }
-}
-
-
-/*
- * allocate dram shared table, it is an aligned memory
- * block of ICT_SIZE.
- * also reset all data related to ICT table interrupt.
- */
-int iwl_alloc_isr_ict(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       trans_pcie->ict_tbl =
-               dma_alloc_coherent(trans->dev, ICT_SIZE,
-                                  &trans_pcie->ict_tbl_dma,
-                                  GFP_KERNEL);
-       if (!trans_pcie->ict_tbl)
-               return -ENOMEM;
-
-       /* just an API sanity check ... it is guaranteed to be aligned */
-       if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
-               iwl_free_isr_ict(trans);
-               return -EINVAL;
-       }
-
-       IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
-                     (unsigned long long)trans_pcie->ict_tbl_dma);
-
-       IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
-
-       /* reset table and index to all 0 */
-       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-       trans_pcie->ict_index = 0;
-
-       /* add periodic RX interrupt */
-       trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
-       return 0;
-}
-
-/* Device is going up inform it about using ICT interrupt table,
- * also we need to tell the driver to start using ICT interrupt.
- */
-void iwl_reset_ict(struct iwl_trans *trans)
-{
-       u32 val;
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (!trans_pcie->ict_tbl)
-               return;
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_disable_interrupts(trans);
-
-       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-
-       val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;
-
-       val |= CSR_DRAM_INT_TBL_ENABLE;
-       val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
-
-       IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);
-
-       iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val);
-       trans_pcie->use_ict = true;
-       trans_pcie->ict_index = 0;
-       iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
-       iwl_enable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-/* Device is going down disable ict interrupt usage */
-void iwl_disable_ict(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       unsigned long flags;
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       trans_pcie->use_ict = false;
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-static irqreturn_t iwl_isr(int irq, void *data)
-{
-       struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie;
-       u32 inta, inta_mask;
-       unsigned long flags;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       u32 inta_fh;
-#endif
-       if (!trans)
-               return IRQ_NONE;
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(trans, CSR_INT);
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared. It might have already raised
-                * an interrupt */
-               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               goto unplugged;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_have_debug_level(IWL_DL_ISR)) {
-               inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS);
-               IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, "
-                             "fh 0x%08x\n", inta, inta_mask, inta_fh);
-       }
-#endif
-
-       trans_pcie->inta |= inta;
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta))
-               tasklet_schedule(&trans_pcie->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-                       !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-
- unplugged:
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service. */
-       /* only Re-enable if disabled by irq  and no schedules tasklet. */
-       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-               !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_NONE;
-}
-
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_isr_ict(int irq, void *data)
-{
-       struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie;
-       u32 inta, inta_mask;
-       u32 val = 0;
-       u32 read;
-       unsigned long flags;
-
-       if (!trans)
-               return IRQ_NONE;
-
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* dram interrupt table not set yet,
-        * use legacy interrupt.
-        */
-       if (!trans_pcie->use_ict)
-               return iwl_isr(irq, data);
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        * back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here.
-        */
-       inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
-       if (!read) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       /*
-        * Collect all entries up to the first 0, starting from ict_index;
-        * note we already read at ict_index.
-        */
-       do {
-               val |= read;
-               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
-                               trans_pcie->ict_index, read);
-               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
-               trans_pcie->ict_index =
-                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
-
-               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
-                                          read);
-       } while (read);
-
-       /* We should not get this value, just ignore it. */
-       if (val == 0xffffffff)
-               val = 0;
-
-       /*
-        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
-        * (bit 15 before shifting it to 31) to clear when using interrupt
-        * coalescing. fortunately, bits 18 and 19 stay set when this happens
-        * so we use them to decide on the real state of the Rx bit.
-        * In order words, bit 15 is set if bit 18 or bit 19 are set.
-        */
-       if (val & 0xC0000)
-               val |= 0x8000;
-
-       inta = (0xff & val) | ((0xff00 & val) << 16);
-       IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
-                       inta, inta_mask, val);
-
-       inta &= trans_pcie->inta_mask;
-       trans_pcie->inta |= inta;
-
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta))
-               tasklet_schedule(&trans_pcie->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-                !trans_pcie->inta) {
-               /* Allow interrupt if was disabled by this handler and
-                * no tasklet was schedules, We should not enable interrupt,
-                * tasklet will enable it.
-                */
-               iwl_enable_interrupts(trans);
-       }
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service.
-        * only Re-enable if disabled by irq.
-        */
-       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
-           !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return IRQ_NONE;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
deleted file mode 100644 (file)
index a875023..0000000
+++ /dev/null
@@ -1,989 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * 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/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-#include "iwl-debug.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-op-mode.h"
-#include "iwl-trans-pcie-int.h"
-/* FIXME: need to abstract out TX command (once we know what it looks like) */
-#include "iwl-commands.h"
-
-#define IWL_TX_CRC_SIZE 4
-#define IWL_TX_DELIMITER_SIZE 4
-
-/**
- * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
- */
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-                                          struct iwl_tx_queue *txq,
-                                          u16 byte_cnt)
-{
-       struct iwlagn_scd_bc_tbl *scd_bc_tbl;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       int write_ptr = txq->q.write_ptr;
-       int txq_id = txq->q.id;
-       u8 sec_ctl = 0;
-       u8 sta_id = 0;
-       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
-       __le16 bc_ent;
-       struct iwl_tx_cmd *tx_cmd =
-               (void *) txq->entries[txq->q.write_ptr].cmd->payload;
-
-       scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
-
-       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       sta_id = tx_cmd->sta_id;
-       sec_ctl = tx_cmd->sec_ctl;
-
-       switch (sec_ctl & TX_CMD_SEC_MSK) {
-       case TX_CMD_SEC_CCM:
-               len += CCMP_MIC_LEN;
-               break;
-       case TX_CMD_SEC_TKIP:
-               len += TKIP_ICV_LEN;
-               break;
-       case TX_CMD_SEC_WEP:
-               len += WEP_IV_LEN + WEP_ICV_LEN;
-               break;
-       }
-
-       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
-
-       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
-
-       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
-}
-
-/**
- * iwl_txq_update_write_ptr - Send new write index to hardware
- */
-void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
-{
-       u32 reg = 0;
-       int txq_id = txq->q.id;
-
-       if (txq->need_update == 0)
-               return;
-
-       if (trans->cfg->base_params->shadow_reg_enable) {
-               /* shadow register enabled */
-               iwl_write32(trans, HBUS_TARG_WRPTR,
-                           txq->q.write_ptr | (txq_id << 8));
-       } else {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(trans);
-               /* if we're trying to save power */
-               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
-                       /* wake up nic if it's powered down ...
-                        * uCode will wake up, and interrupt us again, so next
-                        * time we'll skip this part. */
-                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
-
-                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                               IWL_DEBUG_INFO(trans,
-                                       "Tx queue %d requesting wakeup,"
-                                       " GP1 = 0x%x\n", txq_id, reg);
-                               iwl_set_bit(trans, CSR_GP_CNTRL,
-                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                               return;
-                       }
-
-                       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-                                    txq->q.write_ptr | (txq_id << 8));
-
-               /*
-                * else not in power-save mode,
-                * uCode will never sleep when we're
-                * trying to tx (during RFKILL, we're not trying to tx).
-                */
-               } else
-                       iwl_write32(trans, HBUS_TARG_WRPTR,
-                                   txq->q.write_ptr | (txq_id << 8));
-       }
-       txq->need_update = 0;
-}
-
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-       dma_addr_t addr = get_unaligned_le32(&tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               addr |=
-               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
-
-       return addr;
-}
-
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-       return le16_to_cpu(tb->hi_n_len) >> 4;
-}
-
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
-                                 dma_addr_t addr, u16 len)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-       u16 hi_n_len = len << 4;
-
-       put_unaligned_le32(addr, &tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
-
-       tb->hi_n_len = cpu_to_le16(hi_n_len);
-
-       tfd->num_tbs = idx + 1;
-}
-
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
-{
-       return tfd->num_tbs & 0x1f;
-}
-
-static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
-                    struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
-{
-       int i;
-       int num_tbs;
-
-       /* Sanity check on number of chunks */
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
-               /* @todo issue fatal error, it is quite serious situation */
-               return;
-       }
-
-       /* Unmap tx_cmd */
-       if (num_tbs)
-               dma_unmap_single(trans->dev,
-                               dma_unmap_addr(meta, mapping),
-                               dma_unmap_len(meta, len),
-                               DMA_BIDIRECTIONAL);
-
-       /* Unmap chunks, if any. */
-       for (i = 1; i < num_tbs; i++)
-               dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i),
-                               iwl_tfd_tb_get_len(tfd, i), dma_dir);
-
-       tfd->num_tbs = 0;
-}
-
-/**
- * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @trans - transport private data
- * @txq - tx queue
- * @dma_dir - the direction of the DMA mapping
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                        enum dma_data_direction dma_dir)
-{
-       struct iwl_tfd *tfd_tmp = txq->tfds;
-
-       /* rd_ptr is bounded by n_bd and idx is bounded by n_window */
-       int rd_ptr = txq->q.read_ptr;
-       int idx = get_cmd_index(&txq->q, rd_ptr);
-
-       lockdep_assert_held(&txq->lock);
-
-       /* We have only q->n_window txq->entries, but we use q->n_bd tfds */
-       iwlagn_unmap_tfd(trans, &txq->entries[idx].meta,
-                        &tfd_tmp[rd_ptr], dma_dir);
-
-       /* free SKB */
-       if (txq->entries) {
-               struct sk_buff *skb;
-
-               skb = txq->entries[idx].skb;
-
-               /* Can be called from irqs-disabled context
-                * If skb is not NULL, it means that the whole queue is being
-                * freed and that the queue is not empty - free the skb
-                */
-               if (skb) {
-                       iwl_op_mode_free_skb(trans->op_mode, skb);
-                       txq->entries[idx].skb = NULL;
-               }
-       }
-}
-
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len,
-                                u8 reset)
-{
-       struct iwl_queue *q;
-       struct iwl_tfd *tfd, *tfd_tmp;
-       u32 num_tbs;
-
-       q = &txq->q;
-       tfd_tmp = txq->tfds;
-       tfd = &tfd_tmp[q->write_ptr];
-
-       if (reset)
-               memset(tfd, 0, sizeof(*tfd));
-
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       /* Each TFD can point to a maximum 20 Tx buffers */
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(trans, "Error can not send more than %d chunks\n",
-                         IWL_NUM_OF_TBS);
-               return -EINVAL;
-       }
-
-       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
-               return -EINVAL;
-
-       if (unlikely(addr & ~IWL_TX_DMA_MASK))
-               IWL_ERR(trans, "Unaligned address = %llx\n",
-                         (unsigned long long)addr);
-
-       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
-
-       return 0;
-}
-
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
- * DMA services
- *
- * Theory of operation
- *
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
- * of buffer descriptors, each of which points to one or more data buffers for
- * the device to read from or fill.  Driver and device exchange status of each
- * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
- * entries in each circular buffer, to protect against confusing empty and full
- * queue states.
- *
- * The device reads or writes the data in the queues via the device's several
- * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- ***************************************************/
-
-int iwl_queue_space(const struct iwl_queue *q)
-{
-       int s = q->read_ptr - q->write_ptr;
-
-       if (q->read_ptr > q->write_ptr)
-               s -= q->n_bd;
-
-       if (s <= 0)
-               s += q->n_window;
-       /* keep some reserve to not confuse empty and full situations */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
-}
-
-/**
- * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
- */
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
-{
-       q->n_bd = count;
-       q->n_window = slots_num;
-       q->id = id;
-
-       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-        * and iwl_queue_dec_wrap are broken. */
-       if (WARN_ON(!is_power_of_2(count)))
-               return -EINVAL;
-
-       /* slots_num must be power-of-two size, otherwise
-        * get_cmd_index is broken. */
-       if (WARN_ON(!is_power_of_2(slots_num)))
-               return -EINVAL;
-
-       q->low_mark = q->n_window / 4;
-       if (q->low_mark < 4)
-               q->low_mark = 4;
-
-       q->high_mark = q->n_window / 8;
-       if (q->high_mark < 2)
-               q->high_mark = 2;
-
-       q->write_ptr = q->read_ptr = 0;
-
-       return 0;
-}
-
-static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
-                                         struct iwl_tx_queue *txq)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
-       int txq_id = txq->q.id;
-       int read_ptr = txq->q.read_ptr;
-       u8 sta_id = 0;
-       __le16 bc_ent;
-       struct iwl_tx_cmd *tx_cmd =
-               (void *)txq->entries[txq->q.read_ptr].cmd->payload;
-
-       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       if (txq_id != trans_pcie->cmd_queue)
-               sta_id = tx_cmd->sta_id;
-
-       bc_ent = cpu_to_le16(1 | (sta_id << 12));
-       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
-
-       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
-}
-
-static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid,
-                                       u16 txq_id)
-{
-       u32 tbl_dw_addr;
-       u32 tbl_dw;
-       u16 scd_q2ratid;
-
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
-
-       tbl_dw_addr = trans_pcie->scd_base_addr +
-                       SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
-
-       tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
-
-       if (txq_id & 0x1)
-               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
-       else
-               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
-
-       iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
-
-       return 0;
-}
-
-static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id)
-{
-       /* Simply stop the queue, but don't change any configuration;
-        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-       iwl_write_prph(trans,
-               SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
-void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
-                               int txq_id, u32 index)
-{
-       IWL_DEBUG_TX_QUEUES(trans, "Q %d  WrPtr: %d\n", txq_id, index & 0xff);
-       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-                       (index & 0xff) | (txq_id << 8));
-       iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), index);
-}
-
-void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
-                                  struct iwl_tx_queue *txq,
-                                  int tx_fifo_id, bool active)
-{
-       int txq_id = txq->q.id;
-
-       iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
-                       (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                       (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
-                       (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
-                       SCD_QUEUE_STTS_REG_MSK);
-
-       if (active)
-               IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d\n",
-                                   txq_id, tx_fifo_id);
-       else
-               IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
-}
-
-void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int txq_id, int fifo,
-                                int sta_id, int tid, int frame_limit, u16 ssn)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
-       u16 ra_tid = BUILD_RAxTID(sta_id, tid);
-
-       if (test_and_set_bit(txq_id, trans_pcie->queue_used))
-               WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Stop this Tx queue before configuring it */
-       iwlagn_tx_queue_stop_scheduler(trans, txq_id);
-
-       /* Map receiver-address / traffic-ID to this queue */
-       iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);
-
-       /* Set this queue as a chain-building queue */
-       iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
-
-       /* enable aggregations for the queue */
-       iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-
-       /* Place first TFD at index corresponding to start sequence number.
-        * Assumes that ssn_idx is valid (!= 0xFFF) */
-       trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
-       trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
-       iwl_trans_set_wr_ptrs(trans, txq_id, ssn);
-
-       /* Set up Tx window size and frame limit for this queue */
-       iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-                       SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
-                       ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                       ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id));
-
-       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
-                                     fifo, true);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
-               WARN_ONCE(1, "queue %d not used", txq_id);
-               return;
-       }
-
-       iwlagn_tx_queue_stop_scheduler(trans, txq_id);
-
-       iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-
-       trans_pcie->txq[txq_id].q.read_ptr = 0;
-       trans_pcie->txq[txq_id].q.write_ptr = 0;
-       iwl_trans_set_wr_ptrs(trans, txq_id, 0);
-
-       iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, BIT(txq_id));
-
-       iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
-                                     0, false);
-}
-
-/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
-
-/**
- * iwl_enqueue_hcmd - enqueue a uCode command
- * @priv: device private data point
- * @cmd: a point to the ucode command structure
- *
- * The function returns < 0 values to indicate the operation is
- * failed. On success, it turns the index (> 0) of command in the
- * command queue.
- */
-static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-       struct iwl_queue *q = &txq->q;
-       struct iwl_device_cmd *out_cmd;
-       struct iwl_cmd_meta *out_meta;
-       dma_addr_t phys_addr;
-       u32 idx;
-       u16 copy_size, cmd_size;
-       bool had_nocopy = false;
-       int i;
-       u8 *cmd_dest;
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-       const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
-       int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
-       int trace_idx;
-#endif
-
-       copy_size = sizeof(out_cmd->hdr);
-       cmd_size = sizeof(out_cmd->hdr);
-
-       /* need one for the header if the first is NOCOPY */
-       BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
-
-       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-               if (!cmd->len[i])
-                       continue;
-               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
-                       had_nocopy = true;
-               } else {
-                       /* NOCOPY must not be followed by normal! */
-                       if (WARN_ON(had_nocopy))
-                               return -EINVAL;
-                       copy_size += cmd->len[i];
-               }
-               cmd_size += cmd->len[i];
-       }
-
-       /*
-        * If any of the command structures end up being larger than
-        * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
-        * allocated into separate TFDs, then we will need to
-        * increase the size of the buffers.
-        */
-       if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
-               return -EINVAL;
-
-       spin_lock_bh(&txq->lock);
-
-       if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
-               spin_unlock_bh(&txq->lock);
-
-               IWL_ERR(trans, "No space in command queue\n");
-               iwl_op_mode_cmd_queue_full(trans->op_mode);
-               return -ENOSPC;
-       }
-
-       idx = get_cmd_index(q, q->write_ptr);
-       out_cmd = txq->entries[idx].cmd;
-       out_meta = &txq->entries[idx].meta;
-
-       memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
-       if (cmd->flags & CMD_WANT_SKB)
-               out_meta->source = cmd;
-
-       /* set up the header */
-
-       out_cmd->hdr.cmd = cmd->id;
-       out_cmd->hdr.flags = 0;
-       out_cmd->hdr.sequence =
-               cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) |
-                                        INDEX_TO_SEQ(q->write_ptr));
-
-       /* and copy the data that needs to be copied */
-
-       cmd_dest = out_cmd->payload;
-       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-               if (!cmd->len[i])
-                       continue;
-               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
-                       break;
-               memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
-               cmd_dest += cmd->len[i];
-       }
-
-       IWL_DEBUG_HC(trans,
-               "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
-               trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
-               out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
-               q->write_ptr, idx, trans_pcie->cmd_queue);
-
-       phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
-                               DMA_BIDIRECTIONAL);
-       if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
-               idx = -ENOMEM;
-               goto out;
-       }
-
-       dma_unmap_addr_set(out_meta, mapping, phys_addr);
-       dma_unmap_len_set(out_meta, len, copy_size);
-
-       iwlagn_txq_attach_buf_to_tfd(trans, txq,
-                                       phys_addr, copy_size, 1);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-       trace_bufs[0] = &out_cmd->hdr;
-       trace_lens[0] = copy_size;
-       trace_idx = 1;
-#endif
-
-       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
-               if (!cmd->len[i])
-                       continue;
-               if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
-                       continue;
-               phys_addr = dma_map_single(trans->dev,
-                                          (void *)cmd->data[i],
-                                          cmd->len[i], DMA_BIDIRECTIONAL);
-               if (dma_mapping_error(trans->dev, phys_addr)) {
-                       iwlagn_unmap_tfd(trans, out_meta,
-                                        &txq->tfds[q->write_ptr],
-                                        DMA_BIDIRECTIONAL);
-                       idx = -ENOMEM;
-                       goto out;
-               }
-
-               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-                                            cmd->len[i], 0);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-               trace_bufs[trace_idx] = cmd->data[i];
-               trace_lens[trace_idx] = cmd->len[i];
-               trace_idx++;
-#endif
-       }
-
-       out_meta->flags = cmd->flags;
-
-       txq->need_update = 1;
-
-       /* check that tracing gets all possible blocks */
-       BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
-#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
-       trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
-                              trace_bufs[0], trace_lens[0],
-                              trace_bufs[1], trace_lens[1],
-                              trace_bufs[2], trace_lens[2]);
-#endif
-
-       /* start timer if queue currently empty */
-       if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-
-       /* Increment and update queue's write index */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(trans, txq);
-
- out:
-       spin_unlock_bh(&txq->lock);
-       return idx;
-}
-
-static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
-                                     struct iwl_tx_queue *txq)
-{
-       if (!trans_pcie->wd_timeout)
-               return;
-
-       /*
-        * if empty delete timer, otherwise move timer forward
-        * since we're making progress on this queue
-        */
-       if (txq->q.read_ptr == txq->q.write_ptr)
-               del_timer(&txq->stuck_timer);
-       else
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-}
-
-/**
- * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms.  If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
-                                  int idx)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       int nfreed = 0;
-
-       lockdep_assert_held(&txq->lock);
-
-       if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
-               IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
-                         "index %d is out of range [0-%d] %d %d.\n", __func__,
-                         txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr);
-               return;
-       }
-
-       for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-               if (nfreed++ > 0) {
-                       IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx,
-                                       q->write_ptr, q->read_ptr);
-                       iwl_op_mode_nic_error(trans->op_mode);
-               }
-
-       }
-
-       iwl_queue_progress(trans_pcie, txq);
-}
-
-/**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- * @handler_status: return value of the handler of the command
- *     (put in setup_rx_handlers)
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
-                        int handler_status)
-{
-       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);
-       int cmd_index;
-       struct iwl_device_cmd *cmd;
-       struct iwl_cmd_meta *meta;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-
-       /* If a Tx command is being handled and it isn't in the actual
-        * command queue then there a command routing bug has been introduced
-        * in the queue management code. */
-       if (WARN(txq_id != trans_pcie->cmd_queue,
-                "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
-                 txq_id, trans_pcie->cmd_queue, sequence,
-                 trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
-                 trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
-               iwl_print_hex_error(trans, pkt, 32);
-               return;
-       }
-
-       spin_lock(&txq->lock);
-
-       cmd_index = get_cmd_index(&txq->q, index);
-       cmd = txq->entries[cmd_index].cmd;
-       meta = &txq->entries[cmd_index].meta;
-
-       iwlagn_unmap_tfd(trans, meta, &txq->tfds[index],
-                        DMA_BIDIRECTIONAL);
-
-       /* Input error checking is done when commands are added to queue. */
-       if (meta->flags & CMD_WANT_SKB) {
-               struct page *p = rxb_steal_page(rxb);
-
-               meta->source->resp_pkt = pkt;
-               meta->source->_rx_page_addr = (unsigned long)page_address(p);
-               meta->source->_rx_page_order = trans_pcie->rx_page_order;
-               meta->source->handler_status = handler_status;
-       }
-
-       iwl_hcmd_queue_reclaim(trans, txq_id, index);
-
-       if (!(meta->flags & CMD_ASYNC)) {
-               if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
-                       IWL_WARN(trans,
-                                "HCMD_ACTIVE already clear for command %s\n",
-                                trans_pcie_get_cmd_string(trans_pcie,
-                                                          cmd->hdr.cmd));
-               }
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-               IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
-                              trans_pcie_get_cmd_string(trans_pcie,
-                                                        cmd->hdr.cmd));
-               wake_up(&trans->wait_command_queue);
-       }
-
-       meta->flags = 0;
-
-       spin_unlock(&txq->lock);
-}
-
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-
-static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int ret;
-
-       /* An asynchronous command can not expect an SKB to be set. */
-       if (WARN_ON(cmd->flags & CMD_WANT_SKB))
-               return -EINVAL;
-
-
-       ret = iwl_enqueue_hcmd(trans, cmd);
-       if (ret < 0) {
-               IWL_ERR(trans,
-                       "Error sending %s: enqueue_hcmd failed: %d\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
-               return ret;
-       }
-       return 0;
-}
-
-static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int cmd_idx;
-       int ret;
-
-       IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
-                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-
-       if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
-                                    &trans_pcie->status))) {
-               IWL_ERR(trans, "Command %s: a command is already active!\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-               return -EIO;
-       }
-
-       IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
-                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-
-       cmd_idx = iwl_enqueue_hcmd(trans, cmd);
-       if (cmd_idx < 0) {
-               ret = cmd_idx;
-               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-               IWL_ERR(trans,
-                       "Error sending %s: enqueue_hcmd failed: %d\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
-               return ret;
-       }
-
-       ret = wait_event_timeout(trans->wait_command_queue,
-                       !test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status),
-                       HOST_COMPLETE_TIMEOUT);
-       if (!ret) {
-               if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
-                       struct iwl_tx_queue *txq =
-                               &trans_pcie->txq[trans_pcie->cmd_queue];
-                       struct iwl_queue *q = &txq->q;
-
-                       IWL_ERR(trans,
-                               "Error sending %s: time out after %dms.\n",
-                               trans_pcie_get_cmd_string(trans_pcie, cmd->id),
-                               jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
-
-                       IWL_ERR(trans,
-                               "Current CMD queue read_ptr %d write_ptr %d\n",
-                               q->read_ptr, q->write_ptr);
-
-                       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-                       IWL_DEBUG_INFO(trans,
-                                      "Clearing HCMD_ACTIVE for command %s\n",
-                                      trans_pcie_get_cmd_string(trans_pcie,
-                                                                cmd->id));
-                       ret = -ETIMEDOUT;
-                       goto cancel;
-               }
-       }
-
-       if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
-               IWL_ERR(trans, "Error: Response NULL in '%s'\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
-               ret = -EIO;
-               goto cancel;
-       }
-
-       return 0;
-
-cancel:
-       if (cmd->flags & CMD_WANT_SKB) {
-               /*
-                * Cancel the CMD_WANT_SKB flag for the cmd in the
-                * TX cmd queue. Otherwise in case the cmd comes
-                * in later, it will possibly set an invalid
-                * address (cmd->meta.source).
-                */
-               trans_pcie->txq[trans_pcie->cmd_queue].
-                       entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB;
-       }
-
-       if (cmd->resp_pkt) {
-               iwl_free_resp(cmd);
-               cmd->resp_pkt = NULL;
-       }
-
-       return ret;
-}
-
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
-{
-       if (cmd->flags & CMD_ASYNC)
-               return iwl_send_cmd_async(trans, cmd);
-
-       return iwl_send_cmd_sync(trans, cmd);
-}
-
-/* Frees buffers until index _not_ inclusive */
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-                        struct sk_buff_head *skbs)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       int last_to_free;
-       int freed = 0;
-
-       /* This function is not meant to release cmd queue*/
-       if (WARN_ON(txq_id == trans_pcie->cmd_queue))
-               return 0;
-
-       lockdep_assert_held(&txq->lock);
-
-       /*Since we free until index _not_ inclusive, the one before index is
-        * the last we will free. This one must be used */
-       last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
-
-       if ((index >= q->n_bd) ||
-          (iwl_queue_used(q, last_to_free) == 0)) {
-               IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), "
-                         "last_to_free %d is out of range [0-%d] %d %d.\n",
-                         __func__, txq_id, last_to_free, q->n_bd,
-                         q->write_ptr, q->read_ptr);
-               return 0;
-       }
-
-       if (WARN_ON(!skb_queue_empty(skbs)))
-               return 0;
-
-       for (;
-            q->read_ptr != index;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-               if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
-                       continue;
-
-               __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
-
-               txq->entries[txq->q.read_ptr].skb = NULL;
-
-               iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
-
-               iwlagn_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
-               freed++;
-       }
-
-       iwl_queue_progress(trans_pcie, txq);
-
-       return freed;
-}
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
deleted file mode 100644 (file)
index 79c6b91..0000000
+++ /dev/null
@@ -1,2193 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2012 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.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
-#include <linux/interrupt.h>
-#include <linux/debugfs.h>
-#include <linux/sched.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include "iwl-drv.h"
-#include "iwl-trans.h"
-#include "iwl-trans-pcie-int.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-eeprom.h"
-#include "iwl-agn-hw.h"
-/* FIXME: need to abstract out TX command (once we know what it looks like) */
-#include "iwl-commands.h"
-
-#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
-#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)      \
-       (((1<<trans->cfg->base_params->num_of_queues) - 1) &\
-       (~(1<<(trans_pcie)->cmd_queue)))
-
-static int iwl_trans_rx_alloc(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct device *dev = trans->dev;
-
-       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
-
-       spin_lock_init(&rxq->lock);
-
-       if (WARN_ON(rxq->bd || rxq->rb_stts))
-               return -EINVAL;
-
-       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                     &rxq->bd_dma, GFP_KERNEL);
-       if (!rxq->bd)
-               goto err_bd;
-
-       /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                          &rxq->rb_stts_dma, GFP_KERNEL);
-       if (!rxq->rb_stts)
-               goto err_rb_stts;
-
-       return 0;
-
-err_rb_stts:
-       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                       rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-err_bd:
-       return -ENOMEM;
-}
-
-static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       int i;
-
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       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].page != NULL) {
-                       dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << trans_pcie->rx_page_order,
-                               DMA_FROM_DEVICE);
-                       __free_pages(rxq->pool[i].page,
-                                    trans_pcie->rx_page_order);
-                       rxq->pool[i].page = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-}
-
-static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
-                                struct iwl_rx_queue *rxq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 rb_size;
-       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-       u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-       if (trans_pcie->rx_buf_size_8k)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          (u32)(rxq->bd_dma >> 8));
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          rxq->rb_stts_dma >> 4);
-
-       /* Enable Rx DMA
-        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-        *      the credit mechanism in 5000 HW RX FIFO
-        * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
-        * RB timeout 0x10
-        * 256 RBDs
-        */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          rb_size|
-                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-       /* Set interrupt coalescing timer to default (2048 usecs) */
-       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-}
-
-static int iwl_rx_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-       int i, err;
-       unsigned long flags;
-
-       if (!rxq->bd) {
-               err = iwl_trans_rx_alloc(trans);
-               if (err)
-                       return err;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-
-       iwl_trans_rxq_free_rx_bufs(trans);
-
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
-               rxq->queue[i] = NULL;
-
-       /* 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->write_actual = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       iwlagn_rx_replenish(trans);
-
-       iwl_trans_rx_hw_init(trans, rxq);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       rxq->need_update = 1;
-       iwl_rx_queue_update_write_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       return 0;
-}
-
-static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-       unsigned long flags;
-
-       /*if rxq->bd is NULL, it means that nothing has been allocated,
-        * exit now */
-       if (!rxq->bd) {
-               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
-               return;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       iwl_trans_rxq_free_rx_bufs(trans);
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-
-       if (rxq->rb_stts)
-               dma_free_coherent(trans->dev,
-                                 sizeof(struct iwl_rb_status),
-                                 rxq->rb_stts, rxq->rb_stts_dma);
-       else
-               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
-       rxq->rb_stts = NULL;
-}
-
-static int iwl_trans_rx_stop(struct iwl_trans *trans)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
-                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-}
-
-static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
-                                   struct iwl_dma_ptr *ptr, size_t size)
-{
-       if (WARN_ON(ptr->addr))
-               return -EINVAL;
-
-       ptr->addr = dma_alloc_coherent(trans->dev, size,
-                                      &ptr->dma, GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
-                                   struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
-static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
-{
-       struct iwl_tx_queue *txq = (void *)data;
-       struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
-       struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
-
-       spin_lock(&txq->lock);
-       /* check if triggered erroneously */
-       if (txq->q.read_ptr == txq->q.write_ptr) {
-               spin_unlock(&txq->lock);
-               return;
-       }
-       spin_unlock(&txq->lock);
-
-
-       IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
-               jiffies_to_msecs(trans_pcie->wd_timeout));
-       IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
-               txq->q.read_ptr, txq->q.write_ptr);
-       IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
-               iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq->q.id))
-                                       & (TFD_QUEUE_SIZE_MAX - 1),
-               iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq->q.id)));
-
-       iwl_op_mode_nic_error(trans->op_mode);
-}
-
-static int iwl_trans_txq_alloc(struct iwl_trans *trans,
-                               struct iwl_tx_queue *txq, int slots_num,
-                               u32 txq_id)
-{
-       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
-       int i;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (WARN_ON(txq->entries || txq->tfds))
-               return -EINVAL;
-
-       setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
-                   (unsigned long)txq);
-       txq->trans_pcie = trans_pcie;
-
-       txq->q.n_window = slots_num;
-
-       txq->entries = kcalloc(slots_num,
-                              sizeof(struct iwl_pcie_tx_queue_entry),
-                              GFP_KERNEL);
-
-       if (!txq->entries)
-               goto error;
-
-       if (txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < slots_num; i++) {
-                       txq->entries[i].cmd =
-                               kmalloc(sizeof(struct iwl_device_cmd),
-                                       GFP_KERNEL);
-                       if (!txq->entries[i].cmd)
-                               goto error;
-               }
-
-       /* Circular buffer of transmit frame descriptors (TFDs),
-        * shared with device */
-       txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
-                                      &txq->q.dma_addr, GFP_KERNEL);
-       if (!txq->tfds) {
-               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
-               goto error;
-       }
-       txq->q.id = txq_id;
-
-       return 0;
-error:
-       if (txq->entries && txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < slots_num; i++)
-                       kfree(txq->entries[i].cmd);
-       kfree(txq->entries);
-       txq->entries = NULL;
-
-       return -ENOMEM;
-
-}
-
-static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                             int slots_num, u32 txq_id)
-{
-       int ret;
-
-       txq->need_update = 0;
-
-       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-       /* Initialize queue's high/low-water marks, and head/tail indexes */
-       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
-                       txq_id);
-       if (ret)
-               return ret;
-
-       spin_lock_init(&txq->lock);
-
-       /*
-        * Tell nic where to find circular buffer of Tx Frame Descriptors for
-        * given Tx queue, and enable the DMA channel used for that queue.
-        * Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       return 0;
-}
-
-/**
- * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
- */
-static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       enum dma_data_direction dma_dir;
-
-       if (!q->n_bd)
-               return;
-
-       /* In the command queue, all the TBs are mapped as BIDI
-        * so unmap them as such.
-        */
-       if (txq_id == trans_pcie->cmd_queue)
-               dma_dir = DMA_BIDIRECTIONAL;
-       else
-               dma_dir = DMA_TO_DEVICE;
-
-       spin_lock_bh(&txq->lock);
-       while (q->write_ptr != q->read_ptr) {
-               iwlagn_txq_free_tfd(trans, txq, dma_dir);
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-       spin_unlock_bh(&txq->lock);
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct device *dev = trans->dev;
-       int i;
-       if (WARN_ON(!txq))
-               return;
-
-       iwl_tx_queue_unmap(trans, txq_id);
-
-       /* De-alloc array of command/tx buffers */
-
-       if (txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < txq->q.n_window; i++)
-                       kfree(txq->entries[i].cmd);
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd) {
-               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
-                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
-       }
-
-       kfree(txq->entries);
-       txq->entries = NULL;
-
-       del_timer_sync(&txq->stuck_timer);
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_trans_tx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
-{
-       int txq_id;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* Tx queues */
-       if (trans_pcie->txq) {
-               for (txq_id = 0;
-                    txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
-                       iwl_tx_queue_free(trans, txq_id);
-       }
-
-       kfree(trans_pcie->txq);
-       trans_pcie->txq = NULL;
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
-}
-
-/**
- * iwl_trans_tx_alloc - allocate TX context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-static int iwl_trans_tx_alloc(struct iwl_trans *trans)
-{
-       int ret;
-       int txq_id, slots_num;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
-                       sizeof(struct iwlagn_scd_bc_tbl);
-
-       /*It is not allowed to alloc twice, so warn when this happens.
-        * We cannot rely on the previous allocation, so free and fail */
-       if (WARN_ON(trans_pcie->txq)) {
-               ret = -EINVAL;
-               goto error;
-       }
-
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
-                                  scd_bc_tbls_size);
-       if (ret) {
-               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
-               goto error;
-       }
-
-       /* Alloc keep-warm buffer */
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
-       if (ret) {
-               IWL_ERR(trans, "Keep Warm allocation failed\n");
-               goto error;
-       }
-
-       trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
-                                 sizeof(struct iwl_tx_queue), GFP_KERNEL);
-       if (!trans_pcie->txq) {
-               IWL_ERR(trans, "Not enough memory for txq\n");
-               ret = ENOMEM;
-               goto error;
-       }
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++) {
-               slots_num = (txq_id == trans_pcie->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
-                                         slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       iwl_trans_pcie_tx_free(trans);
-
-       return ret;
-}
-static int iwl_tx_init(struct iwl_trans *trans)
-{
-       int ret;
-       int txq_id, slots_num;
-       unsigned long flags;
-       bool alloc = false;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (!trans_pcie->txq) {
-               ret = iwl_trans_tx_alloc(trans);
-               if (ret)
-                       goto error;
-               alloc = true;
-       }
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       iwl_write_prph(trans, SCD_TXFACT, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
-                          trans_pcie->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++) {
-               slots_num = (txq_id == trans_pcie->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
-                                        slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-error:
-       /*Upon error, free only if we allocated something */
-       if (alloc)
-               iwl_trans_pcie_tx_free(trans);
-       return ret;
-}
-
-static void iwl_set_pwr_vmain(struct iwl_trans *trans)
-{
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
-
-               if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
-                       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
-
-       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
-                              APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-                              ~APMG_PS_CTRL_MSK_PWR_SRC);
-}
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT  0x041
-#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
-#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
-
-static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
-{
-       int pos;
-       u16 pci_lnk_ctl;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       struct pci_dev *pci_dev = trans_pcie->pci_dev;
-
-       pos = pci_pcie_cap(pci_dev);
-       pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
-       return pci_lnk_ctl;
-}
-
-static void iwl_apm_config(struct iwl_trans *trans)
-{
-       /*
-        * HW bug W/A for instability in PCIe bus L0S->L1 transition.
-        * Check if BIOS (or OS) enabled L1-ASPM on this device.
-        * If so (likely), disable L0S, so device moves directly L0->L1;
-        *    costs negligible amount of power savings.
-        * If not (unlikely), enable L0S, so there is at least some
-        *    power savings, even without L1.
-        */
-       u16 lctl = iwl_pciexp_link_ctrl(trans);
-
-       if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
-                               PCI_CFG_LINK_CTRL_VAL_L1_EN) {
-               /* L1-ASPM enabled; disable(!) L0S */
-               iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_printk(KERN_INFO, trans->dev,
-                          "L1 Enabled; Disabling L0S\n");
-       } else {
-               /* L1-ASPM disabled; enable(!) L0S */
-               iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_printk(KERN_INFO, trans->dev,
-                          "L1 Disabled; Enabling L0S\n");
-       }
-       trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
-}
-
-/*
- * 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
- */
-static int iwl_apm_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int ret = 0;
-       IWL_DEBUG_INFO(trans, "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(trans, 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(trans, 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(trans, 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
-        */
-       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-                                   CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
-
-       iwl_apm_config(trans);
-
-       /* Configure analog phase-lock-loop before activating to D0A */
-       if (trans->cfg->base_params->pll_cfg_val)
-               iwl_set_bit(trans, CSR_ANA_PLL_CFG,
-                           trans->cfg->base_params->pll_cfg_val);
-
-       /*
-        * Set "initialization complete" bit to move adapter from
-        * D0U* --> D0A* (powered-up active) state.
-        */
-       iwl_set_bit(trans, 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(trans, 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(trans, "Failed to init the card\n");
-               goto out;
-       }
-
-       /*
-        * Enable DMA clock and wait for it to stabilize.
-        *
-        * 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.
-        */
-       iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-       udelay(20);
-
-       /* Disable L1-Active */
-       iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-       set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-
-out:
-       return ret;
-}
-
-static int iwl_apm_stop_master(struct iwl_trans *trans)
-{
-       int ret = 0;
-
-       /* stop device's busmaster DMA activity */
-       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
-       ret = iwl_poll_bit(trans, CSR_RESET,
-                       CSR_RESET_REG_FLAG_MASTER_DISABLED,
-                       CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-       if (ret)
-               IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
-
-       IWL_DEBUG_INFO(trans, "stop master\n");
-
-       return ret;
-}
-
-static void iwl_apm_stop(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
-
-       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-
-       /* Stop device's DMA activity */
-       iwl_apm_stop_master(trans);
-
-       /* Reset the entire device */
-       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
-       udelay(10);
-
-       /*
-        * Clear "initialization complete" bit to move adapter from
-        * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
-        */
-       iwl_clear_bit(trans, CSR_GP_CNTRL,
-                     CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-}
-
-static int iwl_nic_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
-
-       /* nic_init */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_apm_init(trans);
-
-       /* Set interrupt coalescing calibration timer to default (512 usecs) */
-       iwl_write8(trans, CSR_INT_COALESCING,
-               IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       iwl_set_pwr_vmain(trans);
-
-       iwl_op_mode_nic_config(trans->op_mode);
-
-#ifndef CONFIG_IWLWIFI_IDI
-       /* Allocate the RX queue, or reset if it is already allocated */
-       iwl_rx_init(trans);
-#endif
-
-       /* Allocate or reset and init all Tx and Command queues */
-       if (iwl_tx_init(trans))
-               return -ENOMEM;
-
-       if (trans->cfg->base_params->shadow_reg_enable) {
-               /* enable shadow regs in HW */
-               iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
-                       0x800FFFFF);
-       }
-
-       return 0;
-}
-
-#define HW_READY_TIMEOUT (50)
-
-/* Note: returns poll_bit return value, which is >= 0 if success */
-static int iwl_set_hw_ready(struct iwl_trans *trans)
-{
-       int ret;
-
-       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
-
-       /* See if we got it */
-       ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
-                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-                               HW_READY_TIMEOUT);
-
-       IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
-       return ret;
-}
-
-/* Note: returns standard 0/-ERROR code */
-static int iwl_prepare_card_hw(struct iwl_trans *trans)
-{
-       int ret;
-
-       IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
-
-       ret = iwl_set_hw_ready(trans);
-       /* If the card is ready, exit 0 */
-       if (ret >= 0)
-               return 0;
-
-       /* If HW is not ready, prepare the conditions to check again */
-       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
-                       CSR_HW_IF_CONFIG_REG_PREPARE);
-
-       ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
-                       ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
-                       CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
-
-       if (ret < 0)
-               return ret;
-
-       /* HW should be ready by now, check again. */
-       ret = iwl_set_hw_ready(trans);
-       if (ret >= 0)
-               return 0;
-       return ret;
-}
-
-/*
- * ucode
- */
-static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
-                           const struct fw_desc *section)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       dma_addr_t phy_addr = section->p_addr;
-       u32 byte_cnt = section->len;
-       u32 dst_addr = section->offset;
-       int ret;
-
-       trans_pcie->ucode_write_complete = false;
-
-       iwl_write_direct32(trans,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
-
-       iwl_write_direct32(trans,
-               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
-
-       iwl_write_direct32(trans,
-               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
-               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
-
-       iwl_write_direct32(trans,
-               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-               (iwl_get_dma_hi_addr(phy_addr)
-                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
-
-       iwl_write_direct32(trans,
-               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
-               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
-
-       iwl_write_direct32(trans,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
-               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
-
-       IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
-                    section_num);
-       ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
-                                trans_pcie->ucode_write_complete, 5 * HZ);
-       if (!ret) {
-               IWL_ERR(trans, "Could not load the [%d] uCode section\n",
-                       section_num);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int iwl_load_given_ucode(struct iwl_trans *trans,
-                               const struct fw_img *image)
-{
-       int ret = 0;
-               int i;
-
-               for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
-                       if (!image->sec[i].p_addr)
-                               break;
-
-                       ret = iwl_load_section(trans, i, &image->sec[i]);
-                       if (ret)
-                               return ret;
-               }
-
-       /* Remove all resets to allow NIC to operate */
-       iwl_write32(trans, CSR_RESET, 0);
-
-       return 0;
-}
-
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-                                  const struct fw_img *fw)
-{
-       int ret;
-       bool hw_rfkill;
-
-       /* This may fail if AMT took ownership of the device */
-       if (iwl_prepare_card_hw(trans)) {
-               IWL_WARN(trans, "Exit HW not ready\n");
-               return -EIO;
-       }
-
-       iwl_enable_rfkill_int(trans);
-
-       /* If platform's RF_KILL switch is NOT set to KILL */
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-       if (hw_rfkill)
-               return -ERFKILL;
-
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-       ret = iwl_nic_init(trans);
-       if (ret) {
-               IWL_ERR(trans, "Unable to init nic\n");
-               return ret;
-       }
-
-       /* make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-       /* clear (again), then enable host interrupts */
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-       iwl_enable_interrupts(trans);
-
-       /* really make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* Load the given image to the HW */
-       return iwl_load_given_ucode(trans, fw);
-}
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under the irq lock and with MAC access
- */
-static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-       struct iwl_trans_pcie __maybe_unused *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       lockdep_assert_held(&trans_pcie->irq_lock);
-
-       iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
-static void iwl_tx_start(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 a;
-       unsigned long flags;
-       int i, chan;
-       u32 reg_val;
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       trans_pcie->scd_base_addr =
-               iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
-       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-       /* reset conext data memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       /* reset tx status memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       for (; a < trans_pcie->scd_base_addr +
-              SCD_TRANS_TBL_OFFSET_QUEUE(
-                               trans->cfg->base_params->num_of_queues);
-              a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-
-       iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
-                      trans_pcie->scd_bc_tbls.dma >> 10);
-
-       /* The chain extension of the SCD doesn't work well. This feature is
-        * enabled by default by the HW, so we need to disable it manually.
-        */
-       iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
-
-       /* Enable DMA channel */
-       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
-               iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-       /* Update FH chicken bits */
-       reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
-       iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
-                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-       iwl_write_prph(trans, SCD_QUEUECHAIN_SEL,
-               SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie));
-       iwl_write_prph(trans, SCD_AGGR_SEL, 0);
-
-       /* initiate the queues */
-       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
-               iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0);
-               iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8));
-               iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-                               SCD_CONTEXT_QUEUE_OFFSET(i), 0);
-               iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
-                               SCD_CONTEXT_QUEUE_OFFSET(i) +
-                               sizeof(u32),
-                               ((SCD_WIN_SIZE <<
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                               ((SCD_FRAME_LIMIT <<
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-       }
-
-       iwl_write_prph(trans, SCD_INTERRUPT_MASK,
-                       IWL_MASK(0, trans->cfg->base_params->num_of_queues));
-
-       /* Activate all Tx DMA/FIFO channels */
-       iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
-
-       iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
-
-       /* make sure all queue are not stopped/used */
-       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
-       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
-
-       for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
-               int fifo = trans_pcie->setup_q_to_fifo[i];
-
-               set_bit(i, trans_pcie->queue_used);
-
-               iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
-                                             fifo, true);
-       }
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       /* Enable L1-Active */
-       iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
-{
-       iwl_reset_ict(trans);
-       iwl_tx_start(trans);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-static int iwl_trans_tx_stop(struct iwl_trans *trans)
-{
-       int ch, txq_id, ret;
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       iwl_trans_txq_set_sched(trans, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
-               iwl_write_direct32(trans,
-                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000);
-               if (ret < 0)
-                       IWL_ERR(trans, "Failing on timeout while stopping"
-                           " DMA channel %d [0x%08x]", ch,
-                           iwl_read_direct32(trans,
-                                             FH_TSSR_TX_STATUS_REG));
-       }
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
-               return 0;
-       }
-
-       /* Unmap DMA from host system and free skb's */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++)
-               iwl_tx_queue_unmap(trans, txq_id);
-
-       return 0;
-}
-
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
-{
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* tell the device to stop sending interrupts */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       /* device going down, Stop using ICT table */
-       iwl_disable_ict(trans);
-
-       /*
-        * If a HW restart happens during firmware loading,
-        * then the firmware loading might call this function
-        * and later it might be called again due to the
-        * restart. So don't process again if the device is
-        * already dead.
-        */
-       if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
-               iwl_trans_tx_stop(trans);
-#ifndef CONFIG_IWLWIFI_IDI
-               iwl_trans_rx_stop(trans);
-#endif
-               /* Power-down device's busmaster DMA clocks */
-               iwl_write_prph(trans, APMG_CLK_DIS_REG,
-                              APMG_CLK_VAL_DMA_CLK_RQT);
-               udelay(5);
-       }
-
-       /* Make sure (redundant) we've released our request to stay awake */
-       iwl_clear_bit(trans, CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-       /* Stop the device, and put it in low power state */
-       iwl_apm_stop(trans);
-
-       /* Upon stop, the APM issues an interrupt if HW RF kill is set.
-        * Clean again the interrupt here
-        */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       iwl_enable_rfkill_int(trans);
-
-       /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(trans_pcie->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-
-       cancel_work_sync(&trans_pcie->rx_replenish);
-
-       /* stop and reset the on-board processor */
-       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-       /* clear all status bits */
-       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
-       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
-       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
-       clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-}
-
-static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
-{
-       /* let the ucode operate on its own */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
-                   CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       iwl_disable_interrupts(trans);
-       iwl_clear_bit(trans, CSR_GP_CNTRL,
-                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-}
-
-static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
-                            struct iwl_device_cmd *dev_cmd, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
-       struct iwl_cmd_meta *out_meta;
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       dma_addr_t phys_addr = 0;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       u16 len, firstlen, secondlen;
-       u8 wait_write_ptr = 0;
-       __le16 fc = hdr->frame_control;
-       u8 hdr_len = ieee80211_hdrlen(fc);
-       u16 __maybe_unused wifi_seq;
-
-       txq = &trans_pcie->txq[txq_id];
-       q = &txq->q;
-
-       if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-
-       spin_lock(&txq->lock);
-
-       /* Set up driver data for this TFD */
-       txq->entries[q->write_ptr].skb = skb;
-       txq->entries[q->write_ptr].cmd = dev_cmd;
-
-       dev_cmd->hdr.cmd = REPLY_TX;
-       dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                               INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_meta = &txq->entries[q->write_ptr].meta;
-
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-       firstlen = (len + 3) & ~3;
-
-       /* Tell NIC about any 2-byte padding after MAC header */
-       if (firstlen != len)
-               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = dma_map_single(trans->dev,
-                                   &dev_cmd->hdr, firstlen,
-                                   DMA_BIDIRECTIONAL);
-       if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
-               goto out_err;
-       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       dma_unmap_len_set(out_meta, len, firstlen);
-
-       if (!ieee80211_has_morefrags(fc)) {
-               txq->need_update = 1;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       secondlen = skb->len - hdr_len;
-       if (secondlen > 0) {
-               phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
-                                          secondlen, DMA_TO_DEVICE);
-               if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
-                       dma_unmap_single(trans->dev,
-                                        dma_unmap_addr(out_meta, mapping),
-                                        dma_unmap_len(out_meta, len),
-                                        DMA_BIDIRECTIONAL);
-                       goto out_err;
-               }
-       }
-
-       /* Attach buffers to TFD */
-       iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
-       if (secondlen > 0)
-               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-                                            secondlen, 0);
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-                               offsetof(struct iwl_tx_cmd, scratch);
-
-       /* take back ownership of DMA buffer to enable update */
-       dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
-                       DMA_BIDIRECTIONAL);
-       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-                    le16_to_cpu(dev_cmd->hdr.sequence));
-       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
-
-       dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
-                       DMA_BIDIRECTIONAL);
-
-       trace_iwlwifi_dev_tx(trans->dev,
-                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &dev_cmd->hdr, firstlen,
-                            skb->data + hdr_len, secondlen);
-
-       /* start timer if queue currently empty */
-       if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(trans, txq);
-
-       /*
-        * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
-        */
-       if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr) {
-                       txq->need_update = 1;
-                       iwl_txq_update_write_ptr(trans, txq);
-               } else {
-                       iwl_stop_queue(trans, txq);
-               }
-       }
-       spin_unlock(&txq->lock);
-       return 0;
- out_err:
-       spin_unlock(&txq->lock);
-       return -1;
-}
-
-static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       int err;
-       bool hw_rfkill;
-
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
-
-       if (!trans_pcie->irq_requested) {
-               tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-                       iwl_irq_tasklet, (unsigned long)trans);
-
-               iwl_alloc_isr_ict(trans);
-
-               err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
-                       DRV_NAME, trans);
-               if (err) {
-                       IWL_ERR(trans, "Error allocating IRQ %d\n",
-                               trans_pcie->irq);
-                       goto error;
-               }
-
-               INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
-               trans_pcie->irq_requested = true;
-       }
-
-       err = iwl_prepare_card_hw(trans);
-       if (err) {
-               IWL_ERR(trans, "Error while preparing HW: %d", err);
-               goto err_free_irq;
-       }
-
-       iwl_apm_init(trans);
-
-       /* From now on, the op_mode will be kept updated about RF kill state */
-       iwl_enable_rfkill_int(trans);
-
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-       return err;
-
-err_free_irq:
-       free_irq(trans_pcie->irq, trans);
-error:
-       iwl_free_isr_ict(trans);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-       return err;
-}
-
-static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
-                                  bool op_mode_leaving)
-{
-       bool hw_rfkill;
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_apm_stop(trans);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-       if (!op_mode_leaving) {
-               /*
-                * Even if we stop the HW, we still want the RF kill
-                * interrupt
-                */
-               iwl_enable_rfkill_int(trans);
-
-               /*
-                * Check again since the RF kill state may have changed while
-                * all the interrupts were disabled, in this case we couldn't
-                * receive the RF kill interrupt and update the state in the
-                * op_mode.
-                */
-               hw_rfkill = iwl_is_rfkill_set(trans);
-               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-       }
-}
-
-static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
-                                  struct sk_buff_head *skbs)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       /* n_bd is usually 256 => n_bd - 1 = 0xff */
-       int tfd_num = ssn & (txq->q.n_bd - 1);
-       int freed = 0;
-
-       spin_lock(&txq->lock);
-
-       if (txq->q.read_ptr != tfd_num) {
-               IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
-                                  txq_id, txq->q.read_ptr, tfd_num, ssn);
-               freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
-                       iwl_wake_queue(trans, txq);
-       }
-
-       spin_unlock(&txq->lock);
-}
-
-static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
-{
-       writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
-{
-       writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
-{
-       return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
-}
-
-static void iwl_trans_pcie_configure(struct iwl_trans *trans,
-                                    const struct iwl_trans_config *trans_cfg)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       trans_pcie->cmd_queue = trans_cfg->cmd_queue;
-       if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
-               trans_pcie->n_no_reclaim_cmds = 0;
-       else
-               trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds;
-       if (trans_pcie->n_no_reclaim_cmds)
-               memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
-                      trans_pcie->n_no_reclaim_cmds * sizeof(u8));
-
-       trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
-
-       if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
-               trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
-
-       /* at least the command queue must be mapped */
-       WARN_ON(!trans_pcie->n_q_to_fifo);
-
-       memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
-              trans_pcie->n_q_to_fifo * sizeof(u8));
-
-       trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k;
-       if (trans_pcie->rx_buf_size_8k)
-               trans_pcie->rx_page_order = get_order(8 * 1024);
-       else
-               trans_pcie->rx_page_order = get_order(4 * 1024);
-
-       trans_pcie->wd_timeout =
-               msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
-
-       trans_pcie->command_names = trans_cfg->command_names;
-}
-
-void iwl_trans_pcie_free(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_trans_pcie_tx_free(trans);
-#ifndef CONFIG_IWLWIFI_IDI
-       iwl_trans_pcie_rx_free(trans);
-#endif
-       if (trans_pcie->irq_requested == true) {
-               free_irq(trans_pcie->irq, trans);
-               iwl_free_isr_ict(trans);
-       }
-
-       pci_disable_msi(trans_pcie->pci_dev);
-       iounmap(trans_pcie->hw_base);
-       pci_release_regions(trans_pcie->pci_dev);
-       pci_disable_device(trans_pcie->pci_dev);
-
-       kfree(trans);
-}
-
-static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (state)
-               set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-       else
-               clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
-{
-       return 0;
-}
-
-static int iwl_trans_pcie_resume(struct iwl_trans *trans)
-{
-       bool hw_rfkill;
-
-       iwl_enable_rfkill_int(trans);
-
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
-
-       if (!hw_rfkill)
-               iwl_enable_interrupts(trans);
-
-       return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-#define IWL_FLUSH_WAIT_MS      2000
-
-static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       int cnt;
-       unsigned long now = jiffies;
-       int ret = 0;
-
-       /* waiting for all the tx frames complete might take a while */
-       for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
-               if (cnt == trans_pcie->cmd_queue)
-                       continue;
-               txq = &trans_pcie->txq[cnt];
-               q = &txq->q;
-               while (q->read_ptr != q->write_ptr && !time_after(jiffies,
-                      now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
-                       msleep(1);
-
-               if (q->read_ptr != q->write_ptr) {
-                       IWL_ERR(trans, "fail to flush all tx fifo queues\n");
-                       ret = -ETIMEDOUT;
-                       break;
-               }
-       }
-       return ret;
-}
-
-static const char *get_fh_string(int cmd)
-{
-#define IWL_CMD(x) case x: return #x
-       switch (cmd) {
-       IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
-       IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
-       IWL_CMD(FH_RSCSR_CHNL0_WPTR);
-       IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
-       IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
-       IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
-       IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
-       IWL_CMD(FH_TSSR_TX_STATUS_REG);
-       IWL_CMD(FH_TSSR_TX_ERROR_REG);
-       default:
-               return "UNKNOWN";
-       }
-#undef IWL_CMD
-}
-
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
-{
-       int i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       int pos = 0;
-       size_t bufsz = 0;
-#endif
-       static const u32 fh_tbl[] = {
-               FH_RSCSR_CHNL0_STTS_WPTR_REG,
-               FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-               FH_RSCSR_CHNL0_WPTR,
-               FH_MEM_RCSR_CHNL0_CONFIG_REG,
-               FH_MEM_RSSR_SHARED_CTRL_REG,
-               FH_MEM_RSSR_RX_STATUS_REG,
-               FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
-               FH_TSSR_TX_STATUS_REG,
-               FH_TSSR_TX_ERROR_REG
-       };
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (display) {
-               bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
-               *buf = kmalloc(bufsz, GFP_KERNEL);
-               if (!*buf)
-                       return -ENOMEM;
-               pos += scnprintf(*buf + pos, bufsz - pos,
-                               "FH register values:\n");
-               for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
-                       pos += scnprintf(*buf + pos, bufsz - pos,
-                               "  %34s: 0X%08x\n",
-                               get_fh_string(fh_tbl[i]),
-                               iwl_read_direct32(trans, fh_tbl[i]));
-               }
-               return pos;
-       }
-#endif
-       IWL_ERR(trans, "FH register values:\n");
-       for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
-               IWL_ERR(trans, "  %34s: 0X%08x\n",
-                       get_fh_string(fh_tbl[i]),
-                       iwl_read_direct32(trans, fh_tbl[i]));
-       }
-       return 0;
-}
-
-static const char *get_csr_string(int cmd)
-{
-#define IWL_CMD(x) case x: return #x
-       switch (cmd) {
-       IWL_CMD(CSR_HW_IF_CONFIG_REG);
-       IWL_CMD(CSR_INT_COALESCING);
-       IWL_CMD(CSR_INT);
-       IWL_CMD(CSR_INT_MASK);
-       IWL_CMD(CSR_FH_INT_STATUS);
-       IWL_CMD(CSR_GPIO_IN);
-       IWL_CMD(CSR_RESET);
-       IWL_CMD(CSR_GP_CNTRL);
-       IWL_CMD(CSR_HW_REV);
-       IWL_CMD(CSR_EEPROM_REG);
-       IWL_CMD(CSR_EEPROM_GP);
-       IWL_CMD(CSR_OTP_GP_REG);
-       IWL_CMD(CSR_GIO_REG);
-       IWL_CMD(CSR_GP_UCODE_REG);
-       IWL_CMD(CSR_GP_DRIVER_REG);
-       IWL_CMD(CSR_UCODE_DRV_GP1);
-       IWL_CMD(CSR_UCODE_DRV_GP2);
-       IWL_CMD(CSR_LED_REG);
-       IWL_CMD(CSR_DRAM_INT_TBL_REG);
-       IWL_CMD(CSR_GIO_CHICKEN_BITS);
-       IWL_CMD(CSR_ANA_PLL_CFG);
-       IWL_CMD(CSR_HW_REV_WA_REG);
-       IWL_CMD(CSR_DBG_HPET_MEM_REG);
-       default:
-               return "UNKNOWN";
-       }
-#undef IWL_CMD
-}
-
-void iwl_dump_csr(struct iwl_trans *trans)
-{
-       int i;
-       static const u32 csr_tbl[] = {
-               CSR_HW_IF_CONFIG_REG,
-               CSR_INT_COALESCING,
-               CSR_INT,
-               CSR_INT_MASK,
-               CSR_FH_INT_STATUS,
-               CSR_GPIO_IN,
-               CSR_RESET,
-               CSR_GP_CNTRL,
-               CSR_HW_REV,
-               CSR_EEPROM_REG,
-               CSR_EEPROM_GP,
-               CSR_OTP_GP_REG,
-               CSR_GIO_REG,
-               CSR_GP_UCODE_REG,
-               CSR_GP_DRIVER_REG,
-               CSR_UCODE_DRV_GP1,
-               CSR_UCODE_DRV_GP2,
-               CSR_LED_REG,
-               CSR_DRAM_INT_TBL_REG,
-               CSR_GIO_CHICKEN_BITS,
-               CSR_ANA_PLL_CFG,
-               CSR_HW_REV_WA_REG,
-               CSR_DBG_HPET_MEM_REG
-       };
-       IWL_ERR(trans, "CSR values:\n");
-       IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
-               "CSR_INT_PERIODIC_REG)\n");
-       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
-               IWL_ERR(trans, "  %25s: 0X%08x\n",
-                       get_csr_string(csr_tbl[i]),
-                       iwl_read32(trans, csr_tbl[i]));
-       }
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-/* create and remove of files */
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
-       if (!debugfs_create_file(#name, mode, parent, trans,            \
-                                &iwl_dbgfs_##name##_ops))              \
-               return -ENOMEM;                                         \
-} while (0)
-
-/* file operation */
-#define DEBUGFS_READ_FUNC(name)                                         \
-static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
-                                       char __user *user_buf,          \
-                                       size_t count, loff_t *ppos);
-
-#define DEBUGFS_WRITE_FUNC(name)                                        \
-static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
-                                       const char __user *user_buf,    \
-                                       size_t count, loff_t *ppos);
-
-
-#define DEBUGFS_READ_FILE_OPS(name)                                    \
-       DEBUGFS_READ_FUNC(name);                                        \
-static const struct file_operations iwl_dbgfs_##name##_ops = {         \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_READ_WRITE_FILE_OPS(name)                              \
-       DEBUGFS_READ_FUNC(name);                                        \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {         \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       char *buf;
-       int pos = 0;
-       int cnt;
-       int ret;
-       size_t bufsz;
-
-       bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues;
-
-       if (!trans_pcie->txq)
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
-               txq = &trans_pcie->txq[cnt];
-               q = &txq->q;
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "hwq %.2d: read=%u write=%u use=%d stop=%d\n",
-                               cnt, q->read_ptr, q->write_ptr,
-                               !!test_bit(cnt, trans_pcie->queue_used),
-                               !!test_bit(cnt, trans_pcie->queue_stopped));
-       }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos) {
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       char buf[256];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
-                                               rxq->read);
-       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
-                                               rxq->write);
-       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
-                                               rxq->free_count);
-       if (rxq->rb_stts) {
-               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
-                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
-       } else {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                       "closed_rb_num: Not Allocated\n");
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-       int pos = 0;
-       char *buf;
-       int bufsz = 24 * 64; /* 24 items * 64 char per item */
-       ssize_t ret;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "Interrupt Statistics Report:\n");
-
-       pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
-               isr_stats->hw);
-       pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
-               isr_stats->sw);
-       if (isr_stats->sw || isr_stats->hw) {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tLast Restarting Code:  0x%X\n",
-                       isr_stats->err_code);
-       }
-#ifdef CONFIG_IWLWIFI_DEBUG
-       pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
-               isr_stats->sch);
-       pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
-               isr_stats->alive);
-#endif
-       pos += scnprintf(buf + pos, bufsz - pos,
-               "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
-               isr_stats->ctkill);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
-               isr_stats->wakeup);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-               "Rx command responses:\t\t %u\n", isr_stats->rx);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
-               isr_stats->tx);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
-               isr_stats->unhandled);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-       char buf[8];
-       int buf_size;
-       u32 reset_flag;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%x", &reset_flag) != 1)
-               return -EFAULT;
-       if (reset_flag == 0)
-               memset(isr_stats, 0, sizeof(*isr_stats));
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_csr_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char buf[8];
-       int buf_size;
-       int csr;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &csr) != 1)
-               return -EFAULT;
-
-       iwl_dump_csr(trans);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char *buf;
-       int pos = 0;
-       ssize_t ret = -EFAULT;
-
-       ret = pos = iwl_dump_fh(trans, &buf, true);
-       if (buf) {
-               ret = simple_read_from_buffer(user_buf,
-                                             count, ppos, buf, pos);
-               kfree(buf);
-       }
-
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
-                                         const char __user *user_buf,
-                                         size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-
-       if (!trans->op_mode)
-               return -EAGAIN;
-
-       iwl_op_mode_nic_error(trans->op_mode);
-
-       return count;
-}
-
-DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
-DEBUGFS_READ_FILE_OPS(fh_reg);
-DEBUGFS_READ_FILE_OPS(rx_queue);
-DEBUGFS_READ_FILE_OPS(tx_queue);
-DEBUGFS_WRITE_FILE_OPS(csr);
-DEBUGFS_WRITE_FILE_OPS(fw_restart);
-
-/*
- * Create the debugfs files and directories
- *
- */
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                       struct dentry *dir)
-{
-       DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
-       DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
-       return 0;
-}
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                       struct dentry *dir)
-{ return 0; }
-
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
-
-static const struct iwl_trans_ops trans_ops_pcie = {
-       .start_hw = iwl_trans_pcie_start_hw,
-       .stop_hw = iwl_trans_pcie_stop_hw,
-       .fw_alive = iwl_trans_pcie_fw_alive,
-       .start_fw = iwl_trans_pcie_start_fw,
-       .stop_device = iwl_trans_pcie_stop_device,
-
-       .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
-
-       .send_cmd = iwl_trans_pcie_send_cmd,
-
-       .tx = iwl_trans_pcie_tx,
-       .reclaim = iwl_trans_pcie_reclaim,
-
-       .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
-       .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
-
-       .dbgfs_register = iwl_trans_pcie_dbgfs_register,
-
-       .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
-
-#ifdef CONFIG_PM_SLEEP
-       .suspend = iwl_trans_pcie_suspend,
-       .resume = iwl_trans_pcie_resume,
-#endif
-       .write8 = iwl_trans_pcie_write8,
-       .write32 = iwl_trans_pcie_write32,
-       .read32 = iwl_trans_pcie_read32,
-       .configure = iwl_trans_pcie_configure,
-       .set_pmi = iwl_trans_pcie_set_pmi,
-};
-
-struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent,
-                                      const struct iwl_cfg *cfg)
-{
-       struct iwl_trans_pcie *trans_pcie;
-       struct iwl_trans *trans;
-       u16 pci_cmd;
-       int err;
-
-       trans = kzalloc(sizeof(struct iwl_trans) +
-                            sizeof(struct iwl_trans_pcie), GFP_KERNEL);
-
-       if (WARN_ON(!trans))
-               return NULL;
-
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       trans->ops = &trans_ops_pcie;
-       trans->cfg = cfg;
-       trans_pcie->trans = trans;
-       spin_lock_init(&trans_pcie->irq_lock);
-       init_waitqueue_head(&trans_pcie->ucode_write_waitq);
-
-       /* W/A - seems to solve weird behavior. We need to remove this if we
-        * don't want to stay in L1 all the time. This wastes a lot of power */
-       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
-                               PCIE_LINK_STATE_CLKPM);
-
-       if (pci_enable_device(pdev)) {
-               err = -ENODEV;
-               goto out_no_pci;
-       }
-
-       pci_set_master(pdev);
-
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (err) {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (!err)
-                       err = pci_set_consistent_dma_mask(pdev,
-                                                       DMA_BIT_MASK(32));
-               /* both attempts failed: */
-               if (err) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "No suitable DMA available.\n");
-                       goto out_pci_disable_device;
-               }
-       }
-
-       err = pci_request_regions(pdev, DRV_NAME);
-       if (err) {
-               dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed");
-               goto out_pci_disable_device;
-       }
-
-       trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
-       if (!trans_pcie->hw_base) {
-               dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed");
-               err = -ENODEV;
-               goto out_pci_release_regions;
-       }
-
-       dev_printk(KERN_INFO, &pdev->dev,
-               "pci_resource_len = 0x%08llx\n",
-               (unsigned long long) pci_resource_len(pdev, 0));
-       dev_printk(KERN_INFO, &pdev->dev,
-               "pci_resource_base = %p\n", trans_pcie->hw_base);
-
-       dev_printk(KERN_INFO, &pdev->dev,
-               "HW Revision ID = 0x%X\n", pdev->revision);
-
-       /* We disable the RETRY_TIMEOUT register (0x41) to keep
-        * PCI Tx retries from interfering with C3 CPU state */
-       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
-
-       err = pci_enable_msi(pdev);
-       if (err)
-               dev_printk(KERN_ERR, &pdev->dev,
-                       "pci_enable_msi failed(0X%x)", err);
-
-       trans->dev = &pdev->dev;
-       trans_pcie->irq = pdev->irq;
-       trans_pcie->pci_dev = pdev;
-       trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
-       trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
-       snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
-                "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
-
-       /* TODO: Move this away, not needed if not MSI */
-       /* enable rfkill interrupt: hw bug w/a */
-       pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
-       if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
-               pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
-       }
-
-       /* Initialize the wait queue for commands */
-       init_waitqueue_head(&trans->wait_command_queue);
-       spin_lock_init(&trans->reg_lock);
-
-       return trans;
-
-out_pci_release_regions:
-       pci_release_regions(pdev);
-out_pci_disable_device:
-       pci_disable_device(pdev);
-out_no_pci:
-       kfree(trans);
-       return NULL;
-}
-
index 79a1e7ae4995d615b2e46370bd786350239ecf73..00efde8e5536bf674be9e3d612c8872930529aad 100644 (file)
@@ -154,6 +154,9 @@ struct iwl_cmd_header {
        __le16 sequence;
 } __packed;
 
+/* iwl_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
 
 #define FH_RSCSR_FRAME_SIZE_MSK                0x00003FFF      /* bits 0-13 */
 #define FH_RSCSR_FRAME_INVALID         0x55550000
@@ -280,6 +283,8 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
 
 #define MAX_NO_RECLAIM_CMDS    6
 
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
 /*
  * Maximum number of HW queues the transport layer
  * currently supports
@@ -350,10 +355,10 @@ struct iwl_trans;
  *     Must be atomic
  * @reclaim: free packet until ssn. Returns a list of freed packets.
  *     Must be atomic
- * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
+ * @txq_enable: setup a tx queue for AMPDU - will be called once the HW is
  *     ready and a successful ADDBA response has been received.
  *     May sleep
- * @tx_agg_disable: de-configure a Tx queue to send AMPDUs
+ * @txq_disable: de-configure a Tx queue to send AMPDUs
  *     Must be atomic
  * @wait_tx_queue_empty: wait until all tx queues are empty
  *     May sleep
@@ -386,9 +391,9 @@ struct iwl_trans_ops {
        void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
                        struct sk_buff_head *skbs);
 
-       void (*tx_agg_setup)(struct iwl_trans *trans, int queue, int fifo,
-                            int sta_id, int tid, int frame_limit, u16 ssn);
-       void (*tx_agg_disable)(struct iwl_trans *trans, int queue);
+       void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
+                          int sta_id, int tid, int frame_limit, u16 ssn);
+       void (*txq_disable)(struct iwl_trans *trans, int queue);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*wait_tx_queue_empty)(struct iwl_trans *trans);
@@ -428,6 +433,11 @@ enum iwl_trans_state {
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
  * @pm_support: set to true in start_hw if link pm is supported
  * @wait_command_queue: the wait_queue for SYNC host commands
+ * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
+ *     The user should use iwl_trans_{alloc,free}_tx_cmd.
+ * @dev_cmd_headroom: room needed for the transport's private use before the
+ *     device_cmd for Tx - for internal use only
+ *     The user should use iwl_trans_{alloc,free}_tx_cmd.
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
@@ -445,6 +455,10 @@ struct iwl_trans {
 
        wait_queue_head_t wait_command_queue;
 
+       /* The following fields are internal only */
+       struct kmem_cache *dev_cmd_pool;
+       size_t dev_cmd_headroom;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __aligned(sizeof(void *));
@@ -520,6 +534,26 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
        return trans->ops->send_cmd(trans, cmd);
 }
 
+static inline struct iwl_device_cmd *
+iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
+{
+       u8 *dev_cmd_ptr = kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC);
+
+       if (unlikely(dev_cmd_ptr == NULL))
+               return NULL;
+
+       return (struct iwl_device_cmd *)
+                       (dev_cmd_ptr + trans->dev_cmd_headroom);
+}
+
+static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
+                                        struct iwl_device_cmd *dev_cmd)
+{
+       u8 *dev_cmd_ptr = (u8 *)dev_cmd - trans->dev_cmd_headroom;
+
+       kmem_cache_free(trans->dev_cmd_pool, dev_cmd_ptr);
+}
+
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
                               struct iwl_device_cmd *dev_cmd, int queue)
 {
@@ -538,24 +572,24 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
        trans->ops->reclaim(trans, queue, ssn, skbs);
 }
 
-static inline void iwl_trans_tx_agg_disable(struct iwl_trans *trans, int queue)
+static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
        WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
                  "%s bad state = %d", __func__, trans->state);
 
-       trans->ops->tx_agg_disable(trans, queue);
+       trans->ops->txq_disable(trans, queue);
 }
 
-static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int queue,
-                                         int fifo, int sta_id, int tid,
-                                         int frame_limit, u16 ssn)
+static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
+                                       int fifo, int sta_id, int tid,
+                                       int frame_limit, u16 ssn)
 {
        might_sleep();
 
        WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE,
                  "%s bad state = %d", __func__, trans->state);
 
-       trans->ops->tx_agg_setup(trans, queue, fifo, sta_id, tid,
+       trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
                                 frame_limit, ssn);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
deleted file mode 100644 (file)
index bc40dc6..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-/******************************************************************************
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2012 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.GPL.
- *
- * 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/init.h>
-
-#include "iwl-dev.h"
-#include "iwl-io.h"
-#include "iwl-agn-hw.h"
-#include "iwl-agn.h"
-#include "iwl-agn-calib.h"
-#include "iwl-trans.h"
-#include "iwl-fh.h"
-#include "iwl-op-mode.h"
-
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static inline const struct fw_img *
-iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
-{
-       if (ucode_type >= IWL_UCODE_TYPE_MAX)
-               return NULL;
-
-       return &priv->fw->img[ucode_type];
-}
-
-/*
- *  Calibration
- */
-static int iwl_set_Xtal_calib(struct iwl_priv *priv)
-{
-       struct iwl_calib_xtal_freq_cmd cmd;
-       __le16 *xtal_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL);
-
-       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
-       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
-       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
-       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
-{
-       struct iwl_calib_temperature_offset_cmd cmd;
-       __le16 *offset_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
-
-       memset(&cmd, 0, sizeof(cmd));
-       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
-       memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
-       if (!(cmd.radio_sensor_offset))
-               cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
-
-       IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
-                       le16_to_cpu(cmd.radio_sensor_offset));
-       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
-{
-       struct iwl_calib_temperature_offset_v2_cmd cmd;
-       __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv,
-                                    EEPROM_KELVIN_TEMPERATURE);
-       __le16 *offset_calib_low =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
-       struct iwl_eeprom_calib_hdr *hdr;
-
-       memset(&cmd, 0, sizeof(cmd));
-       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
-       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-                                                       EEPROM_CALIB_ALL);
-       memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
-               sizeof(*offset_calib_high));
-       memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
-               sizeof(*offset_calib_low));
-       if (!(cmd.radio_sensor_offset_low)) {
-               IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
-               cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
-               cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
-       }
-       memcpy(&cmd.burntVoltageRef, &hdr->voltage,
-               sizeof(hdr->voltage));
-
-       IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
-                       le16_to_cpu(cmd.radio_sensor_offset_high));
-       IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
-                       le16_to_cpu(cmd.radio_sensor_offset_low));
-       IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
-                       le16_to_cpu(cmd.burntVoltageRef));
-
-       return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
-}
-
-static int iwl_send_calib_cfg(struct iwl_priv *priv)
-{
-       struct iwl_calib_cfg_cmd calib_cfg_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = CALIBRATION_CFG_CMD,
-               .len = { sizeof(struct iwl_calib_cfg_cmd), },
-               .data = { &calib_cfg_cmd, },
-       };
-
-       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.flags =
-               IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
-
-       return iwl_dvm_send_cmd(priv, &cmd);
-}
-
-int iwl_init_alive_start(struct iwl_priv *priv)
-{
-       int ret;
-
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               /*
-                * Tell uCode we are ready to perform calibration
-                * need to perform this before any calibration
-                * no need to close the envlope since we are going
-                * to load the runtime uCode later.
-                */
-               ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
-                       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
-               if (ret)
-                       return ret;
-
-       }
-
-       ret = iwl_send_calib_cfg(priv);
-       if (ret)
-               return ret;
-
-       /**
-        * temperature offset calibration is only needed for runtime ucode,
-        * so prepare the value now.
-        */
-       if (priv->cfg->need_temp_offset_calib) {
-               if (priv->cfg->temp_offset_v2)
-                       return iwl_set_temperature_offset_calib_v2(priv);
-               else
-                       return iwl_set_temperature_offset_calib(priv);
-       }
-
-       return 0;
-}
-
-int iwl_send_wimax_coex(struct iwl_priv *priv)
-{
-       struct iwl_wimax_coex_cmd coex_cmd;
-
-       /* coexistence is disabled */
-       memset(&coex_cmd, 0, sizeof(coex_cmd));
-
-       return iwl_dvm_send_cmd_pdu(priv,
-                               COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
-                               sizeof(coex_cmd), &coex_cmd);
-}
-
-static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
-       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
-               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
-       0, 0, 0, 0, 0, 0, 0
-};
-
-void iwl_send_prio_tbl(struct iwl_priv *priv)
-{
-       struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
-
-       memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
-               sizeof(iwl_bt_prio_tbl));
-       if (iwl_dvm_send_cmd_pdu(priv,
-                               REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
-                               sizeof(prio_tbl_cmd), &prio_tbl_cmd))
-               IWL_ERR(priv, "failed to send BT prio tbl command\n");
-}
-
-int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
-{
-       struct iwl_bt_coex_prot_env_cmd env_cmd;
-       int ret;
-
-       env_cmd.action = action;
-       env_cmd.type = type;
-       ret = iwl_dvm_send_cmd_pdu(priv,
-                              REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
-                              sizeof(env_cmd), &env_cmd);
-       if (ret)
-               IWL_ERR(priv, "failed to send BT env command\n");
-       return ret;
-}
-
-
-static int iwl_alive_notify(struct iwl_priv *priv)
-{
-       int ret;
-
-       iwl_trans_fw_alive(priv->trans);
-
-       priv->passive_no_rx = false;
-       priv->transport_queue_stop = 0;
-
-       ret = iwl_send_wimax_coex(priv);
-       if (ret)
-               return ret;
-
-       if (!priv->cfg->no_xtal_calib) {
-               ret = iwl_set_Xtal_calib(priv);
-               if (ret)
-                       return ret;
-       }
-
-       return iwl_send_calib_results(priv);
-}
-
-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_sec_sparse(struct iwl_priv *priv,
-                                 const struct fw_desc *fw_desc)
-{
-       __le32 *image = (__le32 *)fw_desc->v_addr;
-       u32 len = fw_desc->len;
-       u32 val;
-       u32 i;
-
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-       for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
-               /* read data comes through single port, auto-incr addr */
-               /* NOTE: Use the debugless read so we don't flood kernel log
-                * if IWL_DL_IO is set */
-               iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-                       i + fw_desc->offset);
-               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image))
-                       return -EIO;
-       }
-
-       return 0;
-}
-
-static void iwl_print_mismatch_sec(struct iwl_priv *priv,
-                                   const struct fw_desc *fw_desc)
-{
-       __le32 *image = (__le32 *)fw_desc->v_addr;
-       u32 len = fw_desc->len;
-       u32 val;
-       u32 offs;
-       int errors = 0;
-
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
-
-       iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR,
-                               fw_desc->offset);
-
-       for (offs = 0;
-            offs < len && errors < 20;
-            offs += sizeof(u32), image++) {
-               /* read data comes through single port, auto-incr addr */
-               val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(priv, "uCode INST section at "
-                               "offset 0x%x, is 0x%x, s/b 0x%x\n",
-                               offs, val, le32_to_cpu(*image));
-                       errors++;
-               }
-       }
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv,
-                           enum iwl_ucode_type ucode_type)
-{
-       const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
-
-       if (!img) {
-               IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
-               return -EINVAL;
-       }
-
-       if (!iwl_verify_sec_sparse(priv, &img->sec[IWL_UCODE_SECTION_INST])) {
-               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
-               return 0;
-       }
-
-       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
-
-       iwl_print_mismatch_sec(priv, &img->sec[IWL_UCODE_SECTION_INST]);
-       return -EIO;
-}
-
-struct iwl_alive_data {
-       bool valid;
-       u8 subtype;
-};
-
-static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
-                        struct iwl_rx_packet *pkt, void *data)
-{
-       struct iwl_priv *priv =
-               container_of(notif_wait, struct iwl_priv, notif_wait);
-       struct iwl_alive_data *alive_data = data;
-       struct iwl_alive_resp *palive;
-
-       palive = (void *)pkt->data;
-
-       IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
-                      "0x%01X 0x%01X\n",
-                      palive->is_valid, palive->ver_type,
-                      palive->ver_subtype);
-
-       priv->device_pointers.error_event_table =
-               le32_to_cpu(palive->error_event_table_ptr);
-       priv->device_pointers.log_event_table =
-               le32_to_cpu(palive->log_event_table_ptr);
-
-       alive_data->subtype = palive->ver_subtype;
-       alive_data->valid = palive->is_valid == UCODE_VALID_OK;
-
-       return true;
-}
-
-#define UCODE_ALIVE_TIMEOUT    HZ
-#define UCODE_CALIB_TIMEOUT    (2*HZ)
-
-int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
-                                enum iwl_ucode_type ucode_type)
-{
-       struct iwl_notification_wait alive_wait;
-       struct iwl_alive_data alive_data;
-       const struct fw_img *fw;
-       int ret;
-       enum iwl_ucode_type old_type;
-       static const u8 alive_cmd[] = { REPLY_ALIVE };
-
-       old_type = priv->cur_ucode;
-       priv->cur_ucode = ucode_type;
-       fw = iwl_get_ucode_image(priv, ucode_type);
-
-       priv->ucode_loaded = false;
-
-       if (!fw)
-               return -EINVAL;
-
-       iwl_init_notification_wait(&priv->notif_wait, &alive_wait,
-                                  alive_cmd, ARRAY_SIZE(alive_cmd),
-                                  iwl_alive_fn, &alive_data);
-
-       ret = iwl_trans_start_fw(priv->trans, fw);
-       if (ret) {
-               priv->cur_ucode = old_type;
-               iwl_remove_notification(&priv->notif_wait, &alive_wait);
-               return ret;
-       }
-
-       /*
-        * Some things may run in the background now, but we
-        * just wait for the ALIVE notification here.
-        */
-       ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
-                                       UCODE_ALIVE_TIMEOUT);
-       if (ret) {
-               priv->cur_ucode = old_type;
-               return ret;
-       }
-
-       if (!alive_data.valid) {
-               IWL_ERR(priv, "Loaded ucode is not valid!\n");
-               priv->cur_ucode = old_type;
-               return -EIO;
-       }
-
-       /*
-        * This step takes a long time (60-80ms!!) and
-        * WoWLAN image should be loaded quickly, so
-        * skip it for WoWLAN.
-        */
-       if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(priv, ucode_type);
-               if (ret) {
-                       priv->cur_ucode = old_type;
-                       return ret;
-               }
-
-               /* delay a bit to give rfkill time to run */
-               msleep(5);
-       }
-
-       ret = iwl_alive_notify(priv);
-       if (ret) {
-               IWL_WARN(priv,
-                       "Could not complete ALIVE transition: %d\n", ret);
-               priv->cur_ucode = old_type;
-               return ret;
-       }
-
-       priv->ucode_loaded = true;
-
-       return 0;
-}
-
-static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait,
-                             struct iwl_rx_packet *pkt, void *data)
-{
-       struct iwl_priv *priv = data;
-       struct iwl_calib_hdr *hdr;
-       int len;
-
-       if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) {
-               WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION);
-               return true;
-       }
-
-       hdr = (struct iwl_calib_hdr *)pkt->data;
-       len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-
-       /* reduce the size by the length field itself */
-       len -= sizeof(__le32);
-
-       if (iwl_calib_set(priv, hdr, len))
-               IWL_ERR(priv, "Failed to record calibration data %d\n",
-                       hdr->op_code);
-
-       return false;
-}
-
-int iwl_run_init_ucode(struct iwl_priv *priv)
-{
-       struct iwl_notification_wait calib_wait;
-       static const u8 calib_complete[] = {
-               CALIBRATION_RES_NOTIFICATION,
-               CALIBRATION_COMPLETE_NOTIFICATION
-       };
-       int ret;
-
-       lockdep_assert_held(&priv->mutex);
-
-       /* No init ucode required? Curious, but maybe ok */
-       if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
-               return 0;
-
-       if (priv->init_ucode_run)
-               return 0;
-
-       iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
-                                  calib_complete, ARRAY_SIZE(calib_complete),
-                                  iwlagn_wait_calib, priv);
-
-       /* Will also start the device */
-       ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
-       if (ret)
-               goto error;
-
-       ret = iwl_init_alive_start(priv);
-       if (ret)
-               goto error;
-
-       /*
-        * Some things may run in the background now, but we
-        * just wait for the calibration complete notification.
-        */
-       ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
-                                       UCODE_CALIB_TIMEOUT);
-       if (!ret)
-               priv->init_ucode_run = true;
-
-       goto out;
-
- error:
-       iwl_remove_notification(&priv->notif_wait, &calib_wait);
- out:
-       /* Whatever happened, stop the device */
-       iwl_trans_stop_device(priv->trans);
-       priv->ucode_loaded = false;
-
-       return ret;
-}
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/pcie/1000.c
new file mode 100644 (file)
index 0000000..81b83f4
--- /dev/null
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-csr.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL1000_UCODE_API_MAX 5
+#define IWL100_UCODE_API_MAX 5
+
+/* Oldest version we won't warn about */
+#define IWL1000_UCODE_API_OK 5
+#define IWL100_UCODE_API_OK 5
+
+/* Lowest firmware API version supported */
+#define IWL1000_UCODE_API_MIN 1
+#define IWL100_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_1000_TX_POWER_VERSION   (4)
+#define EEPROM_1000_EEPROM_VERSION     (0x15C)
+
+#define IWL1000_FW_PRE "iwlwifi-1000-"
+#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL100_FW_PRE "iwlwifi-100-"
+#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode"
+
+
+static const struct iwl_base_params iwl1000_base_params = {
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+       .shadow_ram_support = false,
+       .led_compensation = 51,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_WATCHDOG_DISABLED,
+       .max_event_log_size = 128,
+};
+
+static const struct iwl_ht_params iwl1000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_eeprom_params iwl1000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       }
+};
+
+#define IWL_DEVICE_1000                                                \
+       .fw_name_pre = IWL1000_FW_PRE,                          \
+       .ucode_api_max = IWL1000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL1000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL1000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_1000,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
+       .base_params = &iwl1000_base_params,                    \
+       .eeprom_params = &iwl1000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl1000_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
+       IWL_DEVICE_1000,
+       .ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl1000_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
+       IWL_DEVICE_1000,
+};
+
+#define IWL_DEVICE_100                                         \
+       .fw_name_pre = IWL100_FW_PRE,                           \
+       .ucode_api_max = IWL100_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL100_UCODE_API_OK,                    \
+       .ucode_api_min = IWL100_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_100,                 \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .eeprom_ver = EEPROM_1000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,       \
+       .base_params = &iwl1000_base_params,                    \
+       .eeprom_params = &iwl1000_eeprom_params,                \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl100_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
+       IWL_DEVICE_100,
+       .ht_params = &iwl1000_ht_params,
+};
+
+const struct iwl_cfg iwl100_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
+       IWL_DEVICE_100,
+};
+
+MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL100_MODULE_FIRMWARE(IWL100_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c
new file mode 100644 (file)
index 0000000..fd4e78f
--- /dev/null
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL2030_UCODE_API_MAX 6
+#define IWL2000_UCODE_API_MAX 6
+#define IWL105_UCODE_API_MAX 6
+#define IWL135_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL2030_UCODE_API_OK 6
+#define IWL2000_UCODE_API_OK 6
+#define IWL105_UCODE_API_OK 6
+#define IWL135_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL2030_UCODE_API_MIN 5
+#define IWL2000_UCODE_API_MIN 5
+#define IWL105_UCODE_API_MIN 5
+#define IWL135_UCODE_API_MIN 5
+
+/* EEPROM version */
+#define EEPROM_2000_TX_POWER_VERSION   (6)
+#define EEPROM_2000_EEPROM_VERSION     (0x805)
+
+
+#define IWL2030_FW_PRE "iwlwifi-2030-"
+#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode"
+
+#define IWL2000_FW_PRE "iwlwifi-2000-"
+#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL105_FW_PRE "iwlwifi-105-"
+#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
+
+#define IWL135_FW_PRE "iwlwifi-135-"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl2000_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .hd_v2 = true,
+};
+
+
+static const struct iwl_base_params iwl2030_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
+       .shadow_ram_support = true,
+       .led_compensation = 57,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_LONG_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+       .hd_v2 = true,
+};
+
+static const struct iwl_ht_params iwl2000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ),
+};
+
+static const struct iwl_bt_params iwl2030_bt_params = {
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .advanced_bt_coexist = true,
+       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+       .bt_sco_disable = true,
+       .bt_session_2 = true,
+};
+
+static const struct iwl_eeprom_params iwl20x0_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REGULATORY_BAND_NO_HT40,
+       },
+       .enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_2000                                                \
+       .fw_name_pre = IWL2000_FW_PRE,                          \
+       .ucode_api_max = IWL2000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL2000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL2000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_2000,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
+       .base_params = &iwl2000_base_params,                    \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl2000_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN",
+       IWL_DEVICE_2000,
+       .ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl2000_2bgn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2200D BGN",
+       IWL_DEVICE_2000,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_2030                                                \
+       .fw_name_pre = IWL2030_FW_PRE,                          \
+       .ucode_api_max = IWL2030_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL2030_UCODE_API_OK,                   \
+       .ucode_api_min = IWL2030_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_2030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
+       .base_params = &iwl2030_base_params,                    \
+       .bt_params = &iwl2030_bt_params,                        \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true
+
+const struct iwl_cfg iwl2030_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN",
+       IWL_DEVICE_2030,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_105                                         \
+       .fw_name_pre = IWL105_FW_PRE,                           \
+       .ucode_api_max = IWL105_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL105_UCODE_API_OK,                    \
+       .ucode_api_min = IWL105_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_105,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
+       .base_params = &iwl2000_base_params,                    \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true,                                         \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl105_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 105 BGN",
+       IWL_DEVICE_105,
+       .ht_params = &iwl2000_ht_params,
+};
+
+const struct iwl_cfg iwl105_bgn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 105D BGN",
+       IWL_DEVICE_105,
+       .ht_params = &iwl2000_ht_params,
+};
+
+#define IWL_DEVICE_135                                         \
+       .fw_name_pre = IWL135_FW_PRE,                           \
+       .ucode_api_max = IWL135_UCODE_API_MAX,                  \
+       .ucode_api_ok = IWL135_UCODE_API_OK,                    \
+       .ucode_api_min = IWL135_UCODE_API_MIN,                  \
+       .device_family = IWL_DEVICE_FAMILY_135,                 \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_2000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION,       \
+       .base_params = &iwl2030_base_params,                    \
+       .bt_params = &iwl2030_bt_params,                        \
+       .eeprom_params = &iwl20x0_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true,                                         \
+       .rx_with_siso_diversity = true
+
+const struct iwl_cfg iwl135_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 135 BGN",
+       IWL_DEVICE_135,
+       .ht_params = &iwl2000_ht_params,
+};
+
+MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_OK));
+MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_OK));
+MODULE_FIRMWARE(IWL135_MODULE_FIRMWARE(IWL135_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/pcie/5000.c
new file mode 100644 (file)
index 0000000..d1665fa
--- /dev/null
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 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/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "iwl-csr.h"
+#include "cfg.h"
+
+/* Highest firmware API version supported */
+#define IWL5000_UCODE_API_MAX 5
+#define IWL5150_UCODE_API_MAX 2
+
+/* Oldest version we won't warn about */
+#define IWL5000_UCODE_API_OK 5
+#define IWL5150_UCODE_API_OK 2
+
+/* Lowest firmware API version supported */
+#define IWL5000_UCODE_API_MIN 1
+#define IWL5150_UCODE_API_MIN 1
+
+/* EEPROM versions */
+#define EEPROM_5000_TX_POWER_VERSION   (4)
+#define EEPROM_5000_EEPROM_VERSION     (0x11A)
+#define EEPROM_5050_TX_POWER_VERSION   (4)
+#define EEPROM_5050_EEPROM_VERSION     (0x21E)
+
+#define IWL5000_FW_PRE "iwlwifi-5000-"
+#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL5150_FW_PRE "iwlwifi-5150-"
+#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl5000_base_params = {
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+       .led_compensation = 51,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_WATCHDOG_DISABLED,
+       .max_event_log_size = 512,
+       .no_idle_support = true,
+};
+
+static const struct iwl_ht_params iwl5000_ht_params = {
+       .ht_greenfield_support = true,
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_eeprom_params iwl5000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REG_BAND_52_HT40_CHANNELS
+       },
+};
+
+#define IWL_DEVICE_5000                                                \
+       .fw_name_pre = IWL5000_FW_PRE,                          \
+       .ucode_api_max = IWL5000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL5000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL5000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_5000,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .eeprom_ver = EEPROM_5000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,       \
+       .base_params = &iwl5000_base_params,                    \
+       .eeprom_params = &iwl5000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl5300_agn_cfg = {
+       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
+       IWL_DEVICE_5000,
+       /* at least EEPROM 0x11A has wrong info */
+       .valid_tx_ant = ANT_ABC,        /* .cfg overwrite */
+       .valid_rx_ant = ANT_ABC,        /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_bgn_cfg = {
+       .name = "Intel(R) WiFi Link 5100 BGN",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5100_abg_cfg = {
+       .name = "Intel(R) WiFi Link 5100 ABG",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+};
+
+const struct iwl_cfg iwl5100_agn_cfg = {
+       .name = "Intel(R) WiFi Link 5100 AGN",
+       IWL_DEVICE_5000,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
+       .ht_params = &iwl5000_ht_params,
+};
+
+const struct iwl_cfg iwl5350_agn_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
+       .fw_name_pre = IWL5000_FW_PRE,
+       .ucode_api_max = IWL5000_UCODE_API_MAX,
+       .ucode_api_ok = IWL5000_UCODE_API_OK,
+       .ucode_api_min = IWL5000_UCODE_API_MIN,
+       .device_family = IWL_DEVICE_FAMILY_5000,
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,
+       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+       .base_params = &iwl5000_base_params,
+       .eeprom_params = &iwl5000_eeprom_params,
+       .ht_params = &iwl5000_ht_params,
+       .led_mode = IWL_LED_BLINK,
+       .internal_wimax_coex = true,
+};
+
+#define IWL_DEVICE_5150                                                \
+       .fw_name_pre = IWL5150_FW_PRE,                          \
+       .ucode_api_max = IWL5150_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL5150_UCODE_API_OK,                   \
+       .ucode_api_min = IWL5150_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_5150,                \
+       .max_inst_size = IWLAGN_RTC_INST_SIZE,                  \
+       .max_data_size = IWLAGN_RTC_DATA_SIZE,                  \
+       .eeprom_ver = EEPROM_5050_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,       \
+       .base_params = &iwl5000_base_params,                    \
+       .eeprom_params = &iwl5000_eeprom_params,                \
+       .no_xtal_calib = true,                                  \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl5150_agn_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
+       IWL_DEVICE_5150,
+       .ht_params = &iwl5000_ht_params,
+
+};
+
+const struct iwl_cfg iwl5150_abg_cfg = {
+       .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
+       IWL_DEVICE_5150,
+};
+
+MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/pcie/6000.c
new file mode 100644 (file)
index 0000000..4a57624
--- /dev/null
@@ -0,0 +1,403 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2008 - 2012 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/module.h>
+#include <linux/stringify.h>
+#include "iwl-config.h"
+#include "iwl-agn-hw.h"
+#include "cfg.h"
+#include "dvm/commands.h" /* needed for BT for now */
+
+/* Highest firmware API version supported */
+#define IWL6000_UCODE_API_MAX 6
+#define IWL6050_UCODE_API_MAX 5
+#define IWL6000G2_UCODE_API_MAX 6
+#define IWL6035_UCODE_API_MAX 6
+
+/* Oldest version we won't warn about */
+#define IWL6000_UCODE_API_OK 4
+#define IWL6000G2_UCODE_API_OK 5
+#define IWL6050_UCODE_API_OK 5
+#define IWL6000G2B_UCODE_API_OK 6
+#define IWL6035_UCODE_API_OK 6
+
+/* Lowest firmware API version supported */
+#define IWL6000_UCODE_API_MIN 4
+#define IWL6050_UCODE_API_MIN 4
+#define IWL6000G2_UCODE_API_MIN 5
+#define IWL6035_UCODE_API_MIN 6
+
+/* EEPROM versions */
+#define EEPROM_6000_TX_POWER_VERSION   (4)
+#define EEPROM_6000_EEPROM_VERSION     (0x423)
+#define EEPROM_6050_TX_POWER_VERSION   (4)
+#define EEPROM_6050_EEPROM_VERSION     (0x532)
+#define EEPROM_6150_TX_POWER_VERSION   (6)
+#define EEPROM_6150_EEPROM_VERSION     (0x553)
+#define EEPROM_6005_TX_POWER_VERSION   (6)
+#define EEPROM_6005_EEPROM_VERSION     (0x709)
+#define EEPROM_6030_TX_POWER_VERSION   (6)
+#define EEPROM_6030_EEPROM_VERSION     (0x709)
+#define EEPROM_6035_TX_POWER_VERSION   (6)
+#define EEPROM_6035_EEPROM_VERSION     (0x753)
+
+#define IWL6000_FW_PRE "iwlwifi-6000-"
+#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6050_FW_PRE "iwlwifi-6050-"
+#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
+#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode"
+
+#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
+#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode"
+
+static const struct iwl_base_params iwl6000_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6050_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
+       .shadow_ram_support = true,
+       .led_compensation = 51,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1500,
+       .wd_timeout = IWL_DEF_WD_TIMEOUT,
+       .max_event_log_size = 1024,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_base_params iwl6000_g2_base_params = {
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .pll_cfg_val = 0,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .led_compensation = 57,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .wd_timeout = IWL_LONG_WD_TIMEOUT,
+       .max_event_log_size = 512,
+       .shadow_reg_enable = false, /* TODO: fix bugs using this feature */
+};
+
+static const struct iwl_ht_params iwl6000_ht_params = {
+       .ht_greenfield_support = true,
+       .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
+static const struct iwl_bt_params iwl6000_bt_params = {
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .advanced_bt_coexist = true,
+       .agg_time_limit = BT_AGG_THRESHOLD_DEF,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
+       .bt_sco_disable = true,
+};
+
+static const struct iwl_eeprom_params iwl6000_eeprom_params = {
+       .regulatory_bands = {
+               EEPROM_REG_BAND_1_CHANNELS,
+               EEPROM_REG_BAND_2_CHANNELS,
+               EEPROM_REG_BAND_3_CHANNELS,
+               EEPROM_REG_BAND_4_CHANNELS,
+               EEPROM_REG_BAND_5_CHANNELS,
+               EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+               EEPROM_REG_BAND_52_HT40_CHANNELS
+       },
+       .enhanced_txpower = true,
+};
+
+#define IWL_DEVICE_6005                                                \
+       .fw_name_pre = IWL6005_FW_PRE,                          \
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
+       .ucode_api_ok = IWL6000G2_UCODE_API_OK,                 \
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .device_family = IWL_DEVICE_FAMILY_6005,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_6005_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION,       \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE
+
+const struct iwl_cfg iwl6005_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
+       IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
+       IWL_DEVICE_6005,
+};
+
+const struct iwl_cfg iwl6005_2agn_sff_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_d_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow1_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6206 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6005_2agn_mow2_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6207 AGN",
+       IWL_DEVICE_6005,
+       .ht_params = &iwl6000_ht_params,
+};
+
+#define IWL_DEVICE_6030                                                \
+       .fw_name_pre = IWL6030_FW_PRE,                          \
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,               \
+       .ucode_api_ok = IWL6000G2B_UCODE_API_OK,                \
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,               \
+       .device_family = IWL_DEVICE_FAMILY_6030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_6030_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,       \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .bt_params = &iwl6000_bt_params,                        \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true                                          \
+
+const struct iwl_cfg iwl6030_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
+       IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl6030_2bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6030_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
+       IWL_DEVICE_6030,
+};
+
+#define IWL_DEVICE_6035                                                \
+       .fw_name_pre = IWL6030_FW_PRE,                          \
+       .ucode_api_max = IWL6035_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL6035_UCODE_API_OK,                   \
+       .ucode_api_min = IWL6035_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6030,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_6030_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION,       \
+       .base_params = &iwl6000_g2_base_params,                 \
+       .bt_params = &iwl6000_bt_params,                        \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .need_temp_offset_calib = true,                         \
+       .led_mode = IWL_LED_RF_STATE,                           \
+       .adv_pm = true
+
+const struct iwl_cfg iwl6035_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN",
+       IWL_DEVICE_6035,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl1030_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
+       IWL_DEVICE_6030,
+};
+
+const struct iwl_cfg iwl130_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
+       IWL_DEVICE_6030,
+       .ht_params = &iwl6000_ht_params,
+       .rx_with_siso_diversity = true,
+};
+
+const struct iwl_cfg iwl130_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
+       IWL_DEVICE_6030,
+       .rx_with_siso_diversity = true,
+};
+
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
+#define IWL_DEVICE_6000i                                       \
+       .fw_name_pre = IWL6000_FW_PRE,                          \
+       .ucode_api_max = IWL6000_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL6000_UCODE_API_OK,                   \
+       .ucode_api_min = IWL6000_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6000i,               \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */    \
+       .eeprom_ver = EEPROM_6000_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,       \
+       .base_params = &iwl6000_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK
+
+const struct iwl_cfg iwl6000i_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
+       IWL_DEVICE_6000i,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6000i_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
+       IWL_DEVICE_6000i,
+};
+
+const struct iwl_cfg iwl6000i_2bg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
+       IWL_DEVICE_6000i,
+};
+
+#define IWL_DEVICE_6050                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6050,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .eeprom_ver = EEPROM_6050_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,       \
+       .base_params = &iwl6050_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl6050_2agn_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
+       IWL_DEVICE_6050,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6050_2abg_cfg = {
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
+       IWL_DEVICE_6050,
+};
+
+#define IWL_DEVICE_6150                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .device_family = IWL_DEVICE_FAMILY_6150,                \
+       .max_inst_size = IWL60_RTC_INST_SIZE,                   \
+       .max_data_size = IWL60_RTC_DATA_SIZE,                   \
+       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,       \
+       .base_params = &iwl6050_base_params,                    \
+       .eeprom_params = &iwl6000_eeprom_params,                \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
+const struct iwl_cfg iwl6150_bgn_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
+       IWL_DEVICE_6150,
+       .ht_params = &iwl6000_ht_params,
+};
+
+const struct iwl_cfg iwl6150_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
+       IWL_DEVICE_6150,
+};
+
+const struct iwl_cfg iwl6000_3agn_cfg = {
+       .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
+       .fw_name_pre = IWL6000_FW_PRE,
+       .ucode_api_max = IWL6000_UCODE_API_MAX,
+       .ucode_api_ok = IWL6000_UCODE_API_OK,
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .device_family = IWL_DEVICE_FAMILY_6000,
+       .max_inst_size = IWL60_RTC_INST_SIZE,
+       .max_data_size = IWL60_RTC_DATA_SIZE,
+       .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .base_params = &iwl6000_base_params,
+       .eeprom_params = &iwl6000_eeprom_params,
+       .ht_params = &iwl6000_ht_params,
+       .led_mode = IWL_LED_BLINK,
+};
+
+MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6005_MODULE_FIRMWARE(IWL6000G2_UCODE_API_OK));
+MODULE_FIRMWARE(IWL6030_MODULE_FIRMWARE(IWL6000G2B_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
new file mode 100644 (file)
index 0000000..8215231
--- /dev/null
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __iwl_pci_h__
+#define __iwl_pci_h__
+
+
+/*
+ * This file declares the config structures for all devices.
+ */
+
+extern const struct iwl_cfg iwl5300_agn_cfg;
+extern const struct iwl_cfg iwl5100_agn_cfg;
+extern const struct iwl_cfg iwl5350_agn_cfg;
+extern const struct iwl_cfg iwl5100_bgn_cfg;
+extern const struct iwl_cfg iwl5100_abg_cfg;
+extern const struct iwl_cfg iwl5150_agn_cfg;
+extern const struct iwl_cfg iwl5150_abg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_cfg;
+extern const struct iwl_cfg iwl6005_2abg_cfg;
+extern const struct iwl_cfg iwl6005_2bg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
+extern const struct iwl_cfg iwl6005_2agn_d_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
+extern const struct iwl_cfg iwl1030_bgn_cfg;
+extern const struct iwl_cfg iwl1030_bg_cfg;
+extern const struct iwl_cfg iwl6030_2agn_cfg;
+extern const struct iwl_cfg iwl6030_2abg_cfg;
+extern const struct iwl_cfg iwl6030_2bgn_cfg;
+extern const struct iwl_cfg iwl6030_2bg_cfg;
+extern const struct iwl_cfg iwl6000i_2agn_cfg;
+extern const struct iwl_cfg iwl6000i_2abg_cfg;
+extern const struct iwl_cfg iwl6000i_2bg_cfg;
+extern const struct iwl_cfg iwl6000_3agn_cfg;
+extern const struct iwl_cfg iwl6050_2agn_cfg;
+extern const struct iwl_cfg iwl6050_2abg_cfg;
+extern const struct iwl_cfg iwl6150_bgn_cfg;
+extern const struct iwl_cfg iwl6150_bg_cfg;
+extern const struct iwl_cfg iwl1000_bgn_cfg;
+extern const struct iwl_cfg iwl1000_bg_cfg;
+extern const struct iwl_cfg iwl100_bgn_cfg;
+extern const struct iwl_cfg iwl100_bg_cfg;
+extern const struct iwl_cfg iwl130_bgn_cfg;
+extern const struct iwl_cfg iwl130_bg_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern const struct iwl_cfg iwl2030_2bgn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl105_bgn_cfg;
+extern const struct iwl_cfg iwl105_bgn_d_cfg;
+extern const struct iwl_cfg iwl135_bgn_cfg;
+
+#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
new file mode 100644 (file)
index 0000000..f4c3500
--- /dev/null
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+
+#include "iwl-trans.h"
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+
+#include "cfg.h"
+#include "internal.h"
+
+#define IWL_PCI_DEVICE(dev, subdev, cfg) \
+       .vendor = PCI_VENDOR_ID_INTEL,  .device = (dev), \
+       .subvendor = PCI_ANY_ID, .subdevice = (subdev), \
+       .driver_data = (kernel_ulong_t)&(cfg)
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
+       {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */
+
+/* 5300 Series WiFi */
+       {IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */
+
+/* 5350 Series WiFi/WiMax */
+       {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */
+
+/* 5150 Series Wifi/WiMax */
+       {IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+
+       {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */
+       {IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */
+
+/* 6x00 Series */
+       {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)},
+
+/* 6x05 Series */
+       {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6005_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6005_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6005_2bg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6005_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x4820, iwl6005_2agn_d_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_mow1_cfg)},/* low 5GHz active */
+       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_mow2_cfg)},/* high 5GHz active */
+
+/* 6x30 Series */
+       {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1030_bg_cfg)},
+       {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1030_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1030_bg_cfg)},
+       {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1030_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1030_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6030_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6030_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6030_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6030_2bg_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6030_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6030_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6030_2abg_cfg)},
+
+/* 6x50 WiFi/WiMax Series */
+       {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(0x0089, 0x1311, iwl6050_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
+
+/* 6150 WiFi/WiMax Series */
+       {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
+
+/* 1000 Series WiFi */
+       {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)},
+
+/* 100 Series WiFi */
+       {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)},
+       {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)},
+
+/* 130 Series WiFi */
+       {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5007, iwl130_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0897, 0x5015, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0897, 0x5017, iwl130_bg_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5025, iwl130_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0896, 0x5027, iwl130_bg_cfg)},
+
+/* 2x00 Series */
+       {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
+
+/* 2x30 Series */
+       {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
+
+/* 6x35 Series */
+       {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
+
+/* 105 Series */
+       {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
+
+/* 135 Series */
+       {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
+
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT  0x041
+
+#ifndef CONFIG_IWLWIFI_IDI
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
+       struct iwl_trans *iwl_trans;
+       struct iwl_trans_pcie *trans_pcie;
+
+       iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
+       if (iwl_trans == NULL)
+               return -ENOMEM;
+
+       pci_set_drvdata(pdev, iwl_trans);
+
+       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
+       trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
+       if (!trans_pcie->drv)
+               goto out_free_trans;
+
+       return 0;
+
+out_free_trans:
+       iwl_trans_pcie_free(iwl_trans);
+       pci_set_drvdata(pdev, NULL);
+       return -EFAULT;
+}
+
+static void __devexit iwl_pci_remove(struct pci_dev *pdev)
+{
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_drv_stop(trans_pcie->drv);
+       iwl_trans_pcie_free(trans);
+
+       pci_set_drvdata(pdev, NULL);
+}
+
+#endif /* CONFIG_IWLWIFI_IDI */
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwl_pci_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+
+       /* Before you put code here, think about WoWLAN. You cannot check here
+        * whether WoWLAN is enabled or not, and your code will run even if
+        * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx.
+        */
+
+       return iwl_trans_suspend(iwl_trans);
+}
+
+static int iwl_pci_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *iwl_trans = pci_get_drvdata(pdev);
+
+       /* Before you put code here, think about WoWLAN. You cannot check here
+        * whether WoWLAN is enabled or not, and your code will run even if
+        * WoWLAN is enabled - the NIC may be alive.
+        */
+
+       /*
+        * We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state.
+        */
+       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
+       return iwl_trans_resume(iwl_trans);
+}
+
+static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+
+#define IWL_PM_OPS     (&iwl_dev_pm_ops)
+
+#else
+
+#define IWL_PM_OPS     NULL
+
+#endif
+
+#ifdef CONFIG_IWLWIFI_IDI
+/*
+ * Defined externally in iwl-idi.c
+ */
+int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+void __devexit iwl_pci_remove(struct pci_dev *pdev);
+
+#endif /* CONFIG_IWLWIFI_IDI */
+
+static struct pci_driver iwl_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = iwl_hw_card_ids,
+       .probe = iwl_pci_probe,
+       .remove = __devexit_p(iwl_pci_remove),
+       .driver.pm = IWL_PM_OPS,
+};
+
+int __must_check iwl_pci_register_driver(void)
+{
+       int ret;
+       ret = pci_register_driver(&iwl_pci_driver);
+       if (ret)
+               pr_err("Unable to initialize PCI module\n");
+
+       return ret;
+}
+
+void iwl_pci_unregister_driver(void)
+{
+       pci_unregister_driver(&iwl_pci_driver);
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
new file mode 100644 (file)
index 0000000..5024fb6
--- /dev/null
@@ -0,0 +1,440 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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_trans_int_pcie_h__
+#define __iwl_trans_int_pcie_h__
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+
+#include "iwl-fh.h"
+#include "iwl-csr.h"
+#include "iwl-trans.h"
+#include "iwl-debug.h"
+#include "iwl-io.h"
+#include "iwl-op-mode.h"
+
+struct iwl_host_cmd;
+
+/*This file includes the declaration that are internal to the
+ * trans_pcie layer */
+
+struct iwl_rx_mem_buffer {
+       dma_addr_t page_dma;
+       struct page *page;
+       struct list_head list;
+};
+
+/**
+ * struct isr_statistics - interrupt statistics
+ *
+ */
+struct isr_statistics {
+       u32 hw;
+       u32 sw;
+       u32 err_code;
+       u32 sch;
+       u32 alive;
+       u32 rfkill;
+       u32 ctkill;
+       u32 wakeup;
+       u32 rx;
+       u32 tx;
+       u32 unhandled;
+};
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
+ * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @pool:
+ * @queue:
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @write_actual:
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ * @rb_stts: driver's pointer to receive buffer status
+ * @rb_stts_dma: bus address of receive buffer status
+ * @lock:
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+       __le32 *bd;
+       dma_addr_t bd_dma;
+       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+       u32 read;
+       u32 write;
+       u32 free_count;
+       u32 write_actual;
+       struct list_head rx_free;
+       struct list_head rx_used;
+       int need_update;
+       struct iwl_rb_status *rb_stts;
+       dma_addr_t rb_stts_dma;
+       spinlock_t lock;
+};
+
+struct iwl_dma_ptr {
+       dma_addr_t dma;
+       void *addr;
+       size_t size;
+};
+
+/**
+ * iwl_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+       return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+       return --index & (n_bd - 1);
+}
+
+struct iwl_cmd_meta {
+       /* only for SYNC commands, iff the reply skb is wanted */
+       struct iwl_host_cmd *source;
+
+       DEFINE_DMA_UNMAP_ADDR(mapping);
+       DEFINE_DMA_UNMAP_LEN(len);
+
+       u32 flags;
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ *  SW entries:           | 0      | ... | 31          |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
+ */
+struct iwl_queue {
+       int n_bd;              /* number of BDs in this queue */
+       int write_ptr;       /* 1-st empty entry (index) host_w*/
+       int read_ptr;         /* last used entry (index) host_r*/
+       /* use for monitoring and recovering the stuck queue */
+       dma_addr_t dma_addr;   /* physical addr for BD's */
+       int n_window;          /* safe queue window */
+       u32 id;
+       int low_mark;          /* low watermark, resume queue if free
+                               * space more than this */
+       int high_mark;         /* high watermark, stop queue if free
+                               * space less than this */
+};
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+struct iwl_pcie_tx_queue_entry {
+       struct iwl_device_cmd *cmd;
+       struct sk_buff *skb;
+       struct iwl_cmd_meta meta;
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @tfds: transmit frame descriptors (DMA memory)
+ * @entries: transmit entries (driver state)
+ * @lock: queue lock
+ * @stuck_timer: timer that fires if queue gets stuck
+ * @trans_pcie: pointer back to transport (for timer)
+ * @need_update: indicates need to update read/write index
+ * @active: stores if queue is active
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl_tx_queue {
+       struct iwl_queue q;
+       struct iwl_tfd *tfds;
+       struct iwl_pcie_tx_queue_entry *entries;
+       spinlock_t lock;
+       struct timer_list stuck_timer;
+       struct iwl_trans_pcie *trans_pcie;
+       u8 need_update;
+       u8 active;
+};
+
+/**
+ * struct iwl_trans_pcie - PCIe transport specific data
+ * @rxq: all the RX queue data
+ * @rx_replenish: work that will be called when buffers need to be allocated
+ * @drv - pointer to iwl_drv
+ * @trans: pointer to the generic transport area
+ * @irq - the irq number for the device
+ * @irq_requested: true when the irq has been requested
+ * @scd_base_addr: scheduler sram base address in SRAM
+ * @scd_bc_tbls: pointer to the byte count table of the scheduler
+ * @kw: keep warm address
+ * @pci_dev: basic pci-network driver stuff
+ * @hw_base: pci hardware address support
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_write_waitq: wait queue for uCode load
+ * @status - transport specific status flags
+ * @cmd_queue - command queue number
+ * @rx_buf_size_8k: 8 kB RX buffer size
+ * @rx_page_order: page order for receive buffer size
+ * @wd_timeout: queue watchdog timeout (jiffies)
+ */
+struct iwl_trans_pcie {
+       struct iwl_rx_queue rxq;
+       struct work_struct rx_replenish;
+       struct iwl_trans *trans;
+       struct iwl_drv *drv;
+
+       /* INT ICT Table */
+       __le32 *ict_tbl;
+       dma_addr_t ict_tbl_dma;
+       int ict_index;
+       u32 inta;
+       bool use_ict;
+       bool irq_requested;
+       struct tasklet_struct irq_tasklet;
+       struct isr_statistics isr_stats;
+
+       unsigned int irq;
+       spinlock_t irq_lock;
+       u32 inta_mask;
+       u32 scd_base_addr;
+       struct iwl_dma_ptr scd_bc_tbls;
+       struct iwl_dma_ptr kw;
+
+       struct iwl_tx_queue *txq;
+       unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+       unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
+
+       /* PCI bus related data */
+       struct pci_dev *pci_dev;
+       void __iomem *hw_base;
+
+       bool ucode_write_complete;
+       wait_queue_head_t ucode_write_waitq;
+       unsigned long status;
+       u8 cmd_queue;
+       u8 n_no_reclaim_cmds;
+       u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
+       u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES];
+       u8 n_q_to_fifo;
+
+       bool rx_buf_size_8k;
+       u32 rx_page_order;
+
+       const char **command_names;
+
+       /* queue watchdog */
+       unsigned long wd_timeout;
+};
+
+/*****************************************************
+* DRIVER STATUS FUNCTIONS
+******************************************************/
+#define STATUS_HCMD_ACTIVE     0
+#define STATUS_DEVICE_ENABLED  1
+#define STATUS_TPOWER_PMI      2
+#define STATUS_INT_ENABLED     3
+
+#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
+       ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
+
+static inline struct iwl_trans *
+iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
+{
+       return container_of((void *)trans_pcie, struct iwl_trans,
+                           trans_specific);
+}
+
+struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
+                                      const struct pci_device_id *ent,
+                                      const struct iwl_cfg *cfg);
+void iwl_trans_pcie_free(struct iwl_trans *trans);
+
+/*****************************************************
+* RX
+******************************************************/
+void iwl_bg_rx_replenish(struct work_struct *data);
+void iwl_irq_tasklet(struct iwl_trans *trans);
+void iwlagn_rx_replenish(struct iwl_trans *trans);
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+                                  struct iwl_rx_queue *q);
+
+/*****************************************************
+* ICT
+******************************************************/
+void iwl_reset_ict(struct iwl_trans *trans);
+void iwl_disable_ict(struct iwl_trans *trans);
+int iwl_alloc_isr_ict(struct iwl_trans *trans);
+void iwl_free_isr_ict(struct iwl_trans *trans);
+irqreturn_t iwl_isr_ict(int irq, void *data);
+
+/*****************************************************
+* TX / HCMD
+******************************************************/
+void iwl_txq_update_write_ptr(struct iwl_trans *trans,
+                             struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
+                                struct iwl_tx_queue *txq,
+                                dma_addr_t addr, u16 len, u8 reset);
+int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
+int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
+void iwl_tx_cmd_complete(struct iwl_trans *trans,
+                        struct iwl_rx_cmd_buffer *rxb, int handler_status);
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+                                      struct iwl_tx_queue *txq,
+                                      u16 byte_cnt);
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
+                              int sta_id, int tid, int frame_limit, u16 ssn);
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+                     enum dma_data_direction dma_dir);
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+                        struct sk_buff_head *skbs);
+int iwl_queue_space(const struct iwl_queue *q);
+
+/*****************************************************
+* Error handling
+******************************************************/
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
+void iwl_dump_csr(struct iwl_trans *trans);
+
+/*****************************************************
+* Helpers
+******************************************************/
+static inline void iwl_disable_interrupts(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+
+       /* disable interrupts from uCode/NIC to host */
+       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+       /* acknowledge/clear/reset any interrupts still pending
+        * from uCode or flow handler (Rx/Tx DMA) */
+       iwl_write32(trans, CSR_INT, 0xffffffff);
+       iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
+       IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
+       set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+}
+
+static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
+{
+       IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
+       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
+static inline void iwl_wake_queue(struct iwl_trans *trans,
+                                 struct iwl_tx_queue *txq)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (test_and_clear_bit(txq->q.id, trans_pcie->queue_stopped)) {
+               IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->q.id);
+               iwl_op_mode_queue_not_full(trans->op_mode, txq->q.id);
+       }
+}
+
+static inline void iwl_stop_queue(struct iwl_trans *trans,
+                                 struct iwl_tx_queue *txq)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (!test_and_set_bit(txq->q.id, trans_pcie->queue_stopped)) {
+               iwl_op_mode_queue_full(trans->op_mode, txq->q.id);
+               IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->q.id);
+       } else
+               IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n",
+                                   txq->q.id);
+}
+
+static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+{
+       return q->write_ptr >= q->read_ptr ?
+               (i >= q->read_ptr && i < q->write_ptr) :
+               !(i < q->read_ptr && i >= q->write_ptr);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
+{
+       return index & (q->n_window - 1);
+}
+
+static inline const char *
+trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd)
+{
+       if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
+               return "UNKNOWN";
+       return trans_pcie->command_names[cmd];
+}
+
+static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
+{
+       return !(iwl_read32(trans, CSR_GP_CNTRL) &
+               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
+}
+
+#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
new file mode 100644 (file)
index 0000000..be143eb
--- /dev/null
@@ -0,0 +1,1056 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/sched.h>
+#include <linux/wait.h>
+#include <linux/gfp.h>
+
+#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "internal.h"
+#include "iwl-op-mode.h"
+
+#ifdef CONFIG_IWLWIFI_IDI
+#include "iwl-amfh.h"
+#endif
+
+/******************************************************************************
+ *
+ * RX path functions
+ *
+ ******************************************************************************/
+
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by the NIC.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the NIC.  The driver and NIC manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc()   Allocates rx_free
+ * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+       int s = q->read - q->write;
+       if (s <= 0)
+               s += RX_QUEUE_SIZE;
+       /* keep some buffer to not confuse full and empty queue */
+       s -= 2;
+       if (s < 0)
+               s = 0;
+       return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
+                                  struct iwl_rx_queue *q)
+{
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&q->lock, flags);
+
+       if (q->need_update == 0)
+               goto exit_unlock;
+
+       if (trans->cfg->base_params->shadow_reg_enable) {
+               /* shadow register enabled */
+               /* Device expects a multiple of 8 */
+               q->write_actual = (q->write & ~0x7);
+               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual);
+       } else {
+               struct iwl_trans_pcie *trans_pcie =
+                       IWL_TRANS_GET_PCIE_TRANS(trans);
+
+               /* If power-saving is in use, make sure device is awake */
+               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                               IWL_DEBUG_INFO(trans,
+                                       "Rx queue requesting wakeup,"
+                                       " GP1 = 0x%x\n", reg);
+                               iwl_set_bit(trans, CSR_GP_CNTRL,
+                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                               goto exit_unlock;
+                       }
+
+                       q->write_actual = (q->write & ~0x7);
+                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
+                                       q->write_actual);
+
+               /* Else device is assumed to be awake */
+               } else {
+                       /* Device expects a multiple of 8 */
+                       q->write_actual = (q->write & ~0x7);
+                       iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR,
+                               q->write_actual);
+               }
+       }
+       q->need_update = 0;
+
+ exit_unlock:
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+
+/**
+ * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr)
+{
+       return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static void iwlagn_rx_queue_restock(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+               /* The overwritten rxb must be a used one */
+               rxb = rxq->queue[rxq->write];
+               BUG_ON(rxb && rxb->page);
+
+               /* Get next free Rx buffer, remove from free list */
+               element = rxq->rx_free.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               /* Point to Rx buffer via next RBD in circular buffer */
+               rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma);
+               rxq->queue[rxq->write] = rxb;
+               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+               rxq->free_count--;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               schedule_work(&trans_pcie->rx_replenish);
+
+
+       /* If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8. */
+       if (rxq->write_actual != (rxq->write & ~0x7)) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               rxq->need_update = 1;
+               spin_unlock_irqrestore(&rxq->lock, flags);
+               iwl_rx_queue_update_write_ptr(trans, rxq);
+       }
+}
+
+/**
+ * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       struct page *page;
+       unsigned long flags;
+       gfp_t gfp_mask = priority;
+
+       while (1) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       return;
+               }
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
+
+               if (trans_pcie->rx_page_order > 0)
+                       gfp_mask |= __GFP_COMP;
+
+               /* Alloc a new receive buffer */
+               page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+               if (!page) {
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(trans, "alloc_pages failed, "
+                                          "order: %d\n",
+                                          trans_pcie->rx_page_order);
+
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(trans, "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 */
+                       return;
+               }
+
+               spin_lock_irqsave(&rxq->lock, flags);
+
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       __free_pages(page, trans_pcie->rx_page_order);
+                       return;
+               }
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               BUG_ON(rxb->page);
+               rxb->page = page;
+               /* Get physical address of the RB */
+               rxb->page_dma =
+                       dma_map_page(trans->dev, page, 0,
+                                    PAGE_SIZE << trans_pcie->rx_page_order,
+                                    DMA_FROM_DEVICE);
+               /* dma address must be no more than 36 bits */
+               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+               /* and also 256 byte aligned! */
+               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++;
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+       }
+}
+
+void iwlagn_rx_replenish(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       iwlagn_rx_allocate(trans, GFP_KERNEL);
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwlagn_rx_queue_restock(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+static void iwlagn_rx_replenish_now(struct iwl_trans *trans)
+{
+       iwlagn_rx_allocate(trans, GFP_ATOMIC);
+
+       iwlagn_rx_queue_restock(trans);
+}
+
+void iwl_bg_rx_replenish(struct work_struct *data)
+{
+       struct iwl_trans_pcie *trans_pcie =
+           container_of(data, struct iwl_trans_pcie, rx_replenish);
+
+       iwlagn_rx_replenish(trans_pcie->trans);
+}
+
+static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       unsigned long flags;
+       bool page_stolen = false;
+       int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
+       u32 offset = 0;
+
+       if (WARN_ON(!rxb))
+               return;
+
+       dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE);
+
+       while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {
+               struct iwl_rx_packet *pkt;
+               struct iwl_device_cmd *cmd;
+               u16 sequence;
+               bool reclaim;
+               int index, cmd_index, err, len;
+               struct iwl_rx_cmd_buffer rxcb = {
+                       ._offset = offset,
+                       ._page = rxb->page,
+                       ._page_stolen = false,
+                       .truesize = max_len,
+               };
+
+               pkt = rxb_addr(&rxcb);
+
+               if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
+                       break;
+
+               IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
+                       rxcb._offset,
+                       trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd),
+                       pkt->hdr.cmd);
+
+               len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+               len += sizeof(u32); /* account for status word */
+               trace_iwlwifi_dev_rx(trans->dev, pkt, len);
+
+               /* Reclaim a command buffer only if this packet is a response
+                *   to a (driver-originated) command.
+                * If the packet (e.g. Rx frame) originated from uCode,
+                *   there is no command buffer to reclaim.
+                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+                *   but apparently a few don't get set; catch them here. */
+               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
+               if (reclaim) {
+                       int i;
+
+                       for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
+                               if (trans_pcie->no_reclaim_cmds[i] ==
+                                                       pkt->hdr.cmd) {
+                                       reclaim = false;
+                                       break;
+                               }
+                       }
+               }
+
+               sequence = le16_to_cpu(pkt->hdr.sequence);
+               index = SEQ_TO_INDEX(sequence);
+               cmd_index = get_cmd_index(&txq->q, index);
+
+               if (reclaim)
+                       cmd = txq->entries[cmd_index].cmd;
+               else
+                       cmd = NULL;
+
+               err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
+
+               /*
+                * After here, we should always check rxcb._page_stolen,
+                * if it is true then one of the handlers took the page.
+                */
+
+               if (reclaim) {
+                       /* Invoke any callbacks, transfer the buffer to caller,
+                        * and fire off the (possibly) blocking
+                        * iwl_trans_send_cmd()
+                        * as we reclaim the driver command queue */
+                       if (!rxcb._page_stolen)
+                               iwl_tx_cmd_complete(trans, &rxcb, err);
+                       else
+                               IWL_WARN(trans, "Claim null rxb?\n");
+               }
+
+               page_stolen |= rxcb._page_stolen;
+               offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN);
+       }
+
+       /* page was stolen from us -- free our reference */
+       if (page_stolen) {
+               __free_pages(rxb->page, trans_pcie->rx_page_order);
+               rxb->page = 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);
+       if (rxb->page != NULL) {
+               rxb->page_dma =
+                       dma_map_page(trans->dev, rxb->page, 0,
+                                    PAGE_SIZE << trans_pcie->rx_page_order,
+                                    DMA_FROM_DEVICE);
+               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);
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       u32 r, i;
+       u8 fill_rx = 0;
+       u32 count = 8;
+       int total_empty;
+
+       /* uCode's read index (stored in shared DRAM) indicates the last Rx
+        * buffer that the driver may process (last buffer filled by ucode). */
+       r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
+       i = rxq->read;
+
+       /* Rx interrupt, but nothing sent from uCode */
+       if (i == r)
+               IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
+
+       /* calculate total frames need to be restock after handling RX */
+       total_empty = r - rxq->write_actual;
+       if (total_empty < 0)
+               total_empty += RX_QUEUE_SIZE;
+
+       if (total_empty > (RX_QUEUE_SIZE / 2))
+               fill_rx = 1;
+
+       while (i != r) {
+               struct iwl_rx_mem_buffer *rxb;
+
+               rxb = rxq->queue[i];
+               rxq->queue[i] = NULL;
+
+               IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",
+                            r, i, rxb);
+               iwl_rx_handle_rxbuf(trans, rxb);
+
+               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) {
+                               rxq->read = i;
+                               iwlagn_rx_replenish_now(trans);
+                               count = 0;
+                       }
+               }
+       }
+
+       /* Backtrack one entry */
+       rxq->read = i;
+       if (fill_rx)
+               iwlagn_rx_replenish_now(trans);
+       else
+               iwlagn_rx_queue_restock(trans);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_trans *trans)
+{
+       /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
+       if (trans->cfg->internal_wimax_coex &&
+           (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
+                            APMS_CLK_VAL_MRB_FUNC_MODE) ||
+            (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
+                           APMG_PS_CTRL_VAL_RESET_REQ))) {
+               struct iwl_trans_pcie *trans_pcie =
+                       IWL_TRANS_GET_PCIE_TRANS(trans);
+
+               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               iwl_op_mode_wimax_active(trans->op_mode);
+               wake_up(&trans->wait_command_queue);
+               return;
+       }
+
+       iwl_dump_csr(trans);
+       iwl_dump_fh(trans, NULL, false);
+
+       iwl_op_mode_nic_error(trans->op_mode);
+}
+
+/* tasklet for iwlagn interrupt */
+void iwl_irq_tasklet(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+       u32 inta = 0;
+       u32 handled = 0;
+       unsigned long flags;
+       u32 i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       u32 inta_mask;
+#endif
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       /* Ack/clear/reset pending uCode interrupts.
+        * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+        */
+       /* There is a hardware bug in the interrupt mask function that some
+        * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if
+        * they are disabled in the CSR_INT_MASK register. Furthermore the
+        * ICT interrupt handling mechanism has another bug that might cause
+        * these unmasked interrupts fail to be detected. We workaround the
+        * hardware bugs here by ACKing all the possible interrupts so that
+        * interrupt coalescing can still be achieved.
+        */
+       iwl_write32(trans, CSR_INT,
+                   trans_pcie->inta | ~trans_pcie->inta_mask);
+
+       inta = trans_pcie->inta;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
+               /* just for debug */
+               inta_mask = iwl_read32(trans, CSR_INT_MASK);
+               IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
+                             inta, inta_mask);
+       }
+#endif
+
+       /* saved interrupt in inta variable now we can reset trans_pcie->inta */
+       trans_pcie->inta = 0;
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       /* Now service all interrupt bits discovered above. */
+       if (inta & CSR_INT_BIT_HW_ERR) {
+               IWL_ERR(trans, "Hardware error detected.  Restarting.\n");
+
+               /* Tell the device to stop sending interrupts */
+               iwl_disable_interrupts(trans);
+
+               isr_stats->hw++;
+               iwl_irq_handle_error(trans);
+
+               handled |= CSR_INT_BIT_HW_ERR;
+
+               return;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
+               /* NIC fires this, but we don't use it, redundant with WAKEUP */
+               if (inta & CSR_INT_BIT_SCD) {
+                       IWL_DEBUG_ISR(trans, "Scheduler finished to transmit "
+                                     "the frame/frames.\n");
+                       isr_stats->sch++;
+               }
+
+               /* Alive notification via Rx interrupt will do the real work */
+               if (inta & CSR_INT_BIT_ALIVE) {
+                       IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+                       isr_stats->alive++;
+               }
+       }
+#endif
+       /* Safely ignore these bits for debug checks below */
+       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
+
+       /* HW RF KILL switch toggled */
+       if (inta & CSR_INT_BIT_RF_KILL) {
+               bool hw_rfkill;
+
+               hw_rfkill = iwl_is_rfkill_set(trans);
+               IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
+                        hw_rfkill ? "disable radio" : "enable radio");
+
+               isr_stats->rfkill++;
+
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+               handled |= CSR_INT_BIT_RF_KILL;
+       }
+
+       /* Chip got too hot and stopped itself */
+       if (inta & CSR_INT_BIT_CT_KILL) {
+               IWL_ERR(trans, "Microcode CT kill error detected.\n");
+               isr_stats->ctkill++;
+               handled |= CSR_INT_BIT_CT_KILL;
+       }
+
+       /* Error detected by uCode */
+       if (inta & CSR_INT_BIT_SW_ERR) {
+               IWL_ERR(trans, "Microcode SW error detected. "
+                       " Restarting 0x%X.\n", inta);
+               isr_stats->sw++;
+               iwl_irq_handle_error(trans);
+               handled |= CSR_INT_BIT_SW_ERR;
+       }
+
+       /* uCode wakes up after power-down sleep */
+       if (inta & CSR_INT_BIT_WAKEUP) {
+               IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
+               iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
+               for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
+                       iwl_txq_update_write_ptr(trans,
+                                                &trans_pcie->txq[i]);
+
+               isr_stats->wakeup++;
+
+               handled |= CSR_INT_BIT_WAKEUP;
+       }
+
+       /* All uCode command responses, including Tx command responses,
+        * Rx "responses" (frame-received notification), and other
+        * notifications from uCode come through here*/
+       if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
+                   CSR_INT_BIT_RX_PERIODIC)) {
+               IWL_DEBUG_ISR(trans, "Rx interrupt\n");
+               if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+                       handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+                       iwl_write32(trans, CSR_FH_INT_STATUS,
+                                       CSR_FH_INT_RX_MASK);
+               }
+               if (inta & CSR_INT_BIT_RX_PERIODIC) {
+                       handled |= CSR_INT_BIT_RX_PERIODIC;
+                       iwl_write32(trans,
+                               CSR_INT, CSR_INT_BIT_RX_PERIODIC);
+               }
+               /* Sending RX interrupt require many steps to be done in the
+                * the device:
+                * 1- write interrupt to current index in ICT table.
+                * 2- dma RX frame.
+                * 3- update RX shared data to indicate last write index.
+                * 4- send interrupt.
+                * This could lead to RX race, driver could receive RX interrupt
+                * but the shared data changes does not reflect this;
+                * periodic interrupt will detect any dangling Rx activity.
+                */
+
+               /* Disable periodic interrupt; we use it as just a one-shot. */
+               iwl_write8(trans, CSR_INT_PERIODIC_REG,
+                           CSR_INT_PERIODIC_DIS);
+#ifdef CONFIG_IWLWIFI_IDI
+               iwl_amfh_rx_handler();
+#else
+               iwl_rx_handle(trans);
+#endif
+               /*
+                * Enable periodic interrupt in 8 msec only if we received
+                * real RX interrupt (instead of just periodic int), to catch
+                * any dangling Rx interrupt.  If it was just the periodic
+                * interrupt, there was no dangling Rx activity, and no need
+                * to extend the periodic interrupt; one-shot is enough.
+                */
+               if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
+                       iwl_write8(trans, CSR_INT_PERIODIC_REG,
+                                  CSR_INT_PERIODIC_ENA);
+
+               isr_stats->rx++;
+       }
+
+       /* This "Tx" DMA channel is used only for loading uCode */
+       if (inta & CSR_INT_BIT_FH_TX) {
+               iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
+               IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
+               isr_stats->tx++;
+               handled |= CSR_INT_BIT_FH_TX;
+               /* Wake up uCode load routine, now that load is complete */
+               trans_pcie->ucode_write_complete = true;
+               wake_up(&trans_pcie->ucode_write_waitq);
+       }
+
+       if (inta & ~handled) {
+               IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
+               isr_stats->unhandled++;
+       }
+
+       if (inta & ~(trans_pcie->inta_mask)) {
+               IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n",
+                        inta & ~trans_pcie->inta_mask);
+       }
+
+       /* Re-enable all interrupts */
+       /* only Re-enable if disabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
+               iwl_enable_interrupts(trans);
+       /* Re-enable RF_KILL if it occurred */
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(trans);
+}
+
+/******************************************************************************
+ *
+ * ICT functions
+ *
+ ******************************************************************************/
+
+/* a device (PCI-E) page is 4096 bytes long */
+#define ICT_SHIFT      12
+#define ICT_SIZE       (1 << ICT_SHIFT)
+#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (trans_pcie->ict_tbl) {
+               dma_free_coherent(trans->dev, ICT_SIZE,
+                                 trans_pcie->ict_tbl,
+                                 trans_pcie->ict_tbl_dma);
+               trans_pcie->ict_tbl = NULL;
+               trans_pcie->ict_tbl_dma = 0;
+       }
+}
+
+
+/*
+ * allocate dram shared table, it is an aligned memory
+ * block of ICT_SIZE.
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans_pcie->ict_tbl =
+               dma_alloc_coherent(trans->dev, ICT_SIZE,
+                                  &trans_pcie->ict_tbl_dma,
+                                  GFP_KERNEL);
+       if (!trans_pcie->ict_tbl)
+               return -ENOMEM;
+
+       /* just an API sanity check ... it is guaranteed to be aligned */
+       if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
+               iwl_free_isr_ict(trans);
+               return -EINVAL;
+       }
+
+       IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
+                     (unsigned long long)trans_pcie->ict_tbl_dma);
+
+       IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
+
+       /* reset table and index to all 0 */
+       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
+       trans_pcie->ict_index = 0;
+
+       /* add periodic RX interrupt */
+       trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+       return 0;
+}
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+void iwl_reset_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 val;
+       unsigned long flags;
+
+       if (!trans_pcie->ict_tbl)
+               return;
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_disable_interrupts(trans);
+
+       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
+
+       val = trans_pcie->ict_tbl_dma >> ICT_SHIFT;
+
+       val |= CSR_DRAM_INT_TBL_ENABLE;
+       val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+       IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val);
+
+       iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val);
+       trans_pcie->use_ict = true;
+       trans_pcie->ict_index = 0;
+       iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
+       iwl_enable_interrupts(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       trans_pcie->use_ict = false;
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+}
+
+/* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+       struct iwl_trans *trans = data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 inta, inta_mask;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       u32 inta_fh;
+#endif
+
+       lockdep_assert_held(&trans_pcie->irq_lock);
+
+       if (!trans)
+               return IRQ_NONE;
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        *    back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here. */
+       inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(trans, CSR_INT);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!inta) {
+               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /* Hardware disappeared. It might have already raised
+                * an interrupt */
+               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               return IRQ_HANDLED;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
+               inta_fh = iwl_read32(trans, CSR_FH_INT_STATUS);
+               IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, "
+                             "fh 0x%08x\n", inta, inta_mask, inta_fh);
+       }
+#endif
+
+       trans_pcie->inta |= inta;
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&trans_pcie->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+                !trans_pcie->inta)
+               iwl_enable_interrupts(trans);
+
+none:
+       /* re-enable interrupts here since we don't have anything to service. */
+       /* only Re-enable if disabled by irq  and no schedules tasklet. */
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+           !trans_pcie->inta)
+               iwl_enable_interrupts(trans);
+
+       return IRQ_NONE;
+}
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+       struct iwl_trans *trans = data;
+       struct iwl_trans_pcie *trans_pcie;
+       u32 inta, inta_mask;
+       u32 val = 0;
+       u32 read;
+       unsigned long flags;
+
+       if (!trans)
+               return IRQ_NONE;
+
+       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       /* dram interrupt table not set yet,
+        * use legacy interrupt.
+        */
+       if (unlikely(!trans_pcie->use_ict)) {
+               irqreturn_t ret = iwl_isr(irq, data);
+               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+               return ret;
+       }
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        * back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here.
+        */
+       inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
+       if (!read) {
+               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       /*
+        * Collect all entries up to the first 0, starting from ict_index;
+        * note we already read at ict_index.
+        */
+       do {
+               val |= read;
+               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
+                               trans_pcie->ict_index, read);
+               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
+               trans_pcie->ict_index =
+                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
+
+               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
+                                          read);
+       } while (read);
+
+       /* We should not get this value, just ignore it. */
+       if (val == 0xffffffff)
+               val = 0;
+
+       /*
+        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+        * (bit 15 before shifting it to 31) to clear when using interrupt
+        * coalescing. fortunately, bits 18 and 19 stay set when this happens
+        * so we use them to decide on the real state of the Rx bit.
+        * In order words, bit 15 is set if bit 18 or bit 19 are set.
+        */
+       if (val & 0xC0000)
+               val |= 0x8000;
+
+       inta = (0xff & val) | ((0xff00 & val) << 16);
+       IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+                     inta, inta_mask, val);
+
+       inta &= trans_pcie->inta_mask;
+       trans_pcie->inta |= inta;
+
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&trans_pcie->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+                !trans_pcie->inta) {
+               /* Allow interrupt if was disabled by this handler and
+                * no tasklet was schedules, We should not enable interrupt,
+                * tasklet will enable it.
+                */
+               iwl_enable_interrupts(trans);
+       }
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service.
+        * only Re-enable if disabled by irq.
+        */
+       if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+           !trans_pcie->inta)
+               iwl_enable_interrupts(trans);
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       return IRQ_NONE;
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
new file mode 100644 (file)
index 0000000..42f369d
--- /dev/null
@@ -0,0 +1,2219 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2012 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.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include "iwl-drv.h"
+#include "iwl-trans.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-agn-hw.h"
+#include "internal.h"
+/* FIXME: need to abstract out TX command (once we know what it looks like) */
+#include "dvm/commands.h"
+
+#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)      \
+       (((1<<trans->cfg->base_params->num_of_queues) - 1) &\
+       (~(1<<(trans_pcie)->cmd_queue)))
+
+static int iwl_trans_rx_alloc(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct device *dev = trans->dev;
+
+       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+
+       spin_lock_init(&rxq->lock);
+
+       if (WARN_ON(rxq->bd || rxq->rb_stts))
+               return -EINVAL;
+
+       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                                     &rxq->bd_dma, GFP_KERNEL);
+       if (!rxq->bd)
+               goto err_bd;
+
+       /*Allocate the driver's pointer to receive buffer status */
+       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                          &rxq->rb_stts_dma, GFP_KERNEL);
+       if (!rxq->rb_stts)
+               goto err_rb_stts;
+
+       return 0;
+
+err_rb_stts:
+       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                         rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+err_bd:
+       return -ENOMEM;
+}
+
+static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       int i;
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       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].page != NULL) {
+                       dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
+                                      PAGE_SIZE << trans_pcie->rx_page_order,
+                                      DMA_FROM_DEVICE);
+                       __free_pages(rxq->pool[i].page,
+                                    trans_pcie->rx_page_order);
+                       rxq->pool[i].page = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+}
+
+static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
+                                struct iwl_rx_queue *rxq)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 rb_size;
+       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+       u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+       if (trans_pcie->rx_buf_size_8k)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          (u32)(rxq->bd_dma >> 8));
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          rxq->rb_stts_dma >> 4);
+
+       /* Enable Rx DMA
+        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+        *      the credit mechanism in 5000 HW RX FIFO
+        * Direct rx interrupts to hosts
+        * Rx buffer size 4 or 8k
+        * RB timeout 0x10
+        * 256 RBDs
+        */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          rb_size|
+                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+}
+
+static int iwl_rx_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+       int i, err;
+       unsigned long flags;
+
+       if (!rxq->bd) {
+               err = iwl_trans_rx_alloc(trans);
+               if (err)
+                       return err;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       iwl_trans_rxq_free_rx_bufs(trans);
+
+       for (i = 0; i < RX_QUEUE_SIZE; i++)
+               rxq->queue[i] = NULL;
+
+       /* 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->write_actual = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       iwlagn_rx_replenish(trans);
+
+       iwl_trans_rx_hw_init(trans, rxq);
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       rxq->need_update = 1;
+       iwl_rx_queue_update_write_ptr(trans, rxq);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       unsigned long flags;
+
+       /*if rxq->bd is NULL, it means that nothing has been allocated,
+        * exit now */
+       if (!rxq->bd) {
+               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
+               return;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       iwl_trans_rxq_free_rx_bufs(trans);
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                         rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+
+       if (rxq->rb_stts)
+               dma_free_coherent(trans->dev,
+                                 sizeof(struct iwl_rb_status),
+                                 rxq->rb_stts, rxq->rb_stts_dma);
+       else
+               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
+       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+       rxq->rb_stts = NULL;
+}
+
+static int iwl_trans_rx_stop(struct iwl_trans *trans)
+{
+
+       /* stop Rx DMA */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
+                                  FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
+static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
+                               struct iwl_dma_ptr *ptr, size_t size)
+{
+       if (WARN_ON(ptr->addr))
+               return -EINVAL;
+
+       ptr->addr = dma_alloc_coherent(trans->dev, size,
+                                      &ptr->dma, GFP_KERNEL);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static void iwlagn_free_dma_ptr(struct iwl_trans *trans,
+                               struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
+static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
+{
+       struct iwl_tx_queue *txq = (void *)data;
+       struct iwl_queue *q = &txq->q;
+       struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
+       struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
+       u32 scd_sram_addr = trans_pcie->scd_base_addr +
+               SCD_TX_STTS_MEM_LOWER_BOUND + (16 * txq->q.id);
+       u8 buf[16];
+       int i;
+
+       spin_lock(&txq->lock);
+       /* check if triggered erroneously */
+       if (txq->q.read_ptr == txq->q.write_ptr) {
+               spin_unlock(&txq->lock);
+               return;
+       }
+       spin_unlock(&txq->lock);
+
+       IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
+               jiffies_to_msecs(trans_pcie->wd_timeout));
+       IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+               txq->q.read_ptr, txq->q.write_ptr);
+
+       iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+       iwl_print_hex_error(trans, buf, sizeof(buf));
+
+       for (i = 0; i < FH_TCSR_CHNL_NUM; i++)
+               IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i,
+                       iwl_read_direct32(trans, FH_TX_TRB_REG(i)));
+
+       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+               u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i));
+               u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+               bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+               u32 tbl_dw =
+                       iwl_read_targ_mem(trans,
+                                         trans_pcie->scd_base_addr +
+                                         SCD_TRANS_TBL_OFFSET_QUEUE(i));
+
+               if (i & 0x1)
+                       tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+               else
+                       tbl_dw = tbl_dw & 0x0000FFFF;
+
+               IWL_ERR(trans,
+                       "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+                       i, active ? "" : "in", fifo, tbl_dw,
+                       iwl_read_prph(trans,
+                                     SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1),
+                       iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
+       }
+
+       for (i = q->read_ptr; i != q->write_ptr;
+            i = iwl_queue_inc_wrap(i, q->n_bd)) {
+               struct iwl_tx_cmd *tx_cmd =
+                       (struct iwl_tx_cmd *)txq->entries[i].cmd->payload;
+               IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
+                       get_unaligned_le32(&tx_cmd->scratch));
+       }
+
+       iwl_op_mode_nic_error(trans->op_mode);
+}
+
+static int iwl_trans_txq_alloc(struct iwl_trans *trans,
+                              struct iwl_tx_queue *txq, int slots_num,
+                              u32 txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
+       int i;
+
+       if (WARN_ON(txq->entries || txq->tfds))
+               return -EINVAL;
+
+       setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
+                   (unsigned long)txq);
+       txq->trans_pcie = trans_pcie;
+
+       txq->q.n_window = slots_num;
+
+       txq->entries = kcalloc(slots_num,
+                              sizeof(struct iwl_pcie_tx_queue_entry),
+                              GFP_KERNEL);
+
+       if (!txq->entries)
+               goto error;
+
+       if (txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < slots_num; i++) {
+                       txq->entries[i].cmd =
+                               kmalloc(sizeof(struct iwl_device_cmd),
+                                       GFP_KERNEL);
+                       if (!txq->entries[i].cmd)
+                               goto error;
+               }
+
+       /* Circular buffer of transmit frame descriptors (TFDs),
+        * shared with device */
+       txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
+                                      &txq->q.dma_addr, GFP_KERNEL);
+       if (!txq->tfds) {
+               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+               goto error;
+       }
+       txq->q.id = txq_id;
+
+       return 0;
+error:
+       if (txq->entries && txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < slots_num; i++)
+                       kfree(txq->entries[i].cmd);
+       kfree(txq->entries);
+       txq->entries = NULL;
+
+       return -ENOMEM;
+
+}
+
+static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+                             int slots_num, u32 txq_id)
+{
+       int ret;
+
+       txq->need_update = 0;
+
+       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+       /* Initialize queue's high/low-water marks, and head/tail indexes */
+       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+                       txq_id);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&txq->lock);
+
+       /*
+        * Tell nic where to find circular buffer of Tx Frame Descriptors for
+        * given Tx queue, and enable the DMA channel used for that queue.
+        * Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+                            txq->q.dma_addr >> 8);
+
+       return 0;
+}
+
+/**
+ * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       enum dma_data_direction dma_dir;
+
+       if (!q->n_bd)
+               return;
+
+       /* In the command queue, all the TBs are mapped as BIDI
+        * so unmap them as such.
+        */
+       if (txq_id == trans_pcie->cmd_queue)
+               dma_dir = DMA_BIDIRECTIONAL;
+       else
+               dma_dir = DMA_TO_DEVICE;
+
+       spin_lock_bh(&txq->lock);
+       while (q->write_ptr != q->read_ptr) {
+               iwl_txq_free_tfd(trans, txq, dma_dir);
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+       }
+       spin_unlock_bh(&txq->lock);
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct device *dev = trans->dev;
+       int i;
+
+       if (WARN_ON(!txq))
+               return;
+
+       iwl_tx_queue_unmap(trans, txq_id);
+
+       /* De-alloc array of command/tx buffers */
+
+       if (txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < txq->q.n_window; i++)
+                       kfree(txq->entries[i].cmd);
+
+       /* De-alloc circular buffer of TFDs */
+       if (txq->q.n_bd) {
+               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
+                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+       }
+
+       kfree(txq->entries);
+       txq->entries = NULL;
+
+       del_timer_sync(&txq->stuck_timer);
+
+       /* 0-fill queue descriptor structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
+{
+       int txq_id;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       /* Tx queues */
+       if (trans_pcie->txq) {
+               for (txq_id = 0;
+                    txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
+                       iwl_tx_queue_free(trans, txq_id);
+       }
+
+       kfree(trans_pcie->txq);
+       trans_pcie->txq = NULL;
+
+       iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
+
+       iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
+}
+
+/**
+ * iwl_trans_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl_trans_tx_alloc(struct iwl_trans *trans)
+{
+       int ret;
+       int txq_id, slots_num;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+
+       /*It is not allowed to alloc twice, so warn when this happens.
+        * We cannot rely on the previous allocation, so free and fail */
+       if (WARN_ON(trans_pcie->txq)) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
+                                  scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
+               goto error;
+       }
+
+       /* Alloc keep-warm buffer */
+       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
+       if (ret) {
+               IWL_ERR(trans, "Keep Warm allocation failed\n");
+               goto error;
+       }
+
+       trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
+                                 sizeof(struct iwl_tx_queue), GFP_KERNEL);
+       if (!trans_pcie->txq) {
+               IWL_ERR(trans, "Not enough memory for txq\n");
+               ret = ENOMEM;
+               goto error;
+       }
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
+                                         slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       iwl_trans_pcie_tx_free(trans);
+
+       return ret;
+}
+static int iwl_tx_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+       int txq_id, slots_num;
+       unsigned long flags;
+       bool alloc = false;
+
+       if (!trans_pcie->txq) {
+               ret = iwl_trans_tx_alloc(trans);
+               if (ret)
+                       goto error;
+               alloc = true;
+       }
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       iwl_write_prph(trans, SCD_TXFACT, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+                          trans_pcie->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
+                                        slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+error:
+       /*Upon error, free only if we allocated something */
+       if (alloc)
+               iwl_trans_pcie_tx_free(trans);
+       return ret;
+}
+
+static void iwl_set_pwr_vmain(struct iwl_trans *trans)
+{
+/*
+ * (for documentation purposes)
+ * to set power to V_AUX, do:
+
+               if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
+                       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+ */
+
+       iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG,
+                              APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+}
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT  0x041
+#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
+#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
+
+static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int pos;
+       u16 pci_lnk_ctl;
+
+       struct pci_dev *pci_dev = trans_pcie->pci_dev;
+
+       pos = pci_pcie_cap(pci_dev);
+       pci_read_config_word(pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
+       return pci_lnk_ctl;
+}
+
+static void iwl_apm_config(struct iwl_trans *trans)
+{
+       /*
+        * HW bug W/A for instability in PCIe bus L0S->L1 transition.
+        * Check if BIOS (or OS) enabled L1-ASPM on this device.
+        * If so (likely), disable L0S, so device moves directly L0->L1;
+        *    costs negligible amount of power savings.
+        * If not (unlikely), enable L0S, so there is at least some
+        *    power savings, even without L1.
+        */
+       u16 lctl = iwl_pciexp_link_ctrl(trans);
+
+       if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+                               PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+               /* L1-ASPM enabled; disable(!) L0S */
+               iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+               dev_printk(KERN_INFO, trans->dev,
+                          "L1 Enabled; Disabling L0S\n");
+       } else {
+               /* L1-ASPM disabled; enable(!) L0S */
+               iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+               dev_printk(KERN_INFO, trans->dev,
+                          "L1 Disabled; Enabling L0S\n");
+       }
+       trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
+}
+
+/*
+ * 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
+ */
+static int iwl_apm_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret = 0;
+       IWL_DEBUG_INFO(trans, "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(trans, 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(trans, 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(trans, 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
+        */
+       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+                   CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+
+       iwl_apm_config(trans);
+
+       /* Configure analog phase-lock-loop before activating to D0A */
+       if (trans->cfg->base_params->pll_cfg_val)
+               iwl_set_bit(trans, CSR_ANA_PLL_CFG,
+                           trans->cfg->base_params->pll_cfg_val);
+
+       /*
+        * Set "initialization complete" bit to move adapter from
+        * D0U* --> D0A* (powered-up active) state.
+        */
+       iwl_set_bit(trans, 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(trans, 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(trans, "Failed to init the card\n");
+               goto out;
+       }
+
+       /*
+        * Enable DMA clock and wait for it to stabilize.
+        *
+        * 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.
+        */
+       iwl_write_prph(trans, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+       udelay(20);
+
+       /* Disable L1-Active */
+       iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+       set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+
+out:
+       return ret;
+}
+
+static int iwl_apm_stop_master(struct iwl_trans *trans)
+{
+       int ret = 0;
+
+       /* stop device's busmaster DMA activity */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+       ret = iwl_poll_bit(trans, CSR_RESET,
+                          CSR_RESET_REG_FLAG_MASTER_DISABLED,
+                          CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+       if (ret)
+               IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
+
+       IWL_DEBUG_INFO(trans, "stop master\n");
+
+       return ret;
+}
+
+static void iwl_apm_stop(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
+
+       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+
+       /* Stop device's DMA activity */
+       iwl_apm_stop_master(trans);
+
+       /* Reset the entire device */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       udelay(10);
+
+       /*
+        * Clear "initialization complete" bit to move adapter from
+        * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
+        */
+       iwl_clear_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+}
+
+static int iwl_nic_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       /* nic_init */
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_apm_init(trans);
+
+       /* Set interrupt coalescing calibration timer to default (512 usecs) */
+       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       iwl_set_pwr_vmain(trans);
+
+       iwl_op_mode_nic_config(trans->op_mode);
+
+#ifndef CONFIG_IWLWIFI_IDI
+       /* Allocate the RX queue, or reset if it is already allocated */
+       iwl_rx_init(trans);
+#endif
+
+       /* Allocate or reset and init all Tx and Command queues */
+       if (iwl_tx_init(trans))
+               return -ENOMEM;
+
+       if (trans->cfg->base_params->shadow_reg_enable) {
+               /* enable shadow regs in HW */
+               iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
+               IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
+       }
+
+       return 0;
+}
+
+#define HW_READY_TIMEOUT (50)
+
+/* Note: returns poll_bit return value, which is >= 0 if success */
+static int iwl_set_hw_ready(struct iwl_trans *trans)
+{
+       int ret;
+
+       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+                   CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+
+       /* See if we got it */
+       ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
+                          CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                          CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                          HW_READY_TIMEOUT);
+
+       IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
+       return ret;
+}
+
+/* Note: returns standard 0/-ERROR code */
+static int iwl_prepare_card_hw(struct iwl_trans *trans)
+{
+       int ret;
+
+       IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
+
+       ret = iwl_set_hw_ready(trans);
+       /* If the card is ready, exit 0 */
+       if (ret >= 0)
+               return 0;
+
+       /* If HW is not ready, prepare the conditions to check again */
+       iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+                   CSR_HW_IF_CONFIG_REG_PREPARE);
+
+       ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
+                          ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+                          CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+
+       if (ret < 0)
+               return ret;
+
+       /* HW should be ready by now, check again. */
+       ret = iwl_set_hw_ready(trans);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+/*
+ * ucode
+ */
+static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
+                           const struct fw_desc *section)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       dma_addr_t phy_addr = section->p_addr;
+       u32 byte_cnt = section->len;
+       u32 dst_addr = section->offset;
+       int ret;
+
+       trans_pcie->ucode_write_complete = false;
+
+       iwl_write_direct32(trans,
+                          FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+       iwl_write_direct32(trans,
+                          FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
+                          dst_addr);
+
+       iwl_write_direct32(trans,
+               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+       iwl_write_direct32(trans,
+                          FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+                          (iwl_get_dma_hi_addr(phy_addr)
+                               << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
+       iwl_write_direct32(trans,
+                          FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+                          1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+                          1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+                          FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+       iwl_write_direct32(trans,
+                          FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE    |
+                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
+                          FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+       IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
+                    section_num);
+       ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
+                                trans_pcie->ucode_write_complete, 5 * HZ);
+       if (!ret) {
+               IWL_ERR(trans, "Could not load the [%d] uCode section\n",
+                       section_num);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int iwl_load_given_ucode(struct iwl_trans *trans,
+                               const struct fw_img *image)
+{
+       int ret = 0;
+               int i;
+
+               for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
+                       if (!image->sec[i].p_addr)
+                               break;
+
+                       ret = iwl_load_section(trans, i, &image->sec[i]);
+                       if (ret)
+                               return ret;
+               }
+
+       /* Remove all resets to allow NIC to operate */
+       iwl_write32(trans, CSR_RESET, 0);
+
+       return 0;
+}
+
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+                                  const struct fw_img *fw)
+{
+       int ret;
+       bool hw_rfkill;
+
+       /* This may fail if AMT took ownership of the device */
+       if (iwl_prepare_card_hw(trans)) {
+               IWL_WARN(trans, "Exit HW not ready\n");
+               return -EIO;
+       }
+
+       iwl_enable_rfkill_int(trans);
+
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       if (hw_rfkill)
+               return -ERFKILL;
+
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       ret = iwl_nic_init(trans);
+       if (ret) {
+               IWL_ERR(trans, "Unable to init nic\n");
+               return ret;
+       }
+
+       /* make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+       /* clear (again), then enable host interrupts */
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+       iwl_enable_interrupts(trans);
+
+       /* really make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+       /* Load the given image to the HW */
+       return iwl_load_given_ucode(trans, fw);
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ */
+static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
+{
+       struct iwl_trans_pcie __maybe_unused *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_write_prph(trans, SCD_TXFACT, mask);
+}
+
+static void iwl_tx_start(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 a;
+       int i, chan;
+       u32 reg_val;
+
+       /* make sure all queue are not stopped/used */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+       trans_pcie->scd_base_addr =
+               iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
+       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
+       /* reset conext data memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+       /* reset tx status memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+       for (; a < trans_pcie->scd_base_addr +
+              SCD_TRANS_TBL_OFFSET_QUEUE(
+                               trans->cfg->base_params->num_of_queues);
+              a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+
+       iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
+                      trans_pcie->scd_bc_tbls.dma >> 10);
+
+       /* The chain extension of the SCD doesn't work well. This feature is
+        * enabled by default by the HW, so we need to disable it manually.
+        */
+       iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
+
+       for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
+               int fifo = trans_pcie->setup_q_to_fifo[i];
+
+               iwl_trans_pcie_txq_enable(trans, i, fifo, IWL_INVALID_STATION,
+                                         IWL_TID_NON_QOS, SCD_FRAME_LIMIT, 0);
+       }
+
+       /* Activate all Tx DMA/FIFO channels */
+       iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
+
+       /* Enable DMA channel */
+       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
+               iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+       /* Update FH chicken bits */
+       reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
+       iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
+                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+       /* Enable L1-Active */
+       iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
+                           APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+}
+
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
+{
+       iwl_reset_ict(trans);
+       iwl_tx_start(trans);
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+static int iwl_trans_tx_stop(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ch, txq_id, ret;
+       unsigned long flags;
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       iwl_trans_txq_set_sched(trans, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+               iwl_write_direct32(trans,
+                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
+                       FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
+               if (ret < 0)
+                       IWL_ERR(trans,
+                               "Failing on timeout while stopping DMA channel %d [0x%08x]",
+                               ch,
+                               iwl_read_direct32(trans,
+                                                 FH_TSSR_TX_STATUS_REG));
+       }
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       if (!trans_pcie->txq) {
+               IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
+               return 0;
+       }
+
+       /* Unmap DMA from host system and free skb's */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++)
+               iwl_tx_queue_unmap(trans, txq_id);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
+
+       /* tell the device to stop sending interrupts */
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       /* device going down, Stop using ICT table */
+       iwl_disable_ict(trans);
+
+       /*
+        * If a HW restart happens during firmware loading,
+        * then the firmware loading might call this function
+        * and later it might be called again due to the
+        * restart. So don't process again if the device is
+        * already dead.
+        */
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
+               iwl_trans_tx_stop(trans);
+#ifndef CONFIG_IWLWIFI_IDI
+               iwl_trans_rx_stop(trans);
+#endif
+               /* Power-down device's busmaster DMA clocks */
+               iwl_write_prph(trans, APMG_CLK_DIS_REG,
+                              APMG_CLK_VAL_DMA_CLK_RQT);
+               udelay(5);
+       }
+
+       /* Make sure (redundant) we've released our request to stay awake */
+       iwl_clear_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+       /* Stop the device, and put it in low power state */
+       iwl_apm_stop(trans);
+
+       /* Upon stop, the APM issues an interrupt if HW RF kill is set.
+        * Clean again the interrupt here
+        */
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       iwl_enable_rfkill_int(trans);
+
+       /* wait to make sure we flush pending tasklet*/
+       synchronize_irq(trans_pcie->irq);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+
+       cancel_work_sync(&trans_pcie->rx_replenish);
+
+       /* stop and reset the on-board processor */
+       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+       /* clear all status bits */
+       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+       clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+       clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+       clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+}
+
+static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
+{
+       /* let the ucode operate on its own */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_SET,
+                   CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       iwl_disable_interrupts(trans);
+       iwl_clear_bit(trans, CSR_GP_CNTRL,
+                     CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+
+static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
+                            struct iwl_device_cmd *dev_cmd, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+       struct iwl_cmd_meta *out_meta;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       dma_addr_t phys_addr = 0;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       u16 len, firstlen, secondlen;
+       u8 wait_write_ptr = 0;
+       __le16 fc = hdr->frame_control;
+       u8 hdr_len = ieee80211_hdrlen(fc);
+       u16 __maybe_unused wifi_seq;
+
+       txq = &trans_pcie->txq[txq_id];
+       q = &txq->q;
+
+       if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+
+       spin_lock(&txq->lock);
+
+       /* In AGG mode, the index in the ring must correspond to the WiFi
+        * sequence number. This is a HW requirements to help the SCD to parse
+        * the BA.
+        * Check here that the packets are in the right place on the ring.
+        */
+#ifdef CONFIG_IWLWIFI_DEBUG
+       wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+       WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
+                 ((wifi_seq & 0xff) != q->write_ptr),
+                 "Q: %d WiFi Seq %d tfdNum %d",
+                 txq_id, wifi_seq, q->write_ptr);
+#endif
+
+       /* Set up driver data for this TFD */
+       txq->entries[q->write_ptr].skb = skb;
+       txq->entries[q->write_ptr].cmd = dev_cmd;
+
+       dev_cmd->hdr.cmd = REPLY_TX;
+       dev_cmd->hdr.sequence =
+               cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                           INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_meta = &txq->entries[q->write_ptr].meta;
+
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+       firstlen = (len + 3) & ~3;
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (firstlen != len)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = dma_map_single(trans->dev,
+                                   &dev_cmd->hdr, firstlen,
+                                   DMA_BIDIRECTIONAL);
+       if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
+               goto out_err;
+       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       dma_unmap_len_set(out_meta, len, firstlen);
+
+       if (!ieee80211_has_morefrags(fc)) {
+               txq->need_update = 1;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
+       }
+
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       secondlen = skb->len - hdr_len;
+       if (secondlen > 0) {
+               phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
+                                          secondlen, DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
+                       dma_unmap_single(trans->dev,
+                                        dma_unmap_addr(out_meta, mapping),
+                                        dma_unmap_len(out_meta, len),
+                                        DMA_BIDIRECTIONAL);
+                       goto out_err;
+               }
+       }
+
+       /* Attach buffers to TFD */
+       iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
+       if (secondlen > 0)
+               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+                                            secondlen, 0);
+
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+                               offsetof(struct iwl_tx_cmd, scratch);
+
+       /* take back ownership of DMA buffer to enable update */
+       dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
+                               DMA_BIDIRECTIONAL);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
+                    le16_to_cpu(dev_cmd->hdr.sequence));
+       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+
+       /* Set up entry for this TFD in Tx byte-count array */
+       iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
+
+       dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
+                                  DMA_BIDIRECTIONAL);
+
+       trace_iwlwifi_dev_tx(trans->dev,
+                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &dev_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+
+       /* start timer if queue currently empty */
+       if (txq->need_update && q->read_ptr == q->write_ptr &&
+           trans_pcie->wd_timeout)
+               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_txq_update_write_ptr(trans, txq);
+
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+       if (iwl_queue_space(q) < q->high_mark) {
+               if (wait_write_ptr) {
+                       txq->need_update = 1;
+                       iwl_txq_update_write_ptr(trans, txq);
+               } else {
+                       iwl_stop_queue(trans, txq);
+               }
+       }
+       spin_unlock(&txq->lock);
+       return 0;
+ out_err:
+       spin_unlock(&txq->lock);
+       return -1;
+}
+
+static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int err;
+       bool hw_rfkill;
+
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+       if (!trans_pcie->irq_requested) {
+               tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+                       iwl_irq_tasklet, (unsigned long)trans);
+
+               iwl_alloc_isr_ict(trans);
+
+               err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
+                                 DRV_NAME, trans);
+               if (err) {
+                       IWL_ERR(trans, "Error allocating IRQ %d\n",
+                               trans_pcie->irq);
+                       goto error;
+               }
+
+               INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
+               trans_pcie->irq_requested = true;
+       }
+
+       err = iwl_prepare_card_hw(trans);
+       if (err) {
+               IWL_ERR(trans, "Error while preparing HW: %d", err);
+               goto err_free_irq;
+       }
+
+       iwl_apm_init(trans);
+
+       /* From now on, the op_mode will be kept updated about RF kill state */
+       iwl_enable_rfkill_int(trans);
+
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+       return err;
+
+err_free_irq:
+       free_irq(trans_pcie->irq, trans);
+error:
+       iwl_free_isr_ict(trans);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+       return err;
+}
+
+static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
+                                  bool op_mode_leaving)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       bool hw_rfkill;
+       unsigned long flags;
+
+       iwl_apm_stop(trans);
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       if (!op_mode_leaving) {
+               /*
+                * Even if we stop the HW, we still want the RF kill
+                * interrupt
+                */
+               iwl_enable_rfkill_int(trans);
+
+               /*
+                * Check again since the RF kill state may have changed while
+                * all the interrupts were disabled, in this case we couldn't
+                * receive the RF kill interrupt and update the state in the
+                * op_mode.
+                */
+               hw_rfkill = iwl_is_rfkill_set(trans);
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       }
+}
+
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+                                  struct sk_buff_head *skbs)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       /* n_bd is usually 256 => n_bd - 1 = 0xff */
+       int tfd_num = ssn & (txq->q.n_bd - 1);
+       int freed = 0;
+
+       spin_lock(&txq->lock);
+
+       if (txq->q.read_ptr != tfd_num) {
+               IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
+                                  txq_id, txq->q.read_ptr, tfd_num, ssn);
+               freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+                       iwl_wake_queue(trans, txq);
+       }
+
+       spin_unlock(&txq->lock);
+}
+
+static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
+{
+       writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val)
+{
+       writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
+{
+       return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
+}
+
+static void iwl_trans_pcie_configure(struct iwl_trans *trans,
+                                    const struct iwl_trans_config *trans_cfg)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans_pcie->cmd_queue = trans_cfg->cmd_queue;
+       if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
+               trans_pcie->n_no_reclaim_cmds = 0;
+       else
+               trans_pcie->n_no_reclaim_cmds = trans_cfg->n_no_reclaim_cmds;
+       if (trans_pcie->n_no_reclaim_cmds)
+               memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
+                      trans_pcie->n_no_reclaim_cmds * sizeof(u8));
+
+       trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
+
+       if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
+               trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
+
+       /* at least the command queue must be mapped */
+       WARN_ON(!trans_pcie->n_q_to_fifo);
+
+       memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
+              trans_pcie->n_q_to_fifo * sizeof(u8));
+
+       trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k;
+       if (trans_pcie->rx_buf_size_8k)
+               trans_pcie->rx_page_order = get_order(8 * 1024);
+       else
+               trans_pcie->rx_page_order = get_order(4 * 1024);
+
+       trans_pcie->wd_timeout =
+               msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
+
+       trans_pcie->command_names = trans_cfg->command_names;
+}
+
+void iwl_trans_pcie_free(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_trans_pcie_tx_free(trans);
+#ifndef CONFIG_IWLWIFI_IDI
+       iwl_trans_pcie_rx_free(trans);
+#endif
+       if (trans_pcie->irq_requested == true) {
+               free_irq(trans_pcie->irq, trans);
+               iwl_free_isr_ict(trans);
+       }
+
+       pci_disable_msi(trans_pcie->pci_dev);
+       iounmap(trans_pcie->hw_base);
+       pci_release_regions(trans_pcie->pci_dev);
+       pci_disable_device(trans_pcie->pci_dev);
+       kmem_cache_destroy(trans->dev_cmd_pool);
+
+       kfree(trans);
+}
+
+static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (state)
+               set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+       else
+               clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
+{
+       return 0;
+}
+
+static int iwl_trans_pcie_resume(struct iwl_trans *trans)
+{
+       bool hw_rfkill;
+
+       iwl_enable_rfkill_int(trans);
+
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+
+       if (!hw_rfkill)
+               iwl_enable_interrupts(trans);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#define IWL_FLUSH_WAIT_MS      2000
+
+static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       int cnt;
+       unsigned long now = jiffies;
+       int ret = 0;
+
+       /* waiting for all the tx frames complete might take a while */
+       for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+               if (cnt == trans_pcie->cmd_queue)
+                       continue;
+               txq = &trans_pcie->txq[cnt];
+               q = &txq->q;
+               while (q->read_ptr != q->write_ptr && !time_after(jiffies,
+                      now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+                       msleep(1);
+
+               if (q->read_ptr != q->write_ptr) {
+                       IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static const char *get_fh_string(int cmd)
+{
+#define IWL_CMD(x) case x: return #x
+       switch (cmd) {
+       IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+       IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+       IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+       IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+       IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+       IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+       IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+       IWL_CMD(FH_TSSR_TX_STATUS_REG);
+       IWL_CMD(FH_TSSR_TX_ERROR_REG);
+       default:
+               return "UNKNOWN";
+       }
+#undef IWL_CMD
+}
+
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
+{
+       int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       int pos = 0;
+       size_t bufsz = 0;
+#endif
+       static const u32 fh_tbl[] = {
+               FH_RSCSR_CHNL0_STTS_WPTR_REG,
+               FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+               FH_RSCSR_CHNL0_WPTR,
+               FH_MEM_RCSR_CHNL0_CONFIG_REG,
+               FH_MEM_RSSR_SHARED_CTRL_REG,
+               FH_MEM_RSSR_RX_STATUS_REG,
+               FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+               FH_TSSR_TX_STATUS_REG,
+               FH_TSSR_TX_ERROR_REG
+       };
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+               pos += scnprintf(*buf + pos, bufsz - pos,
+                               "FH register values:\n");
+               for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+                       pos += scnprintf(*buf + pos, bufsz - pos,
+                               "  %34s: 0X%08x\n",
+                               get_fh_string(fh_tbl[i]),
+                               iwl_read_direct32(trans, fh_tbl[i]));
+               }
+               return pos;
+       }
+#endif
+       IWL_ERR(trans, "FH register values:\n");
+       for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
+               IWL_ERR(trans, "  %34s: 0X%08x\n",
+                       get_fh_string(fh_tbl[i]),
+                       iwl_read_direct32(trans, fh_tbl[i]));
+       }
+       return 0;
+}
+
+static const char *get_csr_string(int cmd)
+{
+#define IWL_CMD(x) case x: return #x
+       switch (cmd) {
+       IWL_CMD(CSR_HW_IF_CONFIG_REG);
+       IWL_CMD(CSR_INT_COALESCING);
+       IWL_CMD(CSR_INT);
+       IWL_CMD(CSR_INT_MASK);
+       IWL_CMD(CSR_FH_INT_STATUS);
+       IWL_CMD(CSR_GPIO_IN);
+       IWL_CMD(CSR_RESET);
+       IWL_CMD(CSR_GP_CNTRL);
+       IWL_CMD(CSR_HW_REV);
+       IWL_CMD(CSR_EEPROM_REG);
+       IWL_CMD(CSR_EEPROM_GP);
+       IWL_CMD(CSR_OTP_GP_REG);
+       IWL_CMD(CSR_GIO_REG);
+       IWL_CMD(CSR_GP_UCODE_REG);
+       IWL_CMD(CSR_GP_DRIVER_REG);
+       IWL_CMD(CSR_UCODE_DRV_GP1);
+       IWL_CMD(CSR_UCODE_DRV_GP2);
+       IWL_CMD(CSR_LED_REG);
+       IWL_CMD(CSR_DRAM_INT_TBL_REG);
+       IWL_CMD(CSR_GIO_CHICKEN_BITS);
+       IWL_CMD(CSR_ANA_PLL_CFG);
+       IWL_CMD(CSR_HW_REV_WA_REG);
+       IWL_CMD(CSR_DBG_HPET_MEM_REG);
+       default:
+               return "UNKNOWN";
+       }
+#undef IWL_CMD
+}
+
+void iwl_dump_csr(struct iwl_trans *trans)
+{
+       int i;
+       static const u32 csr_tbl[] = {
+               CSR_HW_IF_CONFIG_REG,
+               CSR_INT_COALESCING,
+               CSR_INT,
+               CSR_INT_MASK,
+               CSR_FH_INT_STATUS,
+               CSR_GPIO_IN,
+               CSR_RESET,
+               CSR_GP_CNTRL,
+               CSR_HW_REV,
+               CSR_EEPROM_REG,
+               CSR_EEPROM_GP,
+               CSR_OTP_GP_REG,
+               CSR_GIO_REG,
+               CSR_GP_UCODE_REG,
+               CSR_GP_DRIVER_REG,
+               CSR_UCODE_DRV_GP1,
+               CSR_UCODE_DRV_GP2,
+               CSR_LED_REG,
+               CSR_DRAM_INT_TBL_REG,
+               CSR_GIO_CHICKEN_BITS,
+               CSR_ANA_PLL_CFG,
+               CSR_HW_REV_WA_REG,
+               CSR_DBG_HPET_MEM_REG
+       };
+       IWL_ERR(trans, "CSR values:\n");
+       IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
+               "CSR_INT_PERIODIC_REG)\n");
+       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
+               IWL_ERR(trans, "  %25s: 0X%08x\n",
+                       get_csr_string(csr_tbl[i]),
+                       iwl_read32(trans, csr_tbl[i]));
+       }
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
+       if (!debugfs_create_file(#name, mode, parent, trans,            \
+                                &iwl_dbgfs_##name##_ops))              \
+               return -ENOMEM;                                         \
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name)                                         \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
+                                       char __user *user_buf,          \
+                                       size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                        \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
+                                       const char __user *user_buf,    \
+                                       size_t count, loff_t *ppos);
+
+
+#define DEBUGFS_READ_FILE_OPS(name)                                    \
+       DEBUGFS_READ_FUNC(name);                                        \
+static const struct file_operations iwl_dbgfs_##name##_ops = {         \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)                              \
+       DEBUGFS_READ_FUNC(name);                                        \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {         \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       char *buf;
+       int pos = 0;
+       int cnt;
+       int ret;
+       size_t bufsz;
+
+       bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues;
+
+       if (!trans_pcie->txq)
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
+               txq = &trans_pcie->txq[cnt];
+               q = &txq->q;
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "hwq %.2d: read=%u write=%u use=%d stop=%d\n",
+                               cnt, q->read_ptr, q->write_ptr,
+                               !!test_bit(cnt, trans_pcie->queue_used),
+                               !!test_bit(cnt, trans_pcie->queue_stopped));
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       char buf[256];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
+                                               rxq->read);
+       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
+                                               rxq->write);
+       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
+                                               rxq->free_count);
+       if (rxq->rb_stts) {
+               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
+       } else {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                       "closed_rb_num: Not Allocated\n");
+       }
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+       int pos = 0;
+       char *buf;
+       int bufsz = 24 * 64; /* 24 items * 64 char per item */
+       ssize_t ret;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "Interrupt Statistics Report:\n");
+
+       pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
+               isr_stats->hw);
+       pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
+               isr_stats->sw);
+       if (isr_stats->sw || isr_stats->hw) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tLast Restarting Code:  0x%X\n",
+                       isr_stats->err_code);
+       }
+#ifdef CONFIG_IWLWIFI_DEBUG
+       pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
+               isr_stats->sch);
+       pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
+               isr_stats->alive);
+#endif
+       pos += scnprintf(buf + pos, bufsz - pos,
+               "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
+               isr_stats->ctkill);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
+               isr_stats->wakeup);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+               "Rx command responses:\t\t %u\n", isr_stats->rx);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
+               isr_stats->tx);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
+               isr_stats->unhandled);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+       char buf[8];
+       int buf_size;
+       u32 reset_flag;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%x", &reset_flag) != 1)
+               return -EFAULT;
+       if (reset_flag == 0)
+               memset(isr_stats, 0, sizeof(*isr_stats));
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+                                  const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       char buf[8];
+       int buf_size;
+       int csr;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &csr) != 1)
+               return -EFAULT;
+
+       iwl_dump_csr(trans);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -EFAULT;
+
+       ret = pos = iwl_dump_fh(trans, &buf, true);
+       if (buf) {
+               ret = simple_read_from_buffer(user_buf,
+                                             count, ppos, buf, pos);
+               kfree(buf);
+       }
+
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+                                         const char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+
+       if (!trans->op_mode)
+               return -EAGAIN;
+
+       local_bh_disable();
+       iwl_op_mode_nic_error(trans->op_mode);
+       local_bh_enable();
+
+       return count;
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_FILE_OPS(rx_queue);
+DEBUGFS_READ_FILE_OPS(tx_queue);
+DEBUGFS_WRITE_FILE_OPS(csr);
+DEBUGFS_WRITE_FILE_OPS(fw_restart);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                        struct dentry *dir)
+{
+       DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
+       DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
+       return 0;
+}
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                        struct dentry *dir)
+{
+       return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
+
+static const struct iwl_trans_ops trans_ops_pcie = {
+       .start_hw = iwl_trans_pcie_start_hw,
+       .stop_hw = iwl_trans_pcie_stop_hw,
+       .fw_alive = iwl_trans_pcie_fw_alive,
+       .start_fw = iwl_trans_pcie_start_fw,
+       .stop_device = iwl_trans_pcie_stop_device,
+
+       .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
+
+       .send_cmd = iwl_trans_pcie_send_cmd,
+
+       .tx = iwl_trans_pcie_tx,
+       .reclaim = iwl_trans_pcie_reclaim,
+
+       .txq_disable = iwl_trans_pcie_txq_disable,
+       .txq_enable = iwl_trans_pcie_txq_enable,
+
+       .dbgfs_register = iwl_trans_pcie_dbgfs_register,
+
+       .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
+
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwl_trans_pcie_suspend,
+       .resume = iwl_trans_pcie_resume,
+#endif
+       .write8 = iwl_trans_pcie_write8,
+       .write32 = iwl_trans_pcie_write32,
+       .read32 = iwl_trans_pcie_read32,
+       .configure = iwl_trans_pcie_configure,
+       .set_pmi = iwl_trans_pcie_set_pmi,
+};
+
+struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
+                                      const struct pci_device_id *ent,
+                                      const struct iwl_cfg *cfg)
+{
+       struct iwl_trans_pcie *trans_pcie;
+       struct iwl_trans *trans;
+       char cmd_pool_name[100];
+       u16 pci_cmd;
+       int err;
+
+       trans = kzalloc(sizeof(struct iwl_trans) +
+                       sizeof(struct iwl_trans_pcie), GFP_KERNEL);
+
+       if (WARN_ON(!trans))
+               return NULL;
+
+       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans->ops = &trans_ops_pcie;
+       trans->cfg = cfg;
+       trans_pcie->trans = trans;
+       spin_lock_init(&trans_pcie->irq_lock);
+       init_waitqueue_head(&trans_pcie->ucode_write_waitq);
+
+       /* W/A - seems to solve weird behavior. We need to remove this if we
+        * don't want to stay in L1 all the time. This wastes a lot of power */
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                              PCIE_LINK_STATE_CLKPM);
+
+       if (pci_enable_device(pdev)) {
+               err = -ENODEV;
+               goto out_no_pci;
+       }
+
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (!err)
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (err) {
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (!err)
+                       err = pci_set_consistent_dma_mask(pdev,
+                                                         DMA_BIT_MASK(32));
+               /* both attempts failed: */
+               if (err) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "No suitable DMA available.\n");
+                       goto out_pci_disable_device;
+               }
+       }
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err) {
+               dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed");
+               goto out_pci_disable_device;
+       }
+
+       trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
+       if (!trans_pcie->hw_base) {
+               dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed");
+               err = -ENODEV;
+               goto out_pci_release_regions;
+       }
+
+       dev_printk(KERN_INFO, &pdev->dev,
+                  "pci_resource_len = 0x%08llx\n",
+                  (unsigned long long) pci_resource_len(pdev, 0));
+       dev_printk(KERN_INFO, &pdev->dev,
+                  "pci_resource_base = %p\n", trans_pcie->hw_base);
+
+       dev_printk(KERN_INFO, &pdev->dev,
+                  "HW Revision ID = 0x%X\n", pdev->revision);
+
+       /* We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state */
+       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
+       err = pci_enable_msi(pdev);
+       if (err)
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "pci_enable_msi failed(0X%x)", err);
+
+       trans->dev = &pdev->dev;
+       trans_pcie->irq = pdev->irq;
+       trans_pcie->pci_dev = pdev;
+       trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
+       trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
+       snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
+                "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
+
+       /* TODO: Move this away, not needed if not MSI */
+       /* enable rfkill interrupt: hw bug w/a */
+       pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+       if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+               pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+               pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+       }
+
+       /* Initialize the wait queue for commands */
+       init_waitqueue_head(&trans->wait_command_queue);
+       spin_lock_init(&trans->reg_lock);
+
+       snprintf(cmd_pool_name, sizeof(cmd_pool_name), "iwl_cmd_pool:%s",
+                dev_name(trans->dev));
+
+       trans->dev_cmd_headroom = 0;
+       trans->dev_cmd_pool =
+               kmem_cache_create(cmd_pool_name,
+                                 sizeof(struct iwl_device_cmd)
+                                 + trans->dev_cmd_headroom,
+                                 sizeof(void *),
+                                 SLAB_HWCACHE_ALIGN,
+                                 NULL);
+
+       if (!trans->dev_cmd_pool)
+               goto out_pci_disable_msi;
+
+       return trans;
+
+out_pci_disable_msi:
+       pci_disable_msi(pdev);
+out_pci_release_regions:
+       pci_release_regions(pdev);
+out_pci_disable_device:
+       pci_disable_device(pdev);
+out_no_pci:
+       kfree(trans);
+       return NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
new file mode 100644 (file)
index 0000000..6baf8de
--- /dev/null
@@ -0,0 +1,969 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * 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/etherdevice.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "iwl-debug.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "iwl-op-mode.h"
+#include "internal.h"
+/* FIXME: need to abstract out TX command (once we know what it looks like) */
+#include "dvm/commands.h"
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
+
+/**
+ * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+                                      struct iwl_tx_queue *txq,
+                                      u16 byte_cnt)
+{
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int write_ptr = txq->q.write_ptr;
+       int txq_id = txq->q.id;
+       u8 sec_ctl = 0;
+       u8 sta_id = 0;
+       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+       __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (void *) txq->entries[txq->q.write_ptr].cmd->payload;
+
+       scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
+
+       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       sta_id = tx_cmd->sta_id;
+       sec_ctl = tx_cmd->sec_ctl;
+
+       switch (sec_ctl & TX_CMD_SEC_MSK) {
+       case TX_CMD_SEC_CCM:
+               len += CCMP_MIC_LEN;
+               break;
+       case TX_CMD_SEC_TKIP:
+               len += TKIP_ICV_LEN;
+               break;
+       case TX_CMD_SEC_WEP:
+               len += WEP_IV_LEN + WEP_ICV_LEN;
+               break;
+       }
+
+       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+
+       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
+
+       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
+}
+
+/**
+ * iwl_txq_update_write_ptr - Send new write index to hardware
+ */
+void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
+{
+       u32 reg = 0;
+       int txq_id = txq->q.id;
+
+       if (txq->need_update == 0)
+               return;
+
+       if (trans->cfg->base_params->shadow_reg_enable) {
+               /* shadow register enabled */
+               iwl_write32(trans, HBUS_TARG_WRPTR,
+                           txq->q.write_ptr | (txq_id << 8));
+       } else {
+               struct iwl_trans_pcie *trans_pcie =
+                       IWL_TRANS_GET_PCIE_TRANS(trans);
+               /* if we're trying to save power */
+               if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+                       /* wake up nic if it's powered down ...
+                        * uCode will wake up, and interrupt us again, so next
+                        * time we'll skip this part. */
+                       reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);
+
+                       if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                               IWL_DEBUG_INFO(trans,
+                                       "Tx queue %d requesting wakeup,"
+                                       " GP1 = 0x%x\n", txq_id, reg);
+                               iwl_set_bit(trans, CSR_GP_CNTRL,
+                                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                               return;
+                       }
+
+                       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+                                    txq->q.write_ptr | (txq_id << 8));
+
+               /*
+                * else not in power-save mode,
+                * uCode will never sleep when we're
+                * trying to tx (during RFKILL, we're not trying to tx).
+                */
+               } else
+                       iwl_write32(trans, HBUS_TARG_WRPTR,
+                                   txq->q.write_ptr | (txq_id << 8));
+       }
+       txq->need_update = 0;
+}
+
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       dma_addr_t addr = get_unaligned_le32(&tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               addr |=
+               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+       return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+                                 dma_addr_t addr, u16 len)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+       u16 hi_n_len = len << 4;
+
+       put_unaligned_le32(addr, &tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+       tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+       tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+       return tfd->num_tbs & 0x1f;
+}
+
+static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
+                         struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
+{
+       int i;
+       int num_tbs;
+
+       /* Sanity check on number of chunks */
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
+               /* @todo issue fatal error, it is quite serious situation */
+               return;
+       }
+
+       /* Unmap tx_cmd */
+       if (num_tbs)
+               dma_unmap_single(trans->dev,
+                               dma_unmap_addr(meta, mapping),
+                               dma_unmap_len(meta, len),
+                               DMA_BIDIRECTIONAL);
+
+       /* Unmap chunks, if any. */
+       for (i = 1; i < num_tbs; i++)
+               dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i),
+                               iwl_tfd_tb_get_len(tfd, i), dma_dir);
+
+       tfd->num_tbs = 0;
+}
+
+/**
+ * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @trans - transport private data
+ * @txq - tx queue
+ * @dma_dir - the direction of the DMA mapping
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+                     enum dma_data_direction dma_dir)
+{
+       struct iwl_tfd *tfd_tmp = txq->tfds;
+
+       /* rd_ptr is bounded by n_bd and idx is bounded by n_window */
+       int rd_ptr = txq->q.read_ptr;
+       int idx = get_cmd_index(&txq->q, rd_ptr);
+
+       lockdep_assert_held(&txq->lock);
+
+       /* We have only q->n_window txq->entries, but we use q->n_bd tfds */
+       iwl_unmap_tfd(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
+                     dma_dir);
+
+       /* free SKB */
+       if (txq->entries) {
+               struct sk_buff *skb;
+
+               skb = txq->entries[idx].skb;
+
+               /* Can be called from irqs-disabled context
+                * If skb is not NULL, it means that the whole queue is being
+                * freed and that the queue is not empty - free the skb
+                */
+               if (skb) {
+                       iwl_op_mode_free_skb(trans->op_mode, skb);
+                       txq->entries[idx].skb = NULL;
+               }
+       }
+}
+
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
+                                struct iwl_tx_queue *txq,
+                                dma_addr_t addr, u16 len,
+                                u8 reset)
+{
+       struct iwl_queue *q;
+       struct iwl_tfd *tfd, *tfd_tmp;
+       u32 num_tbs;
+
+       q = &txq->q;
+       tfd_tmp = txq->tfds;
+       tfd = &tfd_tmp[q->write_ptr];
+
+       if (reset)
+               memset(tfd, 0, sizeof(*tfd));
+
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       /* Each TFD can point to a maximum 20 Tx buffers */
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(trans, "Error can not send more than %d chunks\n",
+                       IWL_NUM_OF_TBS);
+               return -EINVAL;
+       }
+
+       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+               return -EINVAL;
+
+       if (unlikely(addr & ~IWL_TX_DMA_MASK))
+               IWL_ERR(trans, "Unaligned address = %llx\n",
+                       (unsigned long long)addr);
+
+       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+
+       return 0;
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ ***************************************************/
+
+int iwl_queue_space(const struct iwl_queue *q)
+{
+       int s = q->read_ptr - q->write_ptr;
+
+       if (q->read_ptr > q->write_ptr)
+               s -= q->n_bd;
+
+       if (s <= 0)
+               s += q->n_window;
+       /* keep some reserve to not confuse empty and full situations */
+       s -= 2;
+       if (s < 0)
+               s = 0;
+       return s;
+}
+
+/**
+ * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
+{
+       q->n_bd = count;
+       q->n_window = slots_num;
+       q->id = id;
+
+       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+        * and iwl_queue_dec_wrap are broken. */
+       if (WARN_ON(!is_power_of_2(count)))
+               return -EINVAL;
+
+       /* slots_num must be power-of-two size, otherwise
+        * get_cmd_index is broken. */
+       if (WARN_ON(!is_power_of_2(slots_num)))
+               return -EINVAL;
+
+       q->low_mark = q->n_window / 4;
+       if (q->low_mark < 4)
+               q->low_mark = 4;
+
+       q->high_mark = q->n_window / 8;
+       if (q->high_mark < 2)
+               q->high_mark = 2;
+
+       q->write_ptr = q->read_ptr = 0;
+
+       return 0;
+}
+
+static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
+                                         struct iwl_tx_queue *txq)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
+       int txq_id = txq->q.id;
+       int read_ptr = txq->q.read_ptr;
+       u8 sta_id = 0;
+       __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (void *)txq->entries[txq->q.read_ptr].cmd->payload;
+
+       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       if (txq_id != trans_pcie->cmd_queue)
+               sta_id = tx_cmd->sta_id;
+
+       bc_ent = cpu_to_le16(1 | (sta_id << 12));
+       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+}
+
+static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
+                                u16 txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 tbl_dw_addr;
+       u32 tbl_dw;
+       u16 scd_q2ratid;
+
+       scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+       tbl_dw_addr = trans_pcie->scd_base_addr +
+                       SCD_TRANS_TBL_OFFSET_QUEUE(txq_id);
+
+       tbl_dw = iwl_read_targ_mem(trans, tbl_dw_addr);
+
+       if (txq_id & 0x1)
+               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+       else
+               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+       iwl_write_targ_mem(trans, tbl_dw_addr, tbl_dw);
+
+       return 0;
+}
+
+static inline void iwl_txq_set_inactive(struct iwl_trans *trans, u16 txq_id)
+{
+       /* Simply stop the queue, but don't change any configuration;
+        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+       iwl_write_prph(trans,
+               SCD_QUEUE_STATUS_BITS(txq_id),
+               (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+               (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
+                              int sta_id, int tid, int frame_limit, u16 ssn)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (test_and_set_bit(txq_id, trans_pcie->queue_used))
+               WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
+
+       /* Stop this Tx queue before configuring it */
+       iwl_txq_set_inactive(trans, txq_id);
+
+       /* Set this queue as a chain-building queue unless it is CMD queue */
+       if (txq_id != trans_pcie->cmd_queue)
+               iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+
+       /* If this queue is mapped to a certain station: it is an AGG queue */
+       if (sta_id != IWL_INVALID_STATION) {
+               u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+
+               /* Map receiver-address / traffic-ID to this queue */
+               iwl_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+               /* enable aggregations for the queue */
+               iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+       } else {
+               /*
+                * disable aggregations for the queue, this will also make the
+                * ra_tid mapping configuration irrelevant since it is now a
+                * non-AGG queue.
+                */
+               iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+       }
+
+       /* Place first TFD at index corresponding to start sequence number.
+        * Assumes that ssn_idx is valid (!= 0xFFF) */
+       trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
+       trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
+
+       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+                          (ssn & 0xff) | (txq_id << 8));
+       iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+
+       /* Set up Tx window size and frame limit for this queue */
+       iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+                       SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+       iwl_write_targ_mem(trans, trans_pcie->scd_base_addr +
+                       SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+                       ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                       ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
+       iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+                      (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                      (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+                      (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+                      SCD_QUEUE_STTS_REG_MSK);
+       IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
+                           txq_id, fifo, ssn & 0xff);
+}
+
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u16 rd_ptr, wr_ptr;
+       int n_bd = trans_pcie->txq[txq_id].q.n_bd;
+
+       if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
+               WARN_ONCE(1, "queue %d not used", txq_id);
+               return;
+       }
+
+       rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1);
+       wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id));
+
+       WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]",
+                 txq_id, rd_ptr, wr_ptr);
+
+       iwl_txq_set_inactive(trans, txq_id);
+       IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       struct iwl_queue *q = &txq->q;
+       struct iwl_device_cmd *out_cmd;
+       struct iwl_cmd_meta *out_meta;
+       dma_addr_t phys_addr;
+       u32 idx;
+       u16 copy_size, cmd_size;
+       bool had_nocopy = false;
+       int i;
+       u8 *cmd_dest;
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_idx;
+#endif
+
+       copy_size = sizeof(out_cmd->hdr);
+       cmd_size = sizeof(out_cmd->hdr);
+
+       /* need one for the header if the first is NOCOPY */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
+                       had_nocopy = true;
+               } else {
+                       /* NOCOPY must not be followed by normal! */
+                       if (WARN_ON(had_nocopy))
+                               return -EINVAL;
+                       copy_size += cmd->len[i];
+               }
+               cmd_size += cmd->len[i];
+       }
+
+       /*
+        * If any of the command structures end up being larger than
+        * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
+        * allocated into separate TFDs, then we will need to
+        * increase the size of the buffers.
+        */
+       if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
+               return -EINVAL;
+
+       spin_lock_bh(&txq->lock);
+
+       if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
+               spin_unlock_bh(&txq->lock);
+
+               IWL_ERR(trans, "No space in command queue\n");
+               iwl_op_mode_cmd_queue_full(trans->op_mode);
+               return -ENOSPC;
+       }
+
+       idx = get_cmd_index(q, q->write_ptr);
+       out_cmd = txq->entries[idx].cmd;
+       out_meta = &txq->entries[idx].meta;
+
+       memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
+       if (cmd->flags & CMD_WANT_SKB)
+               out_meta->source = cmd;
+
+       /* set up the header */
+
+       out_cmd->hdr.cmd = cmd->id;
+       out_cmd->hdr.flags = 0;
+       out_cmd->hdr.sequence =
+               cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) |
+                                        INDEX_TO_SEQ(q->write_ptr));
+
+       /* and copy the data that needs to be copied */
+
+       cmd_dest = out_cmd->payload;
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+                       break;
+               memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
+               cmd_dest += cmd->len[i];
+       }
+
+       IWL_DEBUG_HC(trans,
+                    "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
+                    trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
+                    out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+                    cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
+
+       phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
+                                  DMA_BIDIRECTIONAL);
+       if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
+               idx = -ENOMEM;
+               goto out;
+       }
+
+       dma_unmap_addr_set(out_meta, mapping, phys_addr);
+       dma_unmap_len_set(out_meta, len, copy_size);
+
+       iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_bufs[0] = &out_cmd->hdr;
+       trace_lens[0] = copy_size;
+       trace_idx = 1;
+#endif
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+                       continue;
+               phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i],
+                                          cmd->len[i], DMA_BIDIRECTIONAL);
+               if (dma_mapping_error(trans->dev, phys_addr)) {
+                       iwl_unmap_tfd(trans, out_meta,
+                                     &txq->tfds[q->write_ptr],
+                                     DMA_BIDIRECTIONAL);
+                       idx = -ENOMEM;
+                       goto out;
+               }
+
+               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+                                            cmd->len[i], 0);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+               trace_bufs[trace_idx] = cmd->data[i];
+               trace_lens[trace_idx] = cmd->len[i];
+               trace_idx++;
+#endif
+       }
+
+       out_meta->flags = cmd->flags;
+
+       txq->need_update = 1;
+
+       /* check that tracing gets all possible blocks */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_iwlwifi_dev_hcmd(trans->dev, cmd->flags,
+                              trace_bufs[0], trace_lens[0],
+                              trace_bufs[1], trace_lens[1],
+                              trace_bufs[2], trace_lens[2]);
+#endif
+
+       /* start timer if queue currently empty */
+       if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
+               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+
+       /* Increment and update queue's write index */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_txq_update_write_ptr(trans, txq);
+
+ out:
+       spin_unlock_bh(&txq->lock);
+       return idx;
+}
+
+static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
+                                     struct iwl_tx_queue *txq)
+{
+       if (!trans_pcie->wd_timeout)
+               return;
+
+       /*
+        * if empty delete timer, otherwise move timer forward
+        * since we're making progress on this queue
+        */
+       if (txq->q.read_ptr == txq->q.write_ptr)
+               del_timer(&txq->stuck_timer);
+       else
+               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+}
+
+/**
+ * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
+                                  int idx)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       int nfreed = 0;
+
+       lockdep_assert_held(&txq->lock);
+
+       if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
+               IWL_ERR(trans,
+                       "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n",
+                       __func__, txq_id, idx, q->n_bd,
+                       q->write_ptr, q->read_ptr);
+               return;
+       }
+
+       for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               if (nfreed++ > 0) {
+                       IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
+                               idx, q->write_ptr, q->read_ptr);
+                       iwl_op_mode_nic_error(trans->op_mode);
+               }
+
+       }
+
+       iwl_queue_progress(trans_pcie, txq);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ * @handler_status: return value of the handler of the command
+ *     (put in setup_rx_handlers)
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
+                        int handler_status)
+{
+       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);
+       int cmd_index;
+       struct iwl_device_cmd *cmd;
+       struct iwl_cmd_meta *meta;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+
+       /* If a Tx command is being handled and it isn't in the actual
+        * command queue then there a command routing bug has been introduced
+        * in the queue management code. */
+       if (WARN(txq_id != trans_pcie->cmd_queue,
+                "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
+                txq_id, trans_pcie->cmd_queue, sequence,
+                trans_pcie->txq[trans_pcie->cmd_queue].q.read_ptr,
+                trans_pcie->txq[trans_pcie->cmd_queue].q.write_ptr)) {
+               iwl_print_hex_error(trans, pkt, 32);
+               return;
+       }
+
+       spin_lock(&txq->lock);
+
+       cmd_index = get_cmd_index(&txq->q, index);
+       cmd = txq->entries[cmd_index].cmd;
+       meta = &txq->entries[cmd_index].meta;
+
+       iwl_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
+
+       /* Input error checking is done when commands are added to queue. */
+       if (meta->flags & CMD_WANT_SKB) {
+               struct page *p = rxb_steal_page(rxb);
+
+               meta->source->resp_pkt = pkt;
+               meta->source->_rx_page_addr = (unsigned long)page_address(p);
+               meta->source->_rx_page_order = trans_pcie->rx_page_order;
+               meta->source->handler_status = handler_status;
+       }
+
+       iwl_hcmd_queue_reclaim(trans, txq_id, index);
+
+       if (!(meta->flags & CMD_ASYNC)) {
+               if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+                       IWL_WARN(trans,
+                                "HCMD_ACTIVE already clear for command %s\n",
+                                trans_pcie_get_cmd_string(trans_pcie,
+                                                          cmd->hdr.cmd));
+               }
+               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
+                              trans_pcie_get_cmd_string(trans_pcie,
+                                                        cmd->hdr.cmd));
+               wake_up(&trans->wait_command_queue);
+       }
+
+       meta->flags = 0;
+
+       spin_unlock(&txq->lock);
+}
+
+#define HOST_COMPLETE_TIMEOUT (2 * HZ)
+
+static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+
+       /* An asynchronous command can not expect an SKB to be set. */
+       if (WARN_ON(cmd->flags & CMD_WANT_SKB))
+               return -EINVAL;
+
+
+       ret = iwl_enqueue_hcmd(trans, cmd);
+       if (ret < 0) {
+               IWL_ERR(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
+                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int cmd_idx;
+       int ret;
+
+       IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
+                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+
+       if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
+                                    &trans_pcie->status))) {
+               IWL_ERR(trans, "Command %s: a command is already active!\n",
+                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+               return -EIO;
+       }
+
+       IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
+                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+
+       cmd_idx = iwl_enqueue_hcmd(trans, cmd);
+       if (cmd_idx < 0) {
+               ret = cmd_idx;
+               clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+               IWL_ERR(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
+                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+               return ret;
+       }
+
+       ret = wait_event_timeout(trans->wait_command_queue,
+                                !test_bit(STATUS_HCMD_ACTIVE,
+                                          &trans_pcie->status),
+                                HOST_COMPLETE_TIMEOUT);
+       if (!ret) {
+               if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+                       struct iwl_tx_queue *txq =
+                               &trans_pcie->txq[trans_pcie->cmd_queue];
+                       struct iwl_queue *q = &txq->q;
+
+                       IWL_ERR(trans,
+                               "Error sending %s: time out after %dms.\n",
+                               trans_pcie_get_cmd_string(trans_pcie, cmd->id),
+                               jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+                       IWL_ERR(trans,
+                               "Current CMD queue read_ptr %d write_ptr %d\n",
+                               q->read_ptr, q->write_ptr);
+
+                       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+                       IWL_DEBUG_INFO(trans,
+                                      "Clearing HCMD_ACTIVE for command %s\n",
+                                      trans_pcie_get_cmd_string(trans_pcie,
+                                                                cmd->id));
+                       ret = -ETIMEDOUT;
+                       goto cancel;
+               }
+       }
+
+       if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
+               IWL_ERR(trans, "Error: Response NULL in '%s'\n",
+                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+               ret = -EIO;
+               goto cancel;
+       }
+
+       return 0;
+
+cancel:
+       if (cmd->flags & CMD_WANT_SKB) {
+               /*
+                * Cancel the CMD_WANT_SKB flag for the cmd in the
+                * TX cmd queue. Otherwise in case the cmd comes
+                * in later, it will possibly set an invalid
+                * address (cmd->meta.source).
+                */
+               trans_pcie->txq[trans_pcie->cmd_queue].
+                       entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB;
+       }
+
+       if (cmd->resp_pkt) {
+               iwl_free_resp(cmd);
+               cmd->resp_pkt = NULL;
+       }
+
+       return ret;
+}
+
+int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+       if (cmd->flags & CMD_ASYNC)
+               return iwl_send_cmd_async(trans, cmd);
+
+       return iwl_send_cmd_sync(trans, cmd);
+}
+
+/* Frees buffers until index _not_ inclusive */
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+                        struct sk_buff_head *skbs)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       int last_to_free;
+       int freed = 0;
+
+       /* This function is not meant to release cmd queue*/
+       if (WARN_ON(txq_id == trans_pcie->cmd_queue))
+               return 0;
+
+       lockdep_assert_held(&txq->lock);
+
+       /*Since we free until index _not_ inclusive, the one before index is
+        * the last we will free. This one must be used */
+       last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
+
+       if ((index >= q->n_bd) ||
+          (iwl_queue_used(q, last_to_free) == 0)) {
+               IWL_ERR(trans,
+                       "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
+                       __func__, txq_id, last_to_free, q->n_bd,
+                       q->write_ptr, q->read_ptr);
+               return 0;
+       }
+
+       if (WARN_ON(!skb_queue_empty(skbs)))
+               return 0;
+
+       for (;
+            q->read_ptr != index;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
+                       continue;
+
+               __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
+
+               txq->entries[txq->q.read_ptr].skb = NULL;
+
+               iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
+
+               iwl_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
+               freed++;
+       }
+
+       iwl_queue_progress(trans_pcie, txq);
+
+       return freed;
+}
index 2fa879b015b6817d24e558395c0f74ef638cbc96..f4a203049fb470d59d5beb2064208ab82d5734e4 100644 (file)
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
  * Set Channel
  */
 
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
-       struct net_device *netdev,
-       struct ieee80211_channel *channel,
-       enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+                                      struct ieee80211_channel *channel,
+                                      enum nl80211_channel_type channel_type)
 {
        struct lbs_private *priv = wiphy_priv(wiphy);
        int ret = -ENOTSUPP;
 
-       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
-                          netdev_name(netdev), channel->center_freq, channel_type);
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+                          channel->center_freq, channel_type);
 
        if (channel_type != NL80211_CHAN_NO_HT)
                goto out;
 
-       if (netdev == priv->mesh_dev)
-               ret = lbs_mesh_set_channel(priv, channel->hw_value);
-       else
-               ret = lbs_set_channel(priv, channel->hw_value);
+       ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+       lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+       return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+                                   struct net_device *netdev,
+                                   struct ieee80211_channel *channel)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+       int ret = -ENOTSUPP;
+
+       lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+                          netdev_name(netdev), channel->center_freq);
+
+       if (netdev != priv->mesh_dev)
+               goto out;
+
+       ret = lbs_mesh_set_channel(priv, channel->hw_value);
 
  out:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
  */
 
 static struct cfg80211_ops lbs_cfg80211_ops = {
-       .set_channel = lbs_cfg_set_channel,
+       .set_monitor_channel = lbs_cfg_set_monitor_channel,
+       .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
        .scan = lbs_cfg_scan,
        .connect = lbs_cfg_connect,
        .disconnect = lbs_cfg_disconnect,
index 672005430acab75e0b650bda1a490245e79d2167..60996ce89f778932e0fa7270e6154e1ad86c03d0 100644 (file)
@@ -58,6 +58,7 @@ struct lbs_private {
        uint16_t mesh_tlv;
        u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
        u8 mesh_ssid_len;
+       u8 mesh_channel;
 #endif
 
        /* Debugfs */
index e87c031b298fcd2c2a75f72a245944e752648763..97807751ebcfd59204fe6d651ce6874e52d552be 100644 (file)
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
 
 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
 {
+       priv->mesh_channel = channel;
        return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
 }
 
 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
 {
-       struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
-       if (mesh_wdev->channel)
-               return mesh_wdev->channel->hw_value;
-       else
-               return 1;
+       return priv->mesh_channel ?: 1;
 }
 
 /***************************************************************************
index a0b7cfd3468532e705eeedaf4cf93cdb1e5be536..5bddf53ece1d2d667708e98b7aee2e10b5939329 100644 (file)
@@ -678,8 +678,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                        continue;
 
                if (data2->idle || !data2->started ||
-                   !hwsim_ps_rx_ok(data2, skb) ||
-                   !data->channel || !data2->channel ||
+                   !hwsim_ps_rx_ok(data2, skb) || !data2->channel ||
                    data->channel->center_freq != data2->channel->center_freq ||
                    !(data->group & data2->group))
                        continue;
@@ -1486,7 +1485,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
        struct mac80211_hwsim_data *data2;
        struct ieee80211_tx_info *txi;
        struct hwsim_tx_rate *tx_attempts;
-       struct sk_buff __user *ret_skb;
+       unsigned long ret_skb_ptr;
        struct sk_buff *skb, *tmp;
        struct mac_address *src;
        unsigned int hwsim_flags;
@@ -1504,8 +1503,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
                                   info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
        hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
 
-       ret_skb = (struct sk_buff __user *)
-                 (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
+       ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
 
        data2 = get_hwsim_data_ref_from_addr(src);
 
@@ -1514,7 +1512,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 
        /* look for the skb matching the cookie passed back from user */
        skb_queue_walk_safe(&data2->pending, skb, tmp) {
-               if (skb == ret_skb) {
+               if ((unsigned long)skb == ret_skb_ptr) {
                        skb_unlink(skb, &data2->pending);
                        found = true;
                        break;
index 5c7fd185373cfb37c0ee57e62b9b54135af505b7..75843fddbad409c560bb4719f523f7dfc8025c0c 100644 (file)
@@ -170,7 +170,9 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
        if (!priv->sec_info.wep_enabled)
                return 0;
 
-       if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
+       if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
+               priv->wep_key_curr_index = key_index;
+       } else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
                wiphy_err(wiphy, "set default Tx key index\n");
                return -EFAULT;
        }
@@ -187,9 +189,25 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
                         struct key_params *params)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
+       struct mwifiex_wep_key *wep_key;
        const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
 
+       if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
+           (params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+               if (params->key && params->key_len) {
+                       wep_key = &priv->wep_key[key_index];
+                       memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
+                       memcpy(wep_key->key_material, params->key,
+                              params->key_len);
+                       wep_key->key_index = key_index;
+                       wep_key->key_length = params->key_len;
+                       priv->sec_info.wep_enabled = 1;
+               }
+               return 0;
+       }
+
        if (mwifiex_set_encode(priv, params->key, params->key_len,
                               key_index, peer_mac, 0)) {
                wiphy_err(wiphy, "crypto keys added\n");
@@ -242,13 +260,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
                        flag = 1;
                        first_chan = (u32) ch->hw_value;
                        next_chan = first_chan;
-                       max_pwr = ch->max_power;
+                       max_pwr = ch->max_reg_power;
                        no_of_parsed_chan = 1;
                        continue;
                }
 
                if (ch->hw_value == next_chan + 1 &&
-                   ch->max_power == max_pwr) {
+                   ch->max_reg_power == max_pwr) {
                        next_chan++;
                        no_of_parsed_chan++;
                } else {
@@ -259,7 +277,7 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
                        no_of_triplet++;
                        first_chan = (u32) ch->hw_value;
                        next_chan = first_chan;
-                       max_pwr = ch->max_power;
+                       max_pwr = ch->max_reg_power;
                        no_of_parsed_chan = 1;
                }
        }
@@ -384,13 +402,13 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv,
        cfp.freq = chan->center_freq;
        cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
 
-       if (mwifiex_bss_set_channel(priv, &cfp))
-               return -EFAULT;
-
-       if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+       if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
+               if (mwifiex_bss_set_channel(priv, &cfp))
+                       return -EFAULT;
                return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
-       else
-               return mwifiex_uap_set_channel(priv, cfp.channel);
+       }
+
+       return 0;
 }
 
 /*
@@ -962,12 +980,25 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       bss_cfg->channel =
+           (u8)ieee80211_frequency_to_channel(params->channel->center_freq);
+       bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
+
+       if (mwifiex_set_rf_channel(priv, params->channel,
+                                  params->channel_type)) {
+               kfree(bss_cfg);
+               wiphy_err(wiphy, "Failed to set band config information!\n");
+               return -1;
+       }
+
        if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
                kfree(bss_cfg);
                wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
                return -1;
        }
 
+       mwifiex_set_ht_params(priv, bss_cfg, params);
+
        if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
                wiphy_err(wiphy, "Failed to stop the BSS\n");
@@ -991,6 +1022,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
                return -1;
        }
 
+       if (priv->sec_info.wep_enabled)
+               priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+       else
+               priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+       if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
+                                 HostCmd_ACT_GEN_SET, 0,
+                                 &priv->curr_pkt_filter))
+               return -1;
+
        return 0;
 }
 
@@ -1382,7 +1423,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
 
                priv->user_scan_cfg->chan_list[i].scan_time = 0;
        }
-       if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg))
+       if (mwifiex_scan_networks(priv, priv->user_scan_cfg))
                return -EFAULT;
 
        if (request->ie && request->ie_len) {
@@ -1703,7 +1744,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
 
        memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY;
+       wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
 
        /* Reserve space for mwifiex specific private data for BSS */
        wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
index 51e023ec1de4e634638575fc561206cd481fdbd7..c68adec3cc8b6522678c98582c7781b885193849 100644 (file)
@@ -578,6 +578,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
        } else {
                adapter->cmd_queued = cmd_node;
                mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+               queue_work(adapter->workqueue, &adapter->main_work);
        }
 
        return ret;
@@ -1102,7 +1103,8 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
                &resp->params.opt_hs_cfg;
        uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
 
-       if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
+       if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) &&
+           adapter->iface_type == MWIFIEX_SDIO) {
                mwifiex_hs_activated_event(priv, true);
                return 0;
        } else {
@@ -1114,6 +1116,9 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
        }
        if (conditions != HOST_SLEEP_CFG_CANCEL) {
                adapter->is_hs_configured = true;
+               if (adapter->iface_type == MWIFIEX_USB ||
+                   adapter->iface_type == MWIFIEX_PCIE)
+                       mwifiex_hs_activated_event(priv, true);
        } else {
                adapter->is_hs_configured = false;
                if (adapter->hs_activated)
index 561452a5c818f4a3d6ea653d029cd32fdab80587..ffb6cdfdb797ef2e9904147c06f83898b4ef644a 100644 (file)
@@ -124,6 +124,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_UAP_DTIM_PERIOD    (PROPRIETARY_TLV_BASE_ID + 45)
 #define TLV_TYPE_UAP_BCAST_SSID     (PROPRIETARY_TLV_BASE_ID + 48)
 #define TLV_TYPE_UAP_RTS_THRESHOLD  (PROPRIETARY_TLV_BASE_ID + 51)
+#define TLV_TYPE_UAP_WEP_KEY        (PROPRIETARY_TLV_BASE_ID + 59)
 #define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
 #define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
 #define TLV_TYPE_UAP_AKMP           (PROPRIETARY_TLV_BASE_ID + 65)
@@ -162,6 +163,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 
 #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
 
+#define MWIFIEX_DEF_HT_CAP     (IEEE80211_HT_CAP_DSSSCCK40 | \
+                                (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \
+                                IEEE80211_HT_CAP_SM_PS)
+
+#define MWIFIEX_DEF_AMPDU      IEEE80211_HT_AMPDU_PARM_FACTOR
+
 /* dev_cap bitmap
  * BIT
  * 0-16                reserved
@@ -219,6 +226,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_RF_REG_ACCESS                     0x001b
 #define HostCmd_CMD_PMIC_REG_ACCESS                   0x00ad
 #define HostCmd_CMD_802_11_RF_CHANNEL                 0x001d
+#define HostCmd_CMD_RF_TX_PWR                         0x001e
 #define HostCmd_CMD_802_11_DEAUTHENTICATE             0x0024
 #define HostCmd_CMD_MAC_CONTROL                       0x0028
 #define HostCmd_CMD_802_11_AD_HOC_START               0x002b
@@ -869,6 +877,13 @@ struct host_cmd_ds_txpwr_cfg {
        __le32 mode;
 } __packed;
 
+struct host_cmd_ds_rf_tx_pwr {
+       __le16 action;
+       __le16 cur_level;
+       u8 max_power;
+       u8 min_power;
+} __packed;
+
 struct mwifiex_bcn_param {
        u8 bssid[ETH_ALEN];
        u8 rssi;
@@ -1195,6 +1210,13 @@ struct host_cmd_tlv_passphrase {
        u8 passphrase[0];
 } __packed;
 
+struct host_cmd_tlv_wep_key {
+       struct host_cmd_tlv tlv;
+       u8 key_index;
+       u8 is_default;
+       u8 key[1];
+};
+
 struct host_cmd_tlv_auth_type {
        struct host_cmd_tlv tlv;
        u8 auth_type;
@@ -1347,6 +1369,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_tx_rate_query tx_rate;
                struct host_cmd_ds_tx_rate_cfg tx_rate_cfg;
                struct host_cmd_ds_txpwr_cfg txp_cfg;
+               struct host_cmd_ds_rf_tx_pwr txp;
                struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
                struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
                struct host_cmd_ds_802_11_scan scan;
index 383820a52beba0d62428614131adbe42def1e5db..8374e33f195a0a0638978b37c6d6592fbc676172 100644 (file)
@@ -225,29 +225,46 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
                         struct cfg80211_ap_settings *params)
 {
        struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
-       struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
-       struct ieee_types_header *ie = NULL;
+       struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
+       struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
        u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
        u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
-       u16 mask;
+       u16 mask, ie_len = 0;
+       const u8 *vendor_ie;
        int ret = 0;
 
        if (params->beacon.tail && params->beacon.tail_len) {
-               ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
-                                             params->beacon.tail_len);
-               if (ie) {
-                       rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
-                       if (!rsn_ie)
-                               return -ENOMEM;
-
-                       rsn_ie->ie_index = cpu_to_le16(rsn_idx);
-                       mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
-                              MGMT_MASK_ASSOC_RESP;
-                       rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
-                       rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
-                       memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
-
-                       if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
+               gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+               if (!gen_ie)
+                       return -ENOMEM;
+               gen_ie->ie_index = cpu_to_le16(rsn_idx);
+               mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+                      MGMT_MASK_ASSOC_RESP;
+               gen_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+
+               rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
+                                                 params->beacon.tail,
+                                                 params->beacon.tail_len);
+               if (rsn_ie) {
+                       memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2);
+                       ie_len = rsn_ie->len + 2;
+                       gen_ie->ie_length = cpu_to_le16(ie_len);
+               }
+
+               vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+                                                   WLAN_OUI_TYPE_MICROSOFT_WPA,
+                                                   params->beacon.tail,
+                                                   params->beacon.tail_len);
+               if (vendor_ie) {
+                       wpa_ie = (struct ieee_types_header *)vendor_ie;
+                       memcpy(gen_ie->ie_buffer + ie_len,
+                              wpa_ie, wpa_ie->len + 2);
+                       ie_len += wpa_ie->len + 2;
+                       gen_ie->ie_length = cpu_to_le16(ie_len);
+               }
+
+               if (rsn_ie || wpa_ie) {
+                       if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx,
                                                         NULL, NULL,
                                                         NULL, NULL)) {
                                ret = -1;
@@ -320,7 +337,7 @@ done:
        kfree(beacon_ie);
        kfree(pr_ie);
        kfree(ar_ie);
-       kfree(rsn_ie);
+       kfree(gen_ie);
 
        return ret;
 }
index c1cb004db913cd0064c55758962900f2ed5aa04f..b543a4d82ff3c64114892e13f758aa4d7db7abf2 100644 (file)
@@ -57,6 +57,69 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
        return 0;
 }
 
+static void scan_delay_timer_fn(unsigned long data)
+{
+       struct mwifiex_private *priv = (struct mwifiex_private *)data;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *cmd_node, *tmp_node;
+       unsigned long flags;
+
+       if (!mwifiex_wmm_lists_empty(adapter)) {
+               if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+                       /*
+                        * Abort scan operation by cancelling all pending scan
+                        * command
+                        */
+                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+                       list_for_each_entry_safe(cmd_node, tmp_node,
+                                                &adapter->scan_pending_q,
+                                                list) {
+                               list_del(&cmd_node->list);
+                               cmd_node->wait_q_enabled = false;
+                               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+                       }
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+
+                       spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+                       adapter->scan_processing = false;
+                       spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
+                                              flags);
+
+                       if (priv->user_scan_cfg) {
+                               dev_dbg(priv->adapter->dev,
+                                       "info: %s: scan aborted\n", __func__);
+                               cfg80211_scan_done(priv->scan_request, 1);
+                               priv->scan_request = NULL;
+                               kfree(priv->user_scan_cfg);
+                               priv->user_scan_cfg = NULL;
+                       }
+               } else {
+                       /*
+                        * Tx data queue is still not empty, delay scan
+                        * operation further by 20msec.
+                        */
+                       mod_timer(&priv->scan_delay_timer, jiffies +
+                                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+                       adapter->scan_delay_cnt++;
+               }
+               queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
+       } else {
+               /*
+                * Tx data queue is empty. Get scan command from scan_pending_q
+                * and put to cmd_pending_q to resume scan operation
+                */
+               adapter->scan_delay_cnt = 0;
+               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+               cmd_node = list_first_entry(&adapter->scan_pending_q,
+                                           struct cmd_ctrl_node, list);
+               list_del(&cmd_node->list);
+               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+               mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+       }
+}
+
 /*
  * This function initializes the private structure and sets default
  * values to the members.
@@ -136,6 +199,9 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
 
        priv->scan_block = false;
 
+       setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn,
+                   (unsigned long)priv);
+
        return mwifiex_add_bss_prio_tbl(priv);
 }
 
index e6be6ee75951ca811c78d7ebacaf9f05c0240c0a..9f088fb88cb7499a3f3d49ea380bf9ef50f07a10 100644 (file)
@@ -21,6 +21,7 @@
 #define _MWIFIEX_IOCTL_H_
 
 #include <net/mac80211.h>
+#include <net/lib80211.h>
 
 enum {
        MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
@@ -71,6 +72,13 @@ struct wpa_param {
        u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
 };
 
+struct wep_key {
+       u8 key_index;
+       u8 is_default;
+       u16 length;
+       u8 key[WLAN_KEY_LEN_WEP104];
+};
+
 #define KEY_MGMT_ON_HOST        0x03
 #define MWIFIEX_AUTH_MODE_AUTO  0xFF
 #define BAND_CONFIG_MANUAL      0x00
@@ -90,6 +98,8 @@ struct mwifiex_uap_bss_param {
        u16 key_mgmt;
        u16 key_mgmt_operation;
        struct wpa_param wpa_cfg;
+       struct wep_key wep_cfg[NUM_WEP_KEYS];
+       struct ieee80211_ht_cap ht_cap;
 };
 
 enum {
index 3192855c31c05df94e55360824f463ff0fbccfb8..f0219efc895386bf8f507ec8a64e94809d17c743 100644 (file)
@@ -190,7 +190,8 @@ process_start:
                            adapter->tx_lock_flag)
                                break;
 
-                       if (adapter->scan_processing || adapter->data_sent ||
+                       if ((adapter->scan_processing &&
+                            !adapter->scan_delay_cnt) || adapter->data_sent ||
                            mwifiex_wmm_lists_empty(adapter)) {
                                if (adapter->cmd_sent || adapter->curr_cmd ||
                                    (!is_command_pending(adapter)))
@@ -244,8 +245,8 @@ process_start:
                        }
                }
 
-               if (!adapter->scan_processing && !adapter->data_sent &&
-                   !mwifiex_wmm_lists_empty(adapter)) {
+               if ((!adapter->scan_processing || adapter->scan_delay_cnt) &&
+                   !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
                        mwifiex_wmm_process_tx(adapter);
                        if (adapter->hs_activated) {
                                adapter->is_hs_configured = false;
index bd3b0bf94b9e9d014a092d9770a8176982cac2df..7cd95cc99a8530f3746aa26529c91df478e2655e 100644 (file)
@@ -79,14 +79,17 @@ enum {
 
 #define SCAN_BEACON_ENTRY_PAD                  6
 
-#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200
-#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME  200
-#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME        110
+#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110
+#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME  30
+#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME        30
 
 #define SCAN_RSSI(RSSI)                                        (0x100 - ((u8)(RSSI)))
 
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME    (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
+#define MWIFIEX_MAX_SCAN_DELAY_CNT                     50
+#define MWIFIEX_SCAN_DELAY_MSEC                                20
+
 #define RSN_GTK_OUI_OFFSET                             2
 
 #define MWIFIEX_OUI_NOT_PRESENT                        0
@@ -482,6 +485,7 @@ struct mwifiex_private {
        u16 proberesp_idx;
        u16 assocresp_idx;
        u16 rsn_idx;
+       struct timer_list scan_delay_timer;
 };
 
 enum mwifiex_ba_status {
@@ -686,6 +690,7 @@ struct mwifiex_adapter {
        struct completion fw_load;
        u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
        u16 max_mgmt_ie_index;
+       u8 scan_delay_cnt;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -835,6 +840,9 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
 int mwifiex_set_secure_params(struct mwifiex_private *priv,
                              struct mwifiex_uap_bss_param *bss_config,
                              struct cfg80211_ap_settings *params);
+void mwifiex_set_ht_params(struct mwifiex_private *priv,
+                          struct mwifiex_uap_bss_param *bss_cfg,
+                          struct cfg80211_ap_settings *params);
 
 /*
  * This function checks if the queuing is RA based or not.
@@ -941,8 +949,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
                              struct mwifiex_rate_cfg *rate);
 int mwifiex_request_scan(struct mwifiex_private *priv,
                         struct cfg80211_ssid *req_ssid);
-int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
-                               struct mwifiex_user_scan_cfg *scan_req);
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+                         const struct mwifiex_user_scan_cfg *user_scan_in);
 int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
 
 int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel);
@@ -985,7 +993,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
 
 int mwifiex_main_process(struct mwifiex_adapter *);
 
-int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel);
 int mwifiex_bss_set_channel(struct mwifiex_private *,
                            struct mwifiex_chan_freq_power *cfp);
 int mwifiex_get_bss_info(struct mwifiex_private *,
index 74f0457157235d8a3100eb95e66027976493b19c..884ed6377003664488ca6b55ef7a9bc1cc703041 100644 (file)
 /* The maximum number of channels the firmware can scan per command */
 #define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
 
-#define MWIFIEX_CHANNELS_PER_SCAN_CMD            4
+#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD      4
+#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD   15
+#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD  27
+#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD  35
 
 /* Memory needed to store a max sized Channel List TLV for a firmware scan */
 #define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
@@ -471,7 +474,7 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
  * This routine is used for any scan that is not provided with a
  * specific channel list to scan.
  */
-static void
+static int
 mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                 const struct mwifiex_user_scan_cfg
                                                        *user_scan_in,
@@ -528,6 +531,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                }
 
        }
+       return chan_idx;
 }
 
 /*
@@ -727,6 +731,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
        u32 num_probes;
        u32 ssid_len;
        u32 chan_idx;
+       u32 chan_num;
        u32 scan_type;
        u16 scan_dur;
        u8 channel;
@@ -850,7 +855,7 @@ mwifiex_config_scan(struct mwifiex_private *priv,
        if (*filtered_scan)
                *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
        else
-               *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
+               *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
 
        /* If the input config or adapter has the number of Probes set,
           add tlv */
@@ -962,13 +967,28 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                        dev_dbg(adapter->dev,
                                "info: Scan: Scanning current channel only\n");
                }
-
+               chan_num = chan_idx;
        } else {
                dev_dbg(adapter->dev,
                        "info: Scan: Creating full region channel list\n");
-               mwifiex_scan_create_channel_list(priv, user_scan_in,
-                                                scan_chan_list,
-                                                *filtered_scan);
+               chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
+                                                           scan_chan_list,
+                                                           *filtered_scan);
+       }
+
+       /*
+        * In associated state we will reduce the number of channels scanned per
+        * scan command to avoid any traffic delay/loss. This number is decided
+        * based on total number of channels to be scanned due to constraints
+        * of command buffers.
+        */
+       if (priv->media_connected) {
+               if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD)
+                       *max_chan_per_scan = 1;
+               else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD)
+                       *max_chan_per_scan = 2;
+               else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
+                       *max_chan_per_scan = 3;
        }
 }
 
@@ -1276,8 +1296,8 @@ mwifiex_radio_type_to_band(u8 radio_type)
  * order to send the appropriate scan commands to firmware to populate or
  * update the internal driver scan table.
  */
-static int mwifiex_scan_networks(struct mwifiex_private *priv,
-               const struct mwifiex_user_scan_cfg *user_scan_in)
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+                         const struct mwifiex_user_scan_cfg *user_scan_in)
 {
        int ret = 0;
        struct mwifiex_adapter *adapter = priv->adapter;
@@ -1342,6 +1362,7 @@ static int mwifiex_scan_networks(struct mwifiex_private *priv,
                        adapter->cmd_queued = cmd_node;
                        mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
                                                        true);
+                       queue_work(adapter->workqueue, &adapter->main_work);
                } else {
                        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                                               flags);
@@ -1357,26 +1378,6 @@ static int mwifiex_scan_networks(struct mwifiex_private *priv,
        return ret;
 }
 
-/*
- * Sends IOCTL request to start a scan with user configurations.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- *
- * Upon completion, it also generates a wireless event to notify
- * applications.
- */
-int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
-                               struct mwifiex_user_scan_cfg *scan_req)
-{
-       int status;
-
-       status = mwifiex_scan_networks(priv, scan_req);
-       queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
-
-       return status;
-}
-
 /*
  * This function prepares a scan command to be sent to the firmware.
  *
@@ -1772,14 +1773,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        priv->user_scan_cfg = NULL;
                }
        } else {
-               /* Get scan command from scan_pending_q and put to
-                  cmd_pending_q */
-               cmd_node = list_first_entry(&adapter->scan_pending_q,
-                                           struct cmd_ctrl_node, list);
-               list_del(&cmd_node->list);
-               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
-               mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+               if (!mwifiex_wmm_lists_empty(adapter)) {
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+                       adapter->scan_delay_cnt = 1;
+                       mod_timer(&priv->scan_delay_timer, jiffies +
+                                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+               } else {
+                       /* Get scan command from scan_pending_q and put to
+                          cmd_pending_q */
+                       cmd_node = list_first_entry(&adapter->scan_pending_q,
+                                                   struct cmd_ctrl_node, list);
+                       list_del(&cmd_node->list);
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+                       mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+                                                       true);
+               }
        }
 
 done:
index 40e025da6bc28463749b76fed338a3c335c0f1b4..2d4319a8941f66a8d37d0594dd8f8f3225f70b38 100644 (file)
@@ -259,6 +259,23 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
        return 0;
 }
 
+/*
+ * This function prepares command to get RF Tx power.
+ */
+static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv,
+                                  struct host_cmd_ds_command *cmd,
+                                  u16 cmd_action, void *data_buf)
+{
+       struct host_cmd_ds_rf_tx_pwr *txp = &cmd->params.txp;
+
+       cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_tx_pwr)
+                               + S_DS_GEN);
+       cmd->command = cpu_to_le16(HostCmd_CMD_RF_TX_PWR);
+       txp->action = cpu_to_le16(cmd_action);
+
+       return 0;
+}
+
 /*
  * This function prepares command to set Host Sleep configuration.
  *
@@ -1055,6 +1072,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
                ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
                                               data_buf);
                break;
+       case HostCmd_CMD_RF_TX_PWR:
+               ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action,
+                                             data_buf);
+               break;
        case HostCmd_CMD_802_11_PS_MODE_ENH:
                ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
                                                 (uint16_t)cmd_oid, data_buf);
@@ -1283,7 +1304,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
        priv->data_rate = 0;
 
        /* get tx power */
-       ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
+       ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_RF_TX_PWR,
                                     HostCmd_ACT_GEN_GET, 0, NULL);
        if (ret)
                return -1;
index a79ed9bd96953d180b0aa956845052e488394066..4cb2c1c783971a2424c3efd7a9ddca836d06f8ce 100644 (file)
@@ -450,6 +450,30 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
        return 0;
 }
 
+/*
+ * This function handles the command response of get RF Tx power.
+ */
+static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv,
+                                  struct host_cmd_ds_command *resp)
+{
+       struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp;
+       u16 action = le16_to_cpu(txp->action);
+
+       priv->tx_power_level = le16_to_cpu(txp->cur_level);
+
+       if (action == HostCmd_ACT_GEN_GET) {
+               priv->max_tx_power_level = txp->max_power;
+               priv->min_tx_power_level = txp->min_power;
+       }
+
+       dev_dbg(priv->adapter->dev,
+               "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n",
+               priv->tx_power_level, priv->max_tx_power_level,
+               priv->min_tx_power_level);
+
+       return 0;
+}
+
 /*
  * This function handles the command response of set/get MAC address.
  *
@@ -847,6 +871,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
        case HostCmd_CMD_TXPWR_CFG:
                ret = mwifiex_ret_tx_power_cfg(priv, resp);
                break;
+       case HostCmd_CMD_RF_TX_PWR:
+               ret = mwifiex_ret_rf_tx_power(priv, resp);
+               break;
        case HostCmd_CMD_802_11_PS_MODE_ENH:
                ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
                break;
index 106c449477b2924029942b9b3863b312b527d24c..f2fd2423214f1375da61e0449a3fcd94e5cfaeef 100644 (file)
@@ -66,9 +66,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
        dev_dbg(adapter->dev, "cmd pending\n");
        atomic_inc(&adapter->cmd_pending);
 
-       /* Status pending, wake up main process */
-       queue_work(adapter->workqueue, &adapter->main_work);
-
        /* Wait for completion */
        wait_event_interruptible(adapter->cmd_wait_q.wait,
                                 *(cmd_queued->condition));
index 89f9a2a45de3f772e15cbd4084735e9bc7013d54..f40e93fe894aca64702219b8223c464a526c92bf 100644 (file)
@@ -26,6 +26,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                              struct mwifiex_uap_bss_param *bss_config,
                              struct cfg80211_ap_settings *params) {
        int i;
+       struct mwifiex_wep_key wep_key;
 
        if (!params->privacy) {
                bss_config->protocol = PROTOCOL_NO_SECURITY;
@@ -65,7 +66,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                        }
                        if (params->crypto.wpa_versions &
                            NL80211_WPA_VERSION_2) {
-                               bss_config->protocol = PROTOCOL_WPA2;
+                               bss_config->protocol |= PROTOCOL_WPA2;
                                bss_config->key_mgmt = KEY_MGMT_EAP;
                        }
                        break;
@@ -77,7 +78,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                        }
                        if (params->crypto.wpa_versions &
                            NL80211_WPA_VERSION_2) {
-                               bss_config->protocol = PROTOCOL_WPA2;
+                               bss_config->protocol |= PROTOCOL_WPA2;
                                bss_config->key_mgmt = KEY_MGMT_PSK;
                        }
                        break;
@@ -91,10 +92,19 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
                case WLAN_CIPHER_SUITE_WEP104:
                        break;
                case WLAN_CIPHER_SUITE_TKIP:
-                       bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+                       if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+                               bss_config->wpa_cfg.pairwise_cipher_wpa |=
+                                                               CIPHER_TKIP;
+                       if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+                               bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
+                                                               CIPHER_TKIP;
                        break;
                case WLAN_CIPHER_SUITE_CCMP:
-                       bss_config->wpa_cfg.pairwise_cipher_wpa2 =
+                       if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+                               bss_config->wpa_cfg.pairwise_cipher_wpa |=
+                                                               CIPHER_AES_CCMP;
+                       if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+                               bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
                                                                CIPHER_AES_CCMP;
                default:
                        break;
@@ -104,6 +114,27 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
        switch (params->crypto.cipher_group) {
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
+               if (priv->sec_info.wep_enabled) {
+                       bss_config->protocol = PROTOCOL_STATIC_WEP;
+                       bss_config->key_mgmt = KEY_MGMT_NONE;
+                       bss_config->wpa_cfg.length = 0;
+
+                       for (i = 0; i < NUM_WEP_KEYS; i++) {
+                               wep_key = priv->wep_key[i];
+                               bss_config->wep_cfg[i].key_index = i;
+
+                               if (priv->wep_key_curr_index == i)
+                                       bss_config->wep_cfg[i].is_default = 1;
+                               else
+                                       bss_config->wep_cfg[i].is_default = 0;
+
+                               bss_config->wep_cfg[i].length =
+                                                            wep_key.key_length;
+                               memcpy(&bss_config->wep_cfg[i].key,
+                                      &wep_key.key_material,
+                                      wep_key.key_length);
+                       }
+               }
                break;
        case WLAN_CIPHER_SUITE_TKIP:
                bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
@@ -118,6 +149,33 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
        return 0;
 }
 
+/* This function updates 11n related parameters from IE and sets them into
+ * bss_config structure.
+ */
+void
+mwifiex_set_ht_params(struct mwifiex_private *priv,
+                     struct mwifiex_uap_bss_param *bss_cfg,
+                     struct cfg80211_ap_settings *params)
+{
+       const u8 *ht_ie;
+
+       if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
+               return;
+
+       ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
+                                params->beacon.tail_len);
+       if (ht_ie) {
+               memcpy(&bss_cfg->ht_cap, ht_ie + 2,
+                      sizeof(struct ieee80211_ht_cap));
+       } else {
+               memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
+               bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
+               bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
+       }
+
+       return;
+}
+
 /* This function initializes some of mwifiex_uap_bss_param variables.
  * This helps FW in ignoring invalid values. These values may or may not
  * be get updated to valid ones at later stage.
@@ -134,6 +192,120 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
        config->retry_limit = 0x7F;
 }
 
+/* This function parses BSS related parameters from structure
+ * and prepares TLVs specific to WPA/WPA2 security.
+ * These TLVs are appended to command buffer.
+ */
+static void
+mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
+{
+       struct host_cmd_tlv_pwk_cipher *pwk_cipher;
+       struct host_cmd_tlv_gwk_cipher *gwk_cipher;
+       struct host_cmd_tlv_passphrase *passphrase;
+       struct host_cmd_tlv_akmp *tlv_akmp;
+       struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+       u16 cmd_size = *param_size;
+       u8 *tlv = *tlv_buf;
+
+       tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
+       tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
+       tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
+                                       sizeof(struct host_cmd_tlv));
+       tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
+       tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
+       cmd_size += sizeof(struct host_cmd_tlv_akmp);
+       tlv += sizeof(struct host_cmd_tlv_akmp);
+
+       if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
+               pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+               pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+               pwk_cipher->tlv.len =
+                       cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
+                                   sizeof(struct host_cmd_tlv));
+               pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
+               pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
+               cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+               tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+       }
+
+       if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
+               pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+               pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+               pwk_cipher->tlv.len =
+                       cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
+                                   sizeof(struct host_cmd_tlv));
+               pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
+               pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
+               cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+               tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+       }
+
+       if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+               gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
+               gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+               gwk_cipher->tlv.len =
+                       cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
+                                   sizeof(struct host_cmd_tlv));
+               gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
+               cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
+               tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
+       }
+
+       if (bss_cfg->wpa_cfg.length) {
+               passphrase = (struct host_cmd_tlv_passphrase *)tlv;
+               passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+               passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
+               memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
+                      bss_cfg->wpa_cfg.length);
+               cmd_size += sizeof(struct host_cmd_tlv) +
+                           bss_cfg->wpa_cfg.length;
+               tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length;
+       }
+
+       *param_size = cmd_size;
+       *tlv_buf = tlv;
+
+       return;
+}
+
+/* This function parses BSS related parameters from structure
+ * and prepares TLVs specific to WEP encryption.
+ * These TLVs are appended to command buffer.
+ */
+static void
+mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
+{
+       struct host_cmd_tlv_wep_key *wep_key;
+       u16 cmd_size = *param_size;
+       int i;
+       u8 *tlv = *tlv_buf;
+       struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+
+       for (i = 0; i < NUM_WEP_KEYS; i++) {
+               if (bss_cfg->wep_cfg[i].length &&
+                   (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
+                    bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
+                       wep_key = (struct host_cmd_tlv_wep_key *)tlv;
+                       wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+                       wep_key->tlv.len =
+                               cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
+                       wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
+                       wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
+                       memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
+                              bss_cfg->wep_cfg[i].length);
+                       cmd_size += sizeof(struct host_cmd_tlv) + 2 +
+                                   bss_cfg->wep_cfg[i].length;
+                       tlv += sizeof(struct host_cmd_tlv) + 2 +
+                                   bss_cfg->wep_cfg[i].length;
+               }
+       }
+
+       *param_size = cmd_size;
+       *tlv_buf = tlv;
+
+       return;
+}
+
 /* This function parses BSS related parameters from structure
  * and prepares TLVs. These TLVs are appended to command buffer.
 */
@@ -148,12 +320,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        struct host_cmd_tlv_frag_threshold *frag_threshold;
        struct host_cmd_tlv_rts_threshold *rts_threshold;
        struct host_cmd_tlv_retry_limit *retry_limit;
-       struct host_cmd_tlv_pwk_cipher *pwk_cipher;
-       struct host_cmd_tlv_gwk_cipher *gwk_cipher;
        struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
        struct host_cmd_tlv_auth_type *auth_type;
-       struct host_cmd_tlv_passphrase *passphrase;
-       struct host_cmd_tlv_akmp *tlv_akmp;
+       struct mwifiex_ie_types_htcap *htcap;
        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
        u16 cmd_size = *param_size;
 
@@ -243,70 +412,11 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        }
        if ((bss_cfg->protocol & PROTOCOL_WPA) ||
            (bss_cfg->protocol & PROTOCOL_WPA2) ||
-           (bss_cfg->protocol & PROTOCOL_EAP)) {
-               tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
-               tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
-               tlv_akmp->tlv.len =
-                   cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
-                               sizeof(struct host_cmd_tlv));
-               tlv_akmp->key_mgmt_operation =
-                       cpu_to_le16(bss_cfg->key_mgmt_operation);
-               tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
-               cmd_size += sizeof(struct host_cmd_tlv_akmp);
-               tlv += sizeof(struct host_cmd_tlv_akmp);
-
-               if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
-                               VALID_CIPHER_BITMAP) {
-                       pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-                       pwk_cipher->tlv.type =
-                               cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-                       pwk_cipher->tlv.len = cpu_to_le16(
-                               sizeof(struct host_cmd_tlv_pwk_cipher) -
-                               sizeof(struct host_cmd_tlv));
-                       pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
-                       pwk_cipher->cipher =
-                               bss_cfg->wpa_cfg.pairwise_cipher_wpa;
-                       cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
-                       tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
-               }
-               if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
-                               VALID_CIPHER_BITMAP) {
-                       pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-                       pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-                       pwk_cipher->tlv.len = cpu_to_le16(
-                               sizeof(struct host_cmd_tlv_pwk_cipher) -
-                               sizeof(struct host_cmd_tlv));
-                       pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
-                       pwk_cipher->cipher =
-                               bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
-                       cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
-                       tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
-               }
-               if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
-                       gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
-                       gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
-                       gwk_cipher->tlv.len = cpu_to_le16(
-                               sizeof(struct host_cmd_tlv_gwk_cipher) -
-                               sizeof(struct host_cmd_tlv));
-                       gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
-                       cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
-                       tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
-               }
-               if (bss_cfg->wpa_cfg.length) {
-                       passphrase = (struct host_cmd_tlv_passphrase *)tlv;
-                       passphrase->tlv.type =
-                               cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
-                       passphrase->tlv.len =
-                               cpu_to_le16(bss_cfg->wpa_cfg.length);
-                       memcpy(passphrase->passphrase,
-                              bss_cfg->wpa_cfg.passphrase,
-                              bss_cfg->wpa_cfg.length);
-                       cmd_size += sizeof(struct host_cmd_tlv) +
-                                   bss_cfg->wpa_cfg.length;
-                       tlv += sizeof(struct host_cmd_tlv) +
-                              bss_cfg->wpa_cfg.length;
-               }
-       }
+           (bss_cfg->protocol & PROTOCOL_EAP))
+               mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
+       else
+               mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
+
        if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
            (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
                auth_type = (struct host_cmd_tlv_auth_type *)tlv;
@@ -330,6 +440,25 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
                tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
        }
 
+       if (bss_cfg->ht_cap.cap_info) {
+               htcap = (struct mwifiex_ie_types_htcap *)tlv;
+               htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+               htcap->header.len =
+                               cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+               htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
+               htcap->ht_cap.ampdu_params_info =
+                                            bss_cfg->ht_cap.ampdu_params_info;
+               memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
+                      sizeof(struct ieee80211_mcs_info));
+               htcap->ht_cap.extended_ht_cap_info =
+                                       bss_cfg->ht_cap.extended_ht_cap_info;
+               htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
+               htcap->ht_cap.antenna_selection_info =
+                                       bss_cfg->ht_cap.antenna_selection_info;
+               cmd_size += sizeof(struct mwifiex_ie_types_htcap);
+               tlv += sizeof(struct mwifiex_ie_types_htcap);
+       }
+
        *param_size = cmd_size;
 
        return 0;
@@ -421,33 +550,3 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
 
        return 0;
 }
-
-/* This function sets the RF channel for AP.
- *
- * This function populates channel information in AP config structure
- * and sends command to configure channel information in AP.
- */
-int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
-{
-       struct mwifiex_uap_bss_param *bss_cfg;
-       struct wiphy *wiphy = priv->wdev->wiphy;
-
-       bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
-       if (!bss_cfg)
-               return -ENOMEM;
-
-       mwifiex_set_sys_config_invalid_data(bss_cfg);
-       bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
-       bss_cfg->channel = channel;
-
-       if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
-                                  HostCmd_ACT_GEN_SET,
-                                  UAP_BSS_PARAMS_I, bss_cfg)) {
-               wiphy_err(wiphy, "Failed to set the uAP channel\n");
-               kfree(bss_cfg);
-               return -1;
-       }
-
-       kfree(bss_cfg);
-       return 0;
-}
index f7b15b8934fabb0648a70106c0c2c25c45f78434..e15675585fb10ae21a16ba7c9210fb3f703911c2 100644 (file)
@@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
        return err;
 }
 
-static int orinoco_set_channel(struct wiphy *wiphy,
-                       struct net_device *netdev,
-                       struct ieee80211_channel *chan,
-                       enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type)
 {
        struct orinoco_private *priv = wiphy_priv(wiphy);
        int err = 0;
@@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 
 const struct cfg80211_ops orinoco_cfg_ops = {
        .change_virtual_intf = orinoco_change_vif,
-       .set_channel = orinoco_set_channel,
+       .set_monitor_channel = orinoco_set_monitor_channel,
        .scan = orinoco_scan,
        .set_wiphy_params = orinoco_set_wiphy_params,
 };
index 299c3879582da14e12ca00d7f11184da8c61bed7..c7548da6573df87e0bf8017cf1da763efc1bc698 100644 (file)
@@ -99,6 +99,14 @@ config RT2800PCI_RT53XX
          rt2800pci driver.
          Supported chips: RT5390
 
+config RT2800PCI_RT3290
+       bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       default y
+       ---help---
+         This adds support for rt3290 wireless chipset family to the
+         rt2800pci driver.
+         Supported chips: RT3290
 endif
 
 config RT2500USB
index 9348521e083275f6dff971cc5c8283a68cacf1c5..e252e9bafd0e2776075a8159d74e4f9180b87e83 100644 (file)
@@ -51,6 +51,7 @@
  * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
  * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
  * RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5360 2.4G 1T1R
  * RF5370 2.4G 1T1R
  * RF5390 2.4G 1T1R
  */
 #define RF3320                         0x000b
 #define RF3322                         0x000c
 #define RF3053                         0x000d
+#define RF3290                         0x3290
+#define RF5360                         0x5360
 #define RF5370                         0x5370
 #define RF5372                         0x5372
 #define RF5390                         0x5390
+#define RF5392                         0x5392
 
 /*
  * Chipset revisions.
  * Registers.
  */
 
+
+/*
+ * MAC_CSR0_3290: MAC_CSR0 for RT3290 to identity MAC version number.
+ */
+#define MAC_CSR0_3290                          0x0000
+
 /*
  * E2PROM_CSR: PCI EEPROM control register.
  * RELOAD: Write 1 to reload eeprom content.
 #define E2PROM_CSR_LOAD_STATUS         FIELD32(0x00000040)
 #define E2PROM_CSR_RELOAD              FIELD32(0x00000080)
 
+/*
+ * CMB_CTRL_CFG
+ */
+#define CMB_CTRL               0x0020
+#define AUX_OPT_BIT0           FIELD32(0x00000001)
+#define AUX_OPT_BIT1           FIELD32(0x00000002)
+#define AUX_OPT_BIT2           FIELD32(0x00000004)
+#define AUX_OPT_BIT3           FIELD32(0x00000008)
+#define AUX_OPT_BIT4           FIELD32(0x00000010)
+#define AUX_OPT_BIT5           FIELD32(0x00000020)
+#define AUX_OPT_BIT6           FIELD32(0x00000040)
+#define AUX_OPT_BIT7           FIELD32(0x00000080)
+#define AUX_OPT_BIT8           FIELD32(0x00000100)
+#define AUX_OPT_BIT9           FIELD32(0x00000200)
+#define AUX_OPT_BIT10          FIELD32(0x00000400)
+#define AUX_OPT_BIT11          FIELD32(0x00000800)
+#define AUX_OPT_BIT12          FIELD32(0x00001000)
+#define AUX_OPT_BIT13          FIELD32(0x00002000)
+#define AUX_OPT_BIT14          FIELD32(0x00004000)
+#define AUX_OPT_BIT15          FIELD32(0x00008000)
+#define LDO25_LEVEL            FIELD32(0x00030000)
+#define LDO25_LARGEA           FIELD32(0x00040000)
+#define LDO25_FRC_ON           FIELD32(0x00080000)
+#define CMB_RSV                        FIELD32(0x00300000)
+#define XTAL_RDY               FIELD32(0x00400000)
+#define PLL_LD                 FIELD32(0x00800000)
+#define LDO_CORE_LEVEL         FIELD32(0x0F000000)
+#define LDO_BGSEL              FIELD32(0x30000000)
+#define LDO3_EN                        FIELD32(0x40000000)
+#define LDO0_EN                        FIELD32(0x80000000)
+
+/*
+ * EFUSE_CSR_3290: RT3290 EEPROM
+ */
+#define EFUSE_CTRL_3290                        0x0024
+
+/*
+ * EFUSE_DATA3 of 3290
+ */
+#define EFUSE_DATA3_3290               0x0028
+
+/*
+ * EFUSE_DATA2 of 3290
+ */
+#define EFUSE_DATA2_3290               0x002c
+
+/*
+ * EFUSE_DATA1 of 3290
+ */
+#define EFUSE_DATA1_3290               0x0030
+
+/*
+ * EFUSE_DATA0 of 3290
+ */
+#define EFUSE_DATA0_3290               0x0034
+
+/*
+ * OSC_CTRL_CFG
+ * Ring oscillator configuration
+ */
+#define OSC_CTRL               0x0038
+#define OSC_REF_CYCLE          FIELD32(0x00001fff)
+#define OSC_RSV                        FIELD32(0x0000e000)
+#define OSC_CAL_CNT            FIELD32(0x0fff0000)
+#define OSC_CAL_ACK            FIELD32(0x10000000)
+#define OSC_CLK_32K_VLD                FIELD32(0x20000000)
+#define OSC_CAL_REQ            FIELD32(0x40000000)
+#define OSC_ROSC_EN            FIELD32(0x80000000)
+
+/*
+ * COEX_CFG_0
+ */
+#define COEX_CFG0                      0x0040
+#define COEX_CFG_ANT           FIELD32(0xff000000)
+/*
+ * COEX_CFG_1
+ */
+#define COEX_CFG1                      0x0044
+
+/*
+ * COEX_CFG_2
+ */
+#define COEX_CFG2                      0x0048
+#define BT_COEX_CFG1           FIELD32(0xff000000)
+#define BT_COEX_CFG0           FIELD32(0x00ff0000)
+#define WL_COEX_CFG1           FIELD32(0x0000ff00)
+#define WL_COEX_CFG0           FIELD32(0x000000ff)
+/*
+ * PLL_CTRL_CFG
+ * PLL configuration register
+ */
+#define PLL_CTRL               0x0050
+#define PLL_RESERVED_INPUT1    FIELD32(0x000000ff)
+#define PLL_RESERVED_INPUT2    FIELD32(0x0000ff00)
+#define PLL_CONTROL            FIELD32(0x00070000)
+#define PLL_LPF_R1             FIELD32(0x00080000)
+#define PLL_LPF_C1_CTRL        FIELD32(0x00300000)
+#define PLL_LPF_C2_CTRL        FIELD32(0x00c00000)
+#define PLL_CP_CURRENT_CTRL    FIELD32(0x03000000)
+#define PLL_PFD_DELAY_CTRL     FIELD32(0x0c000000)
+#define PLL_LOCK_CTRL          FIELD32(0x70000000)
+#define PLL_VBGBK_EN           FIELD32(0x80000000)
+
+
+/*
+ * WLAN_CTRL_CFG
+ * RT3290 wlan configuration
+ */
+#define WLAN_FUN_CTRL                  0x0080
+#define WLAN_EN                                FIELD32(0x00000001)
+#define WLAN_CLK_EN                    FIELD32(0x00000002)
+#define WLAN_RSV1                      FIELD32(0x00000004)
+#define WLAN_RESET                     FIELD32(0x00000008)
+#define PCIE_APP0_CLK_REQ              FIELD32(0x00000010)
+#define FRC_WL_ANT_SET                 FIELD32(0x00000020)
+#define INV_TR_SW0                     FIELD32(0x00000040)
+#define WLAN_GPIO_IN_BIT0              FIELD32(0x00000100)
+#define WLAN_GPIO_IN_BIT1              FIELD32(0x00000200)
+#define WLAN_GPIO_IN_BIT2              FIELD32(0x00000400)
+#define WLAN_GPIO_IN_BIT3              FIELD32(0x00000800)
+#define WLAN_GPIO_IN_BIT4              FIELD32(0x00001000)
+#define WLAN_GPIO_IN_BIT5              FIELD32(0x00002000)
+#define WLAN_GPIO_IN_BIT6              FIELD32(0x00004000)
+#define WLAN_GPIO_IN_BIT7              FIELD32(0x00008000)
+#define WLAN_GPIO_IN_BIT_ALL           FIELD32(0x0000ff00)
+#define WLAN_GPIO_OUT_BIT0             FIELD32(0x00010000)
+#define WLAN_GPIO_OUT_BIT1             FIELD32(0x00020000)
+#define WLAN_GPIO_OUT_BIT2             FIELD32(0x00040000)
+#define WLAN_GPIO_OUT_BIT3             FIELD32(0x00050000)
+#define WLAN_GPIO_OUT_BIT4             FIELD32(0x00100000)
+#define WLAN_GPIO_OUT_BIT5             FIELD32(0x00200000)
+#define WLAN_GPIO_OUT_BIT6             FIELD32(0x00400000)
+#define WLAN_GPIO_OUT_BIT7             FIELD32(0x00800000)
+#define WLAN_GPIO_OUT_BIT_ALL          FIELD32(0x00ff0000)
+#define WLAN_GPIO_OUT_OE_BIT0          FIELD32(0x01000000)
+#define WLAN_GPIO_OUT_OE_BIT1          FIELD32(0x02000000)
+#define WLAN_GPIO_OUT_OE_BIT2          FIELD32(0x04000000)
+#define WLAN_GPIO_OUT_OE_BIT3          FIELD32(0x08000000)
+#define WLAN_GPIO_OUT_OE_BIT4          FIELD32(0x10000000)
+#define WLAN_GPIO_OUT_OE_BIT5          FIELD32(0x20000000)
+#define WLAN_GPIO_OUT_OE_BIT6          FIELD32(0x40000000)
+#define WLAN_GPIO_OUT_OE_BIT7          FIELD32(0x80000000)
+#define WLAN_GPIO_OUT_OE_BIT_ALL       FIELD32(0xff000000)
+
 /*
  * AUX_CTRL: Aux/PCI-E related configuration
  */
@@ -1760,9 +1914,11 @@ struct mac_iveiv_entry {
 /*
  * BBP 3: RX Antenna
  */
-#define BBP3_RX_ADC                            FIELD8(0x03)
+#define BBP3_RX_ADC                    FIELD8(0x03)
 #define BBP3_RX_ANTENNA                        FIELD8(0x18)
 #define BBP3_HT40_MINUS                        FIELD8(0x20)
+#define BBP3_ADC_MODE_SWITCH           FIELD8(0x40)
+#define BBP3_ADC_INIT_MODE             FIELD8(0x80)
 
 /*
  * BBP 4: Bandwidth
@@ -1771,6 +1927,14 @@ struct mac_iveiv_entry {
 #define BBP4_BANDWIDTH                 FIELD8(0x18)
 #define BBP4_MAC_IF_CTRL               FIELD8(0x40)
 
+/*
+ * BBP 47: Bandwidth
+ */
+#define BBP47_TSSI_REPORT_SEL          FIELD8(0x03)
+#define BBP47_TSSI_UPDATE_REQ          FIELD8(0x04)
+#define BBP47_TSSI_TSSI_MODE           FIELD8(0x18)
+#define BBP47_TSSI_ADC6                        FIELD8(0x80)
+
 /*
  * BBP 109
  */
@@ -1913,6 +2077,16 @@ struct mac_iveiv_entry {
 #define RFCSR27_R3                     FIELD8(0x30)
 #define RFCSR27_R4                     FIELD8(0x40)
 
+/*
+ * RFCSR 29:
+ */
+#define RFCSR29_ADC6_TEST              FIELD8(0x01)
+#define RFCSR29_ADC6_INT_TEST          FIELD8(0x02)
+#define RFCSR29_RSSI_RESET             FIELD8(0x04)
+#define RFCSR29_RSSI_ON                        FIELD8(0x08)
+#define RFCSR29_RSSI_RIP_CTRL          FIELD8(0x30)
+#define RFCSR29_RSSI_GAIN              FIELD8(0xc0)
+
 /*
  * RFCSR 30:
  */
@@ -1943,6 +2117,11 @@ struct mac_iveiv_entry {
  */
 #define RFCSR49_TX                     FIELD8(0x3f)
 
+/*
+ * RFCSR 50:
+ */
+#define RFCSR50_TX                     FIELD8(0x3f)
+
 /*
  * RF registers
  */
index dfc90d34be6d31def8590d85a413a38067de8ed4..068276ee8affd07605c2b02f82e0d9314aff7a1f 100644 (file)
@@ -354,16 +354,15 @@ int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
         * of 4kb. Certain USB chipsets however require different firmware,
         * which Ralink only provides attached to the original firmware
         * file. Thus for USB devices, firmware files have a length
-        * which is a multiple of 4kb.
+        * which is a multiple of 4kb. The firmware for rt3290 chip also
+        * have a length which is a multiple of 4kb.
         */
-       if (rt2x00_is_usb(rt2x00dev)) {
+       if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290))
                fw_len = 4096;
-               multiple = true;
-       } else {
+       else
                fw_len = 8192;
-               multiple = true;
-       }
 
+       multiple = true;
        /*
         * Validate the firmware length
         */
@@ -415,7 +414,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
                return -EBUSY;
 
        if (rt2x00_is_pci(rt2x00dev)) {
-               if (rt2x00_rt(rt2x00dev, RT3572) ||
+               if (rt2x00_rt(rt2x00dev, RT3290) ||
+                   rt2x00_rt(rt2x00dev, RT3572) ||
                    rt2x00_rt(rt2x00dev, RT5390) ||
                    rt2x00_rt(rt2x00dev, RT5392)) {
                        rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
@@ -851,8 +851,13 @@ int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
-       return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+               return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0);
+       } else {
+               rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+               return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+       }
 }
 EXPORT_SYMBOL_GPL(rt2800_rfkill_poll);
 
@@ -1935,9 +1940,54 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
 }
 
+#define RT3290_POWER_BOUND     0x27
+#define RT3290_FREQ_OFFSET_BOUND       0x5f
 #define RT5390_POWER_BOUND     0x27
 #define RT5390_FREQ_OFFSET_BOUND       0x5f
 
+static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
+{
+       u8 rfcsr;
+
+       rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
+       rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
+       rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2);
+       rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
+       if (info->default_power1 > RT3290_POWER_BOUND)
+               rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT3290_POWER_BOUND);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
+       rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+       if (rt2x00dev->freq_offset > RT3290_FREQ_OFFSET_BOUND)
+               rt2x00_set_field8(&rfcsr, RFCSR17_CODE,
+                                 RT3290_FREQ_OFFSET_BOUND);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
+       rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+
+       if (rf->channel <= 14) {
+               if (rf->channel == 6)
+                       rt2800_bbp_write(rt2x00dev, 68, 0x0c);
+               else
+                       rt2800_bbp_write(rt2x00dev, 68, 0x0b);
+
+               if (rf->channel >= 1 && rf->channel <= 6)
+                       rt2800_bbp_write(rt2x00dev, 59, 0x0f);
+               else if (rf->channel >= 7 && rf->channel <= 11)
+                       rt2800_bbp_write(rt2x00dev, 59, 0x0e);
+               else if (rf->channel >= 12 && rf->channel <= 14)
+                       rt2800_bbp_write(rt2x00dev, 59, 0x0d);
+       }
+}
+
 static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
                                         struct ieee80211_conf *conf,
                                         struct rf_channel *rf,
@@ -1958,7 +2008,22 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
                rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
        rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
 
+       if (rt2x00_rt(rt2x00dev, RT5392)) {
+               rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+               if (info->default_power1 > RT5390_POWER_BOUND)
+                       rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+                                         RT5390_POWER_BOUND);
+               else
+                       rt2x00_set_field8(&rfcsr, RFCSR50_TX,
+                                         info->default_power2);
+               rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+       }
+
        rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+       if (rt2x00_rt(rt2x00dev, RT5392)) {
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+       }
        rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
        rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
        rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
@@ -2021,15 +2086,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
                        }
                }
        }
-
-       rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0);
-       rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0);
-       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-
-       rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
-       rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
 }
 
 static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -2039,7 +2095,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
        unsigned int tx_pin;
-       u8 bbp;
+       u8 bbp, rfcsr;
 
        if (rf->channel <= 14) {
                info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
@@ -2060,15 +2116,36 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        case RF3052:
                rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
                break;
+       case RF3290:
+               rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
+               break;
+       case RF5360:
        case RF5370:
        case RF5372:
        case RF5390:
+       case RF5392:
                rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
                break;
        default:
                rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
        }
 
+       if (rt2x00_rf(rt2x00dev, RF3290) ||
+           rt2x00_rf(rt2x00dev, RF5360) ||
+           rt2x00_rf(rt2x00dev, RF5370) ||
+           rt2x00_rf(rt2x00dev, RF5372) ||
+           rt2x00_rf(rt2x00dev, RF5390) ||
+           rt2x00_rf(rt2x00dev, RF5392)) {
+               rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0);
+               rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+               rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+       }
+
        /*
         * Change BBP settings
         */
@@ -2549,9 +2626,12 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
                rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
                break;
+       case RF3290:
+       case RF5360:
        case RF5370:
        case RF5372:
        case RF5390:
+       case RF5392:
                rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
                rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
                rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
@@ -2682,6 +2762,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
                if (rt2x00_rt(rt2x00dev, RT3070) ||
                    rt2x00_rt(rt2x00dev, RT3071) ||
                    rt2x00_rt(rt2x00dev, RT3090) ||
+                   rt2x00_rt(rt2x00dev, RT3290) ||
                    rt2x00_rt(rt2x00dev, RT3390) ||
                    rt2x00_rt(rt2x00dev, RT5390) ||
                    rt2x00_rt(rt2x00dev, RT5392))
@@ -2778,10 +2859,54 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
        rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
 
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+               if (rt2x00_get_field32(reg, WLAN_EN) == 1) {
+                       rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 1);
+                       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               }
+
+               rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+               if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) {
+                       rt2x00_set_field32(&reg, LDO0_EN, 1);
+                       rt2x00_set_field32(&reg, LDO_BGSEL, 3);
+                       rt2800_register_write(rt2x00dev, CMB_CTRL, reg);
+               }
+
+               rt2800_register_read(rt2x00dev, OSC_CTRL, &reg);
+               rt2x00_set_field32(&reg, OSC_ROSC_EN, 1);
+               rt2x00_set_field32(&reg, OSC_CAL_REQ, 1);
+               rt2x00_set_field32(&reg, OSC_REF_CYCLE, 0x27);
+               rt2800_register_write(rt2x00dev, OSC_CTRL, reg);
+
+               rt2800_register_read(rt2x00dev, COEX_CFG0, &reg);
+               rt2x00_set_field32(&reg, COEX_CFG_ANT, 0x5e);
+               rt2800_register_write(rt2x00dev, COEX_CFG0, reg);
+
+               rt2800_register_read(rt2x00dev, COEX_CFG2, &reg);
+               rt2x00_set_field32(&reg, BT_COEX_CFG1, 0x00);
+               rt2x00_set_field32(&reg, BT_COEX_CFG0, 0x17);
+               rt2x00_set_field32(&reg, WL_COEX_CFG1, 0x93);
+               rt2x00_set_field32(&reg, WL_COEX_CFG0, 0x7f);
+               rt2800_register_write(rt2x00dev, COEX_CFG2, reg);
+
+               rt2800_register_read(rt2x00dev, PLL_CTRL, &reg);
+               rt2x00_set_field32(&reg, PLL_CONTROL, 1);
+               rt2800_register_write(rt2x00dev, PLL_CTRL, reg);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT3071) ||
            rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3290) ||
            rt2x00_rt(rt2x00dev, RT3390)) {
-               rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+
+               if (rt2x00_rt(rt2x00dev, RT3290))
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG0,
+                                             0x00000404);
+               else
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG0,
+                                             0x00000400);
+
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
                if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
                    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
@@ -3190,14 +3315,16 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                     rt2800_wait_bbp_ready(rt2x00dev)))
                return -EACCES;
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392)) {
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_read(rt2x00dev, 4, &value);
                rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
                rt2800_bbp_write(rt2x00dev, 4, value);
        }
 
        if (rt2800_is_305x_soc(rt2x00dev) ||
+           rt2x00_rt(rt2x00dev, RT3290) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
            rt2x00_rt(rt2x00dev, RT5392))
@@ -3206,20 +3333,26 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        rt2800_bbp_write(rt2x00dev, 65, 0x2c);
        rt2800_bbp_write(rt2x00dev, 66, 0x38);
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
                rt2800_bbp_write(rt2x00dev, 69, 0x16);
                rt2800_bbp_write(rt2x00dev, 73, 0x12);
-       } else if (rt2x00_rt(rt2x00dev, RT5390) ||
-                          rt2x00_rt(rt2x00dev, RT5392)) {
+       } else if (rt2x00_rt(rt2x00dev, RT3290) ||
+                  rt2x00_rt(rt2x00dev, RT5390) ||
+                  rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 69, 0x12);
                rt2800_bbp_write(rt2x00dev, 73, 0x13);
                rt2800_bbp_write(rt2x00dev, 75, 0x46);
                rt2800_bbp_write(rt2x00dev, 76, 0x28);
-               rt2800_bbp_write(rt2x00dev, 77, 0x59);
+
+               if (rt2x00_rt(rt2x00dev, RT3290))
+                       rt2800_bbp_write(rt2x00dev, 77, 0x58);
+               else
+                       rt2800_bbp_write(rt2x00dev, 77, 0x59);
        } else {
                rt2800_bbp_write(rt2x00dev, 69, 0x12);
                rt2800_bbp_write(rt2x00dev, 73, 0x10);
@@ -3244,23 +3377,33 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                rt2800_bbp_write(rt2x00dev, 81, 0x37);
        }
 
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_bbp_write(rt2x00dev, 74, 0x0b);
+               rt2800_bbp_write(rt2x00dev, 79, 0x18);
+               rt2800_bbp_write(rt2x00dev, 80, 0x09);
+               rt2800_bbp_write(rt2x00dev, 81, 0x33);
+       }
+
        rt2800_bbp_write(rt2x00dev, 82, 0x62);
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 83, 0x7a);
        else
                rt2800_bbp_write(rt2x00dev, 83, 0x6a);
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
                rt2800_bbp_write(rt2x00dev, 84, 0x19);
-       else if (rt2x00_rt(rt2x00dev, RT5390) ||
-                        rt2x00_rt(rt2x00dev, RT5392))
+       else if (rt2x00_rt(rt2x00dev, RT3290) ||
+                    rt2x00_rt(rt2x00dev, RT5390) ||
+                    rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 84, 0x9a);
        else
                rt2800_bbp_write(rt2x00dev, 84, 0x99);
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 86, 0x38);
        else
                rt2800_bbp_write(rt2x00dev, 86, 0x00);
@@ -3270,8 +3413,9 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp_write(rt2x00dev, 91, 0x04);
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 92, 0x02);
        else
                rt2800_bbp_write(rt2x00dev, 92, 0x00);
@@ -3285,6 +3429,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
            rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+           rt2x00_rt(rt2x00dev, RT3290) ||
            rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
            rt2x00_rt(rt2x00dev, RT5392) ||
@@ -3293,27 +3438,32 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        else
                rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 104, 0x92);
 
        if (rt2800_is_305x_soc(rt2x00dev))
                rt2800_bbp_write(rt2x00dev, 105, 0x01);
+       else if (rt2x00_rt(rt2x00dev, RT3290))
+               rt2800_bbp_write(rt2x00dev, 105, 0x1c);
        else if (rt2x00_rt(rt2x00dev, RT5390) ||
                         rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 105, 0x3c);
        else
                rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
-       if (rt2x00_rt(rt2x00dev, RT5390))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390))
                rt2800_bbp_write(rt2x00dev, 106, 0x03);
        else if (rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 106, 0x12);
        else
                rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392))
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392))
                rt2800_bbp_write(rt2x00dev, 128, 0x12);
 
        if (rt2x00_rt(rt2x00dev, RT5392)) {
@@ -3338,6 +3488,29 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                rt2800_bbp_write(rt2x00dev, 138, value);
        }
 
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_bbp_write(rt2x00dev, 67, 0x24);
+               rt2800_bbp_write(rt2x00dev, 143, 0x04);
+               rt2800_bbp_write(rt2x00dev, 142, 0x99);
+               rt2800_bbp_write(rt2x00dev, 150, 0x30);
+               rt2800_bbp_write(rt2x00dev, 151, 0x2e);
+               rt2800_bbp_write(rt2x00dev, 152, 0x20);
+               rt2800_bbp_write(rt2x00dev, 153, 0x34);
+               rt2800_bbp_write(rt2x00dev, 154, 0x40);
+               rt2800_bbp_write(rt2x00dev, 155, 0x3b);
+               rt2800_bbp_write(rt2x00dev, 253, 0x04);
+
+               rt2800_bbp_read(rt2x00dev, 47, &value);
+               rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1);
+               rt2800_bbp_write(rt2x00dev, 47, value);
+
+               /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */
+               rt2800_bbp_read(rt2x00dev, 3, &value);
+               rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1);
+               rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1);
+               rt2800_bbp_write(rt2x00dev, 3, value);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT5390) ||
                rt2x00_rt(rt2x00dev, RT5392)) {
                int ant, div_mode;
@@ -3470,6 +3643,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00_rt(rt2x00dev, RT3070) &&
            !rt2x00_rt(rt2x00dev, RT3071) &&
            !rt2x00_rt(rt2x00dev, RT3090) &&
+           !rt2x00_rt(rt2x00dev, RT3290) &&
            !rt2x00_rt(rt2x00dev, RT3390) &&
            !rt2x00_rt(rt2x00dev, RT3572) &&
            !rt2x00_rt(rt2x00dev, RT5390) &&
@@ -3480,8 +3654,9 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        /*
         * Init RF calibration.
         */
-       if (rt2x00_rt(rt2x00dev, RT5390) ||
-               rt2x00_rt(rt2x00dev, RT5392)) {
+       if (rt2x00_rt(rt2x00dev, RT3290) ||
+           rt2x00_rt(rt2x00dev, RT5390) ||
+           rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
                rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
                rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
@@ -3519,6 +3694,53 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
                rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
                rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+       } else if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
+               rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+               rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+               rt2800_rfcsr_write(rt2x00dev, 4, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 6, 0xa0);
+               rt2800_rfcsr_write(rt2x00dev, 8, 0xf3);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x53);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0x4a);
+               rt2800_rfcsr_write(rt2x00dev, 12, 0x46);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0x9f);
+               rt2800_rfcsr_write(rt2x00dev, 18, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x83);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x09);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+               rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+               rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 34, 0x05);
+               rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+               rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+               rt2800_rfcsr_write(rt2x00dev, 39, 0x1b);
+               rt2800_rfcsr_write(rt2x00dev, 40, 0x0b);
+               rt2800_rfcsr_write(rt2x00dev, 41, 0xbb);
+               rt2800_rfcsr_write(rt2x00dev, 42, 0xd5);
+               rt2800_rfcsr_write(rt2x00dev, 43, 0x7b);
+               rt2800_rfcsr_write(rt2x00dev, 44, 0x0e);
+               rt2800_rfcsr_write(rt2x00dev, 45, 0xa2);
+               rt2800_rfcsr_write(rt2x00dev, 46, 0x73);
+               rt2800_rfcsr_write(rt2x00dev, 47, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+               rt2800_rfcsr_write(rt2x00dev, 49, 0x98);
+               rt2800_rfcsr_write(rt2x00dev, 52, 0x38);
+               rt2800_rfcsr_write(rt2x00dev, 53, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 54, 0x78);
+               rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+               rt2800_rfcsr_write(rt2x00dev, 56, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
+               rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
+               rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
+               rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+               rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
        } else if (rt2x00_rt(rt2x00dev, RT3390)) {
                rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
                rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
@@ -3927,6 +4149,12 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
        }
 
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3);
+               rt2800_rfcsr_write(rt2x00dev, 29, rfcsr);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT5390) ||
                rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
@@ -4033,9 +4261,14 @@ EXPORT_SYMBOL_GPL(rt2800_disable_radio);
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
+       u16 efuse_ctrl_reg;
 
-       rt2800_register_read(rt2x00dev, EFUSE_CTRL, &reg);
+       if (rt2x00_rt(rt2x00dev, RT3290))
+               efuse_ctrl_reg = EFUSE_CTRL_3290;
+       else
+               efuse_ctrl_reg = EFUSE_CTRL;
 
+       rt2800_register_read(rt2x00dev, efuse_ctrl_reg, &reg);
        return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT);
 }
 EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
@@ -4043,27 +4276,44 @@ EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
 static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
 {
        u32 reg;
-
+       u16 efuse_ctrl_reg;
+       u16 efuse_data0_reg;
+       u16 efuse_data1_reg;
+       u16 efuse_data2_reg;
+       u16 efuse_data3_reg;
+
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               efuse_ctrl_reg = EFUSE_CTRL_3290;
+               efuse_data0_reg = EFUSE_DATA0_3290;
+               efuse_data1_reg = EFUSE_DATA1_3290;
+               efuse_data2_reg = EFUSE_DATA2_3290;
+               efuse_data3_reg = EFUSE_DATA3_3290;
+       } else {
+               efuse_ctrl_reg = EFUSE_CTRL;
+               efuse_data0_reg = EFUSE_DATA0;
+               efuse_data1_reg = EFUSE_DATA1;
+               efuse_data2_reg = EFUSE_DATA2;
+               efuse_data3_reg = EFUSE_DATA3;
+       }
        mutex_lock(&rt2x00dev->csr_mutex);
 
-       rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, &reg);
+       rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, &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);
-       rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg);
+       rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg);
 
        /* Wait until the EEPROM has been loaded */
-       rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
-
+       rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, &reg);
        /* Apparently the data is read from end to start */
-       rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
+       rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, &reg);
        /* The returned value is in CPU order, but eeprom is le */
        *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
-       rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
+       rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, &reg);
        *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
-       rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
+       rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, &reg);
        *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg);
-       rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, &reg);
+       rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, &reg);
        *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg);
 
        mutex_unlock(&rt2x00dev->csr_mutex);
@@ -4225,9 +4475,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
         * RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field
         * RT53xx: defined in "EEPROM_CHIP_ID" field
         */
-       rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-       if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
-               rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
+       if (rt2x00_rt(rt2x00dev, RT3290))
+               rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
+       else
+               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+
+       if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT3290 ||
+           rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
+           rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
                rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
        else
                value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
@@ -4242,6 +4497,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RT3070:
        case RT3071:
        case RT3090:
+       case RT3290:
        case RT3390:
        case RT3572:
        case RT5390:
@@ -4262,10 +4518,13 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RF3021:
        case RF3022:
        case RF3052:
+       case RF3290:
        case RF3320:
+       case RF5360:
        case RF5370:
        case RF5372:
        case RF5390:
+       case RF5392:
                break;
        default:
                ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
@@ -4576,10 +4835,13 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                   rt2x00_rf(rt2x00dev, RF2020) ||
                   rt2x00_rf(rt2x00dev, RF3021) ||
                   rt2x00_rf(rt2x00dev, RF3022) ||
+                  rt2x00_rf(rt2x00dev, RF3290) ||
                   rt2x00_rf(rt2x00dev, RF3320) ||
+                  rt2x00_rf(rt2x00dev, RF5360) ||
                   rt2x00_rf(rt2x00dev, RF5370) ||
                   rt2x00_rf(rt2x00dev, RF5372) ||
-                  rt2x00_rf(rt2x00dev, RF5390)) {
+                  rt2x00_rf(rt2x00dev, RF5390) ||
+                  rt2x00_rf(rt2x00dev, RF5392)) {
                spec->num_channels = 14;
                spec->channels = rf_vals_3x;
        } else if (rt2x00_rf(rt2x00dev, RF3052)) {
@@ -4662,9 +4924,12 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        case RF3022:
        case RF3320:
        case RF3052:
+       case RF3290:
+       case RF5360:
        case RF5370:
        case RF5372:
        case RF5390:
+       case RF5392:
                __set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags);
                break;
        }
index cad25bfebd7a4f900917057b69257f5ed8f0c5ce..dd436125fe3d3a175e18f3dffc5f73d0ba49f1a0 100644 (file)
@@ -280,7 +280,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
  */
 static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
 {
-       return FIRMWARE_RT2860;
+       /*
+        * Chip rt3290 use specific 4KB firmware named rt3290.bin.
+        */
+       if (rt2x00_rt(rt2x00dev, RT3290))
+               return FIRMWARE_RT3290;
+       else
+               return FIRMWARE_RT2860;
 }
 
 static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
@@ -974,6 +980,66 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        return rt2800_validate_eeprom(rt2x00dev);
 }
 
+static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       int i, count;
+
+       rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+       if ((rt2x00_get_field32(reg, WLAN_EN) == 1))
+               return 0;
+
+       rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
+       rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
+       rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
+       rt2x00_set_field32(&reg, WLAN_EN, 1);
+       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+
+       udelay(REGISTER_BUSY_DELAY);
+
+       count = 0;
+       do {
+               /*
+                * Check PLL_LD & XTAL_RDY.
+                */
+               for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+                       rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+                       if ((rt2x00_get_field32(reg, PLL_LD) == 1) &&
+                               (rt2x00_get_field32(reg, XTAL_RDY) == 1))
+                                       break;
+                       udelay(REGISTER_BUSY_DELAY);
+               }
+
+               if (i >= REGISTER_BUSY_COUNT) {
+
+                       if (count >= 10)
+                               return -EIO;
+
+                       rt2800_register_write(rt2x00dev, 0x58, 0x018);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x418);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x618);
+                       udelay(REGISTER_BUSY_DELAY);
+                       count++;
+               } else {
+                       count = 0;
+               }
+
+               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+               rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
+               rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
+               rt2x00_set_field32(&reg, WLAN_RESET, 1);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2x00_set_field32(&reg, WLAN_RESET, 0);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
+       } while (count != 0);
+
+       return 0;
+}
 static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
        int retval;
@@ -996,6 +1062,17 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        if (retval)
                return retval;
 
+       /*
+        * In probe phase call rt2800_enable_wlan_rt3290 to enable wlan
+        * clk for rt3290. That avoid the MCU fail in start phase.
+        */
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               retval = rt2800_enable_wlan_rt3290(rt2x00dev);
+
+               if (retval)
+                       return retval;
+       }
+
        /*
         * This device has multiple filters for control frames
         * and has a separate filter for PS Poll frames.
@@ -1175,6 +1252,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1432, 0x7768) },
        { PCI_DEVICE(0x1462, 0x891a) },
        { PCI_DEVICE(0x1a3b, 0x1059) },
+#ifdef CONFIG_RT2800PCI_RT3290
+       { PCI_DEVICE(0x1814, 0x3290) },
+#endif
 #ifdef CONFIG_RT2800PCI_RT33XX
        { PCI_DEVICE(0x1814, 0x3390) },
 #endif
@@ -1188,6 +1268,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x3593) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT53XX
+       { PCI_DEVICE(0x1814, 0x5360) },
        { PCI_DEVICE(0x1814, 0x5362) },
        { PCI_DEVICE(0x1814, 0x5390) },
        { PCI_DEVICE(0x1814, 0x5392) },
index 70e050d904c853c81973942d9526cbc7dc41635d..ab22a087c50dba15cf67b3ff237f8915bc8e2996 100644 (file)
@@ -47,6 +47,7 @@
  * 8051 firmware image.
  */
 #define FIRMWARE_RT2860                        "rt2860.bin"
+#define FIRMWARE_RT3290                        "rt3290.bin"
 #define FIRMWARE_IMAGE_BASE            0x2000
 
 /*
index bf78317a6adbfccd5e179d5a2482718880e8bfdd..6cf336595e2544a5703612e5156af0559b5cc8ab 100644 (file)
@@ -971,6 +971,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0411, 0x015d) },
        { USB_DEVICE(0x0411, 0x016f) },
        { USB_DEVICE(0x0411, 0x01a2) },
+       { USB_DEVICE(0x0411, 0x01ee) },
        /* Corega */
        { USB_DEVICE(0x07aa, 0x002f) },
        { USB_DEVICE(0x07aa, 0x003c) },
@@ -1137,6 +1138,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
 #ifdef CONFIG_RT2800USB_RT33XX
        /* Belkin */
        { USB_DEVICE(0x050d, 0x945b) },
+       /* D-Link */
+       { USB_DEVICE(0x2001, 0x3c17) },
        /* Panasonic */
        { USB_DEVICE(0x083a, 0xb511) },
        /* Philips */
@@ -1237,7 +1240,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* D-Link */
        { USB_DEVICE(0x07d1, 0x3c0b) },
        { USB_DEVICE(0x07d1, 0x3c17) },
-       { USB_DEVICE(0x2001, 0x3c17) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1) },
        /* Gemtek */
index 8f754025b06ead9b9a2c9d5be62d5d19b871690f..8afb546c2b2d3b1741be167969e7c04dcefb0239 100644 (file)
@@ -187,6 +187,7 @@ struct rt2x00_chip {
 #define RT3070         0x3070
 #define RT3071         0x3071
 #define RT3090         0x3090  /* 2.4GHz PCIe */
+#define RT3290         0x3290
 #define RT3390         0x3390
 #define RT3572         0x3572
 #define RT3593         0x3593
index e5404e576251342f24a1410ba9c6104dae8919be..a6b88bd4a1a57d7f904c75faa62c95ea219be029 100644 (file)
@@ -1161,6 +1161,8 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
                    BIT(NL80211_IFTYPE_MESH_POINT) |
                    BIT(NL80211_IFTYPE_WDS);
 
+       rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
        /*
         * Initialize work.
         */
index dd24b2663b5e528e04a0814726ec0f06ceae6cf3..4ff26c2159bf4b25178fbb66a0cd9794651ac185 100644 (file)
@@ -506,9 +506,19 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
                return 0;
-       else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+
+       if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+               return -EOPNOTSUPP;
+
+       /*
+        * To support IBSS RSN, don't program group keys in IBSS, the
+        * hardware will then not attempt to decrypt the frames.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
                return -EOPNOTSUPP;
-       else if (key->keylen > 32)
+
+       if (key->keylen > 32)
                return -ENOSPC;
 
        memset(&crypto, 0, sizeof(crypto));
index 0a4653a92cab059f1dcfc18d6304c754df168fb6..a0c8caef3b0a8f3616a4dd4a71e6eebeb3b939ae 100644 (file)
@@ -256,6 +256,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
        struct ieee80211_hw *hw;
        struct rt2x00_dev *rt2x00dev;
        int retval;
+       u16 chip;
 
        retval = pci_enable_device(pci_dev);
        if (retval) {
@@ -305,6 +306,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
        if (retval)
                goto exit_free_device;
 
+       /*
+        * Because rt3290 chip use different efuse offset to read efuse data.
+        * So before read efuse it need to indicate it is the
+        * rt3290 or not.
+        */
+       pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip);
+       rt2x00dev->chip.rt = chip;
+
        retval = rt2x00lib_probe_dev(rt2x00dev);
        if (retval)
                goto exit_free_reg;
index 2bebcb71a1e946c122f26ceb293f306904256ac9..3b505395d869c7987544794572969a1abaa68d16 100644 (file)
@@ -47,6 +47,8 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
        { PCI_DEVICE(0x1799, 0x6001) },
        { PCI_DEVICE(0x1799, 0x6020) },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) },
+       { PCI_DEVICE(0x1186, 0x3301) },
+       { PCI_DEVICE(0x1432, 0x7106) },
        { }
 };
 
index 3d8cc4a0c86dfba898a23c2a7ef4625d3a3885b7..6a2d72beb00d2d552d07e8524d79c9ee837e81e0 100644 (file)
@@ -128,7 +128,7 @@ u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
        u32 us_config;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+       RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
                 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
                 ul_entry_idx, ul_key_id, ul_enc_alg,
                 ul_default_key, mac_addr);
@@ -342,7 +342,8 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
                        /* Remove from HW Security CAM */
                        memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
                        rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
-                       pr_info("&&&&&&&&&del entry %d\n", i);
+                       RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+                                "del CAM entry %d\n", i);
                }
        }
        return;
index 2062ea1d7c807118229a08fe182993d888194d44..36bffbc4519eaa4d8c2a639d68c36fa5ffbe3f0e 100644 (file)
@@ -1273,17 +1273,18 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
         *after reset, release previous pending packet,
         *and force the  tx idx to the first one
         */
-       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
        for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
                if (rtlpci->tx_ring[i].desc) {
                        struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
 
                        while (skb_queue_len(&ring->queue)) {
-                               struct rtl_tx_desc *entry =
-                                   &ring->desc[ring->idx];
-                               struct sk_buff *skb =
-                                   __skb_dequeue(&ring->queue);
+                               struct rtl_tx_desc *entry;
+                               struct sk_buff *skb;
 
+                               spin_lock_irqsave(&rtlpriv->locks.irq_th_lock,
+                                                 flags);
+                               entry = &ring->desc[ring->idx];
+                               skb = __skb_dequeue(&ring->queue);
                                pci_unmap_single(rtlpci->pdev,
                                                 rtlpriv->cfg->ops->
                                                         get_desc((u8 *)
@@ -1291,15 +1292,15 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
                                                         true,
                                                         HW_DESC_TXBUFF_ADDR),
                                                 skb->len, PCI_DMA_TODEVICE);
-                               kfree_skb(skb);
                                ring->idx = (ring->idx + 1) % ring->entries;
+                               spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+                                                 flags);
+                               kfree_skb(skb);
                        }
                        ring->idx = 0;
                }
        }
 
-       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
        return 0;
 }
 
index 8d7099bc472cc296b86338d4e8d338ff5c97f049..b917a2a3caf75c960c8d1dd5827d74fd4550c2a5 100644 (file)
@@ -1247,6 +1247,9 @@ static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
                /* Read HT 40 OFDM TX power */
                ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index];
                ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index];
+       } else {
+               ofdmpowerLevel[0] = 0;
+               ofdmpowerLevel[1] = 0;
        }
 }
 
index 730bcc91952948160a0b50976b90f75e7c6bcc11..ad4b4803482d307dcf4ac6f39f85839771645d23 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "../wifi.h"
 #include "../core.h"
-#include "../pci.h"
 #include "../base.h"
 #include "../pci.h"
 #include "reg.h"
index 1a72932e2213cc4a1714a5fa50c9756874e43d6b..be800119d0a355d5404122341def2dba8b21c647 100644 (file)
@@ -8,6 +8,7 @@ menuconfig WL_TI
 if WL_TI
 source "drivers/net/wireless/ti/wl1251/Kconfig"
 source "drivers/net/wireless/ti/wl12xx/Kconfig"
+source "drivers/net/wireless/ti/wl18xx/Kconfig"
 
 # keep last for automatic dependencies
 source "drivers/net/wireless/ti/wlcore/Kconfig"
index 0a565622d4a414b0d9f07527e8188444506f7c13..4d6823983c04e38e71a467deb15a098214e52daa 100644 (file)
@@ -2,3 +2,4 @@ obj-$(CONFIG_WLCORE)                    += wlcore/
 obj-$(CONFIG_WL12XX)                   += wl12xx/
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)     += wlcore/
 obj-$(CONFIG_WL1251)                   += wl1251/
+obj-$(CONFIG_WL18XX)                   += wl18xx/
index d14d69d733a07fc9bd9e77c4e2192e42ea8f83c9..6822b845efc15d5e2305bf468cf76c6bd83e1dce 100644 (file)
@@ -277,15 +277,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
        join->rx_config_options = wl->rx_config;
        join->rx_filter_options = wl->rx_filter;
 
-       /*
-        * 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 = 0;
-       join->rx_filter_options = WL1251_DEFAULT_RX_FILTER;
-
        join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
                RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
 
index d1afb8e3b2ef0a3673b5ff9ef60f98379180bfa3..3118c425bcf17dcbdf85f274a568e25a80cac9e2 100644 (file)
@@ -334,6 +334,12 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
        if (ret < 0)
                goto out;
 
+       /*
+        * Join command applies filters, and if we are not associated,
+        * BSSID filter must be disabled for association to work.
+        */
+       if (is_zero_ether_addr(wl->bssid))
+               wl->rx_config &= ~CFG_BSSID_FILTER_EN;
 
        ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval,
                              dtim_period);
@@ -348,33 +354,6 @@ out:
        return ret;
 }
 
-static void wl1251_filter_work(struct work_struct *work)
-{
-       struct wl1251 *wl =
-               container_of(work, struct wl1251, filter_work);
-       int ret;
-
-       mutex_lock(&wl->mutex);
-
-       if (wl->state == WL1251_STATE_OFF)
-               goto out;
-
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out;
-
-       ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int,
-                         wl->dtim_period);
-       if (ret < 0)
-               goto out_sleep;
-
-out_sleep:
-       wl1251_ps_elp_sleep(wl);
-
-out:
-       mutex_unlock(&wl->mutex);
-}
-
 static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1251 *wl = hw->priv;
@@ -478,7 +457,6 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
 
        cancel_work_sync(&wl->irq_work);
        cancel_work_sync(&wl->tx_work);
-       cancel_work_sync(&wl->filter_work);
        cancel_delayed_work_sync(&wl->elp_work);
 
        mutex_lock(&wl->mutex);
@@ -681,13 +659,15 @@ out:
                                  FIF_FCSFAIL | \
                                  FIF_BCN_PRBRESP_PROMISC | \
                                  FIF_CONTROL | \
-                                 FIF_OTHER_BSS)
+                                 FIF_OTHER_BSS | \
+                                 FIF_PROBE_REQ)
 
 static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
                                       unsigned int *total,u64 multicast)
 {
        struct wl1251 *wl = hw->priv;
+       int ret;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
 
@@ -698,7 +678,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                /* no filters which we support changed */
                return;
 
-       /* FIXME: wl->rx_config and wl->rx_filter are not protected */
+       mutex_lock(&wl->mutex);
 
        wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
        wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
@@ -721,15 +701,25 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        }
        if (*total & FIF_CONTROL)
                wl->rx_filter |= CFG_RX_CTL_EN;
-       if (*total & FIF_OTHER_BSS)
-               wl->rx_filter &= ~CFG_BSSID_FILTER_EN;
+       if (*total & FIF_OTHER_BSS || is_zero_ether_addr(wl->bssid))
+               wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+       if (*total & FIF_PROBE_REQ)
+               wl->rx_filter |= CFG_RX_PREQ_EN;
 
-       /*
-        * 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); */
+       if (wl->state == WL1251_STATE_OFF)
+               goto out;
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       /* send filters to firmware */
+       wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+
+       wl1251_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
 }
 
 /* HW encryption */
@@ -1390,7 +1380,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
        skb_queue_head_init(&wl->tx_queue);
 
-       INIT_WORK(&wl->filter_work, wl1251_filter_work);
        INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
        wl->scanning = false;
index 9d8f5816c6f91628d609ecd0090c438133c5b115..fd02060038de6479051accfa7b63c1993193315b 100644 (file)
@@ -315,7 +315,6 @@ struct wl1251 {
        bool tx_queue_stopped;
 
        struct work_struct tx_work;
-       struct work_struct filter_work;
 
        /* Pending TX frames */
        struct sk_buff *tx_frames[16];
index 87f64b14db3593b6ac27b0a69fc90388cd7228ff..da509aa7d0092ffb95d00936908873c4d6a4af58 100644 (file)
@@ -1,3 +1,3 @@
-wl12xx-objs    = main.o cmd.o acx.o
+wl12xx-objs    = main.o cmd.o acx.o debugfs.o
 
 obj-$(CONFIG_WL12XX)           += wl12xx.o
index d1f5aba0afced532e08de434e39e9ae00641bf3e..2a26868b837d93a131a68bb4a03e55d7e62a2f5a 100644 (file)
 #define __WL12XX_ACX_H__
 
 #include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+#define WL12XX_ACX_ALL_EVENTS_VECTOR   (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_INIT_COMPLETE | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_CMD_COMPLETE  | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
+
+#define WL12XX_INTR_MASK               (WL1271_ACX_INTR_WATCHDOG      | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA)
 
 struct wl1271_acx_host_config_bitmap {
        struct acx_header header;
@@ -31,6 +46,228 @@ struct wl1271_acx_host_config_bitmap {
        __le32 host_cfg_bitmap;
 } __packed;
 
+struct wl12xx_acx_tx_statistics {
+       __le32 internal_desc_overflow;
+}  __packed;
+
+struct wl12xx_acx_rx_statistics {
+       __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;
+} __packed;
+
+struct wl12xx_acx_dma_statistics {
+       __le32 rx_requested;
+       __le32 rx_errors;
+       __le32 tx_requested;
+       __le32 tx_errors;
+}  __packed;
+
+struct wl12xx_acx_isr_statistics {
+       /* host command complete */
+       __le32 cmd_cmplt;
+
+       /* fiqisr() */
+       __le32 fiqs;
+
+       /* (INT_STS_ND & INT_TRIG_RX_HEADER) */
+       __le32 rx_headers;
+
+       /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
+       __le32 rx_completes;
+
+       /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
+       __le32 rx_mem_overflow;
+
+       /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
+       __le32 rx_rdys;
+
+       /* irqisr() */
+       __le32 irqs;
+
+       /* (INT_STS_ND & INT_TRIG_TX_PROC) */
+       __le32 tx_procs;
+
+       /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
+       __le32 decrypt_done;
+
+       /* (INT_STS_ND & INT_TRIG_DMA0) */
+       __le32 dma0_done;
+
+       /* (INT_STS_ND & INT_TRIG_DMA1) */
+       __le32 dma1_done;
+
+       /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
+       __le32 tx_exch_complete;
+
+       /* (INT_STS_ND & INT_TRIG_COMMAND) */
+       __le32 commands;
+
+       /* (INT_STS_ND & INT_TRIG_RX_PROC) */
+       __le32 rx_procs;
+
+       /* (INT_STS_ND & INT_TRIG_PM_802) */
+       __le32 hw_pm_mode_changes;
+
+       /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
+       __le32 host_acknowledges;
+
+       /* (INT_STS_ND & INT_TRIG_PM_PCI) */
+       __le32 pci_pm;
+
+       /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
+       __le32 wakeups;
+
+       /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
+       __le32 low_rssi;
+} __packed;
+
+struct wl12xx_acx_wep_statistics {
+       /* WEP address keys configured */
+       __le32 addr_key_count;
+
+       /* default keys configured */
+       __le32 default_key_count;
+
+       __le32 reserved;
+
+       /* number of times that WEP key not found on lookup */
+       __le32 key_not_found;
+
+       /* number of times that WEP key decryption failed */
+       __le32 decrypt_fail;
+
+       /* WEP packets decrypted */
+       __le32 packets;
+
+       /* WEP decrypt interrupts */
+       __le32 interrupt;
+} __packed;
+
+#define ACX_MISSED_BEACONS_SPREAD 10
+
+struct wl12xx_acx_pwr_statistics {
+       /* the amount of enters into power save mode (both PD & ELP) */
+       __le32 ps_enter;
+
+       /* the amount of enters into ELP mode */
+       __le32 elp_enter;
+
+       /* the amount of missing beacon interrupts to the host */
+       __le32 missing_bcns;
+
+       /* the amount of wake on host-access times */
+       __le32 wake_on_host;
+
+       /* the amount of wake on timer-expire */
+       __le32 wake_on_timer_exp;
+
+       /* the number of packets that were transmitted with PS bit set */
+       __le32 tx_with_ps;
+
+       /* the number of packets that were transmitted with PS bit clear */
+       __le32 tx_without_ps;
+
+       /* the number of received beacons */
+       __le32 rcvd_beacons;
+
+       /* the number of entering into PowerOn (power save off) */
+       __le32 power_save_off;
+
+       /* the number of entries into power save mode */
+       __le16 enable_ps;
+
+       /*
+        * the number of exits from power save, not including failed PS
+        * transitions
+        */
+       __le16 disable_ps;
+
+       /*
+        * the number of times the TSF counter was adjusted because
+        * of drift
+        */
+       __le32 fix_tsf_ps;
+
+       /* Gives statistics about the spread continuous missed beacons.
+        * The 16 LSB are dedicated for the PS mode.
+        * The 16 MSB are dedicated for the PS mode.
+        * cont_miss_bcns_spread[0] - single missed beacon.
+        * cont_miss_bcns_spread[1] - two continuous missed beacons.
+        * cont_miss_bcns_spread[2] - three continuous missed beacons.
+        * ...
+        * cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
+       */
+       __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
+
+       /* the number of beacons in awake mode */
+       __le32 rcvd_awake_beacons;
+} __packed;
+
+struct wl12xx_acx_mic_statistics {
+       __le32 rx_pkts;
+       __le32 calc_failure;
+} __packed;
+
+struct wl12xx_acx_aes_statistics {
+       __le32 encrypt_fail;
+       __le32 decrypt_fail;
+       __le32 encrypt_packets;
+       __le32 decrypt_packets;
+       __le32 encrypt_interrupt;
+       __le32 decrypt_interrupt;
+} __packed;
+
+struct wl12xx_acx_event_statistics {
+       __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;
+} __packed;
+
+struct wl12xx_acx_ps_statistics {
+       __le32 pspoll_timeouts;
+       __le32 upsd_timeouts;
+       __le32 upsd_max_sptime;
+       __le32 upsd_max_apturn;
+       __le32 pspoll_max_apturn;
+       __le32 pspoll_utilization;
+       __le32 upsd_utilization;
+} __packed;
+
+struct wl12xx_acx_rxpipe_statistics {
+       __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;
+} __packed;
+
+struct wl12xx_acx_statistics {
+       struct acx_header header;
+
+       struct wl12xx_acx_tx_statistics tx;
+       struct wl12xx_acx_rx_statistics rx;
+       struct wl12xx_acx_dma_statistics dma;
+       struct wl12xx_acx_isr_statistics isr;
+       struct wl12xx_acx_wep_statistics wep;
+       struct wl12xx_acx_pwr_statistics pwr;
+       struct wl12xx_acx_aes_statistics aes;
+       struct wl12xx_acx_mic_statistics mic;
+       struct wl12xx_acx_event_statistics event;
+       struct wl12xx_acx_ps_statistics ps;
+       struct wl12xx_acx_rxpipe_statistics rxpipe;
+} __packed;
+
 int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
 
 #endif /* __WL12XX_ACX_H__ */
index 8ffaeb5f2147e9e77d1ad584729560d4e9060d83..30be784a40d8c128238befa09aba0c055a3378a9 100644 (file)
@@ -65,6 +65,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
        struct wl1271_general_parms_cmd *gen_parms;
        struct wl1271_ini_general_params *gp =
                &((struct wl1271_nvs_file *)wl->nvs)->general_params;
+       struct wl12xx_priv *priv = wl->priv;
        bool answer = false;
        int ret;
 
@@ -88,7 +89,7 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
                answer = true;
 
        /* Override the REF CLK from the NVS with the one from platform data */
-       gen_parms->general_params.ref_clock = wl->ref_clock;
+       gen_parms->general_params.ref_clock = priv->ref_clock;
 
        ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
        if (ret < 0) {
@@ -118,6 +119,7 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
        struct wl128x_general_parms_cmd *gen_parms;
        struct wl128x_ini_general_params *gp =
                &((struct wl128x_nvs_file *)wl->nvs)->general_params;
+       struct wl12xx_priv *priv = wl->priv;
        bool answer = false;
        int ret;
 
@@ -141,8 +143,8 @@ int wl128x_cmd_general_parms(struct wl1271 *wl)
                answer = true;
 
        /* Replace REF and TCXO CLKs with the ones from platform data */
-       gen_parms->general_params.ref_clock = wl->ref_clock;
-       gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
+       gen_parms->general_params.ref_clock = priv->ref_clock;
+       gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock;
 
        ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
        if (ret < 0) {
@@ -172,7 +174,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
        struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
        struct wl1271_radio_parms_cmd *radio_parms;
        struct wl1271_ini_general_params *gp = &nvs->general_params;
-       int ret;
+       int ret, fem_idx;
 
        if (!wl->nvs)
                return -ENODEV;
@@ -183,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
 
        radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
+       fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
+
        /* 2.4GHz parameters */
        memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
               sizeof(struct wl1271_ini_band_params_2));
        memcpy(&radio_parms->dyn_params_2,
-              &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+              &nvs->dyn_radio_params_2[fem_idx].params,
               sizeof(struct wl1271_ini_fem_params_2));
 
        /* 5GHz parameters */
@@ -195,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
               &nvs->stat_radio_params_5,
               sizeof(struct wl1271_ini_band_params_5));
        memcpy(&radio_parms->dyn_params_5,
-              &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+              &nvs->dyn_radio_params_5[fem_idx].params,
               sizeof(struct wl1271_ini_fem_params_5));
 
        wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
@@ -214,7 +218,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
        struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
        struct wl128x_radio_parms_cmd *radio_parms;
        struct wl128x_ini_general_params *gp = &nvs->general_params;
-       int ret;
+       int ret, fem_idx;
 
        if (!wl->nvs)
                return -ENODEV;
@@ -225,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
 
        radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
 
+       fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer);
+
        /* 2.4GHz parameters */
        memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
               sizeof(struct wl128x_ini_band_params_2));
        memcpy(&radio_parms->dyn_params_2,
-              &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+              &nvs->dyn_radio_params_2[fem_idx].params,
               sizeof(struct wl128x_ini_fem_params_2));
 
        /* 5GHz parameters */
@@ -237,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl)
               &nvs->stat_radio_params_5,
               sizeof(struct wl128x_ini_band_params_5));
        memcpy(&radio_parms->dyn_params_5,
-              &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+              &nvs->dyn_radio_params_5[fem_idx].params,
               sizeof(struct wl128x_ini_fem_params_5));
 
        radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.c b/drivers/net/wireless/ti/wl12xx/debugfs.c
new file mode 100644 (file)
index 0000000..0521cbf
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * 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
+ *
+ */
+
+#include "../wlcore/debugfs.h"
+#include "../wlcore/wlcore.h"
+
+#include "wl12xx.h"
+#include "acx.h"
+#include "debugfs.h"
+
+#define WL12XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
+       DEBUGFS_FWSTATS_FILE(a, b, c, wl12xx_acx_statistics)
+
+WL12XX_DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
+/* skipping wep.reserved */
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
+/* skipping cont_miss_bcns_spread for now */
+WL12XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
+
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data,
+                           "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
+WL12XX_DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
+
+int wl12xx_debugfs_add_files(struct wl1271 *wl,
+                            struct dentry *rootdir)
+{
+       int ret = 0;
+       struct dentry *entry, *stats, *moddir;
+
+       moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
+       if (!moddir || IS_ERR(moddir)) {
+               entry = moddir;
+               goto err;
+       }
+
+       stats = debugfs_create_dir("fw_stats", moddir);
+       if (!stats || IS_ERR(stats)) {
+               entry = stats;
+               goto err;
+       }
+
+       DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
+
+       DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
+       DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
+       DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
+       DEBUGFS_FWSTATS_ADD(rx, dropped);
+       DEBUGFS_FWSTATS_ADD(rx, fcs_err);
+       DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
+       DEBUGFS_FWSTATS_ADD(rx, path_reset);
+       DEBUGFS_FWSTATS_ADD(rx, reset_counter);
+
+       DEBUGFS_FWSTATS_ADD(dma, rx_requested);
+       DEBUGFS_FWSTATS_ADD(dma, rx_errors);
+       DEBUGFS_FWSTATS_ADD(dma, tx_requested);
+       DEBUGFS_FWSTATS_ADD(dma, tx_errors);
+
+       DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
+       DEBUGFS_FWSTATS_ADD(isr, fiqs);
+       DEBUGFS_FWSTATS_ADD(isr, rx_headers);
+       DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
+       DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
+       DEBUGFS_FWSTATS_ADD(isr, irqs);
+       DEBUGFS_FWSTATS_ADD(isr, tx_procs);
+       DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
+       DEBUGFS_FWSTATS_ADD(isr, dma0_done);
+       DEBUGFS_FWSTATS_ADD(isr, dma1_done);
+       DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
+       DEBUGFS_FWSTATS_ADD(isr, commands);
+       DEBUGFS_FWSTATS_ADD(isr, rx_procs);
+       DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
+       DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
+       DEBUGFS_FWSTATS_ADD(isr, pci_pm);
+       DEBUGFS_FWSTATS_ADD(isr, wakeups);
+       DEBUGFS_FWSTATS_ADD(isr, low_rssi);
+
+       DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
+       DEBUGFS_FWSTATS_ADD(wep, default_key_count);
+       /* skipping wep.reserved */
+       DEBUGFS_FWSTATS_ADD(wep, key_not_found);
+       DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
+       DEBUGFS_FWSTATS_ADD(wep, packets);
+       DEBUGFS_FWSTATS_ADD(wep, interrupt);
+
+       DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
+       DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
+       DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
+       DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
+       DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
+       DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
+       DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
+       DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
+       DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
+       DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
+       DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
+       DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
+       /* skipping cont_miss_bcns_spread for now */
+       DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
+
+       DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
+       DEBUGFS_FWSTATS_ADD(mic, calc_failure);
+
+       DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
+       DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
+       DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
+       DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
+       DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
+       DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
+
+       DEBUGFS_FWSTATS_ADD(event, heart_beat);
+       DEBUGFS_FWSTATS_ADD(event, calibration);
+       DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
+       DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
+       DEBUGFS_FWSTATS_ADD(event, rx_pool);
+       DEBUGFS_FWSTATS_ADD(event, oom_late);
+       DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
+       DEBUGFS_FWSTATS_ADD(event, tx_stuck);
+
+       DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
+       DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
+       DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
+       DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
+       DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
+       DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
+       DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
+
+       DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
+       DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
+       DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
+       DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
+       DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+
+       return 0;
+
+err:
+       if (IS_ERR(entry))
+               ret = PTR_ERR(entry);
+       else
+               ret = -ENOMEM;
+
+       return ret;
+}
diff --git a/drivers/net/wireless/ti/wl12xx/debugfs.h b/drivers/net/wireless/ti/wl12xx/debugfs.h
new file mode 100644 (file)
index 0000000..96898e2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl12xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 __WL12XX_DEBUGFS_H__
+#define __WL12XX_DEBUGFS_H__
+
+int wl12xx_debugfs_add_files(struct wl1271 *wl,
+                            struct dentry *rootdir);
+
+#endif /* __WL12XX_DEBUGFS_H__ */
index d7dd3def07b59b34fd59b8afb4eba1a686940651..47ba2e0017f48ec7c6771508108e43319335a305 100644 (file)
 #include "reg.h"
 #include "cmd.h"
 #include "acx.h"
+#include "debugfs.h"
+
+static char *fref_param;
+static char *tcxo_param;
 
 static struct wlcore_conf wl12xx_conf = {
        .sg = {
@@ -212,7 +216,7 @@ static struct wlcore_conf wl12xx_conf = {
                .suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
                .suspend_listen_interval     = 3,
                .bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
-               .bcn_filt_ie_count           = 2,
+               .bcn_filt_ie_count           = 3,
                .bcn_filt_ie = {
                        [0] = {
                                .ie          = WLAN_EID_CHANNEL_SWITCH,
@@ -222,9 +226,13 @@ static struct wlcore_conf wl12xx_conf = {
                                .ie          = WLAN_EID_HT_OPERATION,
                                .rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
                        },
+                       [2] = {
+                               .ie          = WLAN_EID_ERP_INFO,
+                               .rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
+                       },
                },
-               .synch_fail_thold            = 10,
-               .bss_lose_timeout            = 100,
+               .synch_fail_thold            = 12,
+               .bss_lose_timeout            = 400,
                .beacon_rx_timeout           = 10000,
                .broadcast_timeout           = 20000,
                .rx_broadcast_in_ps          = 1,
@@ -234,10 +242,11 @@ static struct wlcore_conf wl12xx_conf = {
                .psm_entry_retries           = 8,
                .psm_exit_retries            = 16,
                .psm_entry_nullfunc_retries  = 3,
-               .dynamic_ps_timeout          = 40,
+               .dynamic_ps_timeout          = 200,
                .forced_ps                   = false,
                .keep_alive_interval         = 55000,
                .max_listen_interval         = 20,
+               .sta_sleep_auth              = WL1271_PSM_ILLEGAL,
        },
        .itrim = {
                .enable = false,
@@ -245,7 +254,7 @@ static struct wlcore_conf wl12xx_conf = {
        },
        .pm_config = {
                .host_clk_settling_time = 5000,
-               .host_fast_wakeup_support = false
+               .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
        },
        .roam_trigger = {
                .trigger_pacing               = 1,
@@ -305,8 +314,8 @@ static struct wlcore_conf wl12xx_conf = {
                .swallow_period               = 5,
                .n_divider_fref_set_1         = 0xff,       /* default */
                .n_divider_fref_set_2         = 12,
-               .m_divider_fref_set_1         = 148,
-               .m_divider_fref_set_2         = 0xffff,     /* default */
+               .m_divider_fref_set_1         = 0xffff,
+               .m_divider_fref_set_2         = 148,        /* default */
                .coex_pll_stabilization_time  = 0xffffffff, /* default */
                .ldo_stabilization_time       = 0xffff,     /* default */
                .fm_disturbed_band_margin     = 0xff,       /* default */
@@ -589,11 +598,13 @@ static const int wl12xx_rtable[REG_TABLE_LEN] = {
 #define WL128X_FW_NAME_SINGLE  "ti-connectivity/wl128x-fw-4-sr.bin"
 #define WL128X_PLT_FW_NAME     "ti-connectivity/wl128x-fw-4-plt.bin"
 
-static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
+static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
 {
+       int ret;
+
        if (wl->chip.id != CHIP_ID_1283_PG20) {
                struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
-               struct wl1271_rx_mem_pool_addr rx_mem_addr;
+               struct wl127x_rx_mem_pool_addr rx_mem_addr;
 
                /*
                 * Choose the block we want to read
@@ -607,9 +618,13 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
 
                rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
 
-               wl1271_write(wl, WL1271_SLV_REG_DATA,
-                            &rx_mem_addr, sizeof(rx_mem_addr), false);
+               ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr,
+                                  sizeof(rx_mem_addr), false);
+               if (ret < 0)
+                       return ret;
        }
+
+       return 0;
 }
 
 static int wl12xx_identify_chip(struct wl1271 *wl)
@@ -621,10 +636,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
                               wl->chip.id);
 
-               /* clear the alignment quirk, since we don't support it */
-               wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-               wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
+               wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
+                             WLCORE_QUIRK_TKIP_HEADER_SPACE;
                wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
                wl->mr_fw_name = WL127X_FW_NAME_MULTI;
                memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
@@ -639,10 +652,8 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
                             wl->chip.id);
 
-               /* clear the alignment quirk, since we don't support it */
-               wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-               wl->quirks |= WLCORE_QUIRK_LEGACY_NVS;
+               wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
+                             WLCORE_QUIRK_TKIP_HEADER_SPACE;
                wl->plt_fw_name = WL127X_PLT_FW_NAME;
                wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
                wl->mr_fw_name = WL127X_FW_NAME_MULTI;
@@ -660,6 +671,11 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
                wl->plt_fw_name = WL128X_PLT_FW_NAME;
                wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
                wl->mr_fw_name = WL128X_FW_NAME_MULTI;
+
+               /* wl128x requires TX blocksize alignment */
+               wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
+                             WLCORE_QUIRK_TKIP_HEADER_SPACE;
+
                break;
        case CHIP_ID_1283_PG10:
        default:
@@ -672,64 +688,95 @@ out:
        return ret;
 }
 
-static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
+static int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr,
+                                            u16 val)
 {
+       int ret;
+
        /* write address >> 1 + 0x30000 to OCP_POR_CTR */
        addr = (addr >> 1) + 0x30000;
-       wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
+       ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
+       if (ret < 0)
+               goto out;
 
        /* write value to OCP_POR_WDATA */
-       wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val);
+       ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val);
+       if (ret < 0)
+               goto out;
 
        /* write 1 to OCP_CMD */
-       wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
+       ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
+       if (ret < 0)
+               goto out;
+
+out:
+       return ret;
 }
 
-static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr)
+static int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr,
+                                           u16 *out)
 {
        u32 val;
        int timeout = OCP_CMD_LOOP;
+       int ret;
 
        /* write address >> 1 + 0x30000 to OCP_POR_CTR */
        addr = (addr >> 1) + 0x30000;
-       wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
+       ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
+       if (ret < 0)
+               return ret;
 
        /* write 2 to OCP_CMD */
-       wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
+       ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
+       if (ret < 0)
+               return ret;
 
        /* poll for data ready */
        do {
-               val = wl1271_read32(wl, WL12XX_OCP_DATA_READ);
+               ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val);
+               if (ret < 0)
+                       return ret;
        } while (!(val & OCP_READY_MASK) && --timeout);
 
        if (!timeout) {
                wl1271_warning("Top register access timed out.");
-               return 0xffff;
+               return -ETIMEDOUT;
        }
 
        /* check data status and return if OK */
-       if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
-               return val & 0xffff;
-       else {
+       if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) {
                wl1271_warning("Top register access returned error.");
-               return 0xffff;
+               return -EIO;
        }
+
+       if (out)
+               *out = val & 0xffff;
+
+       return 0;
 }
 
 static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
 {
        u16 spare_reg;
+       int ret;
 
        /* Mask bits [2] & [8:4] in the sys_clk_cfg register */
-       spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
+       ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
+       if (ret < 0)
+               return ret;
+
        if (spare_reg == 0xFFFF)
                return -EFAULT;
        spare_reg |= (BIT(3) | BIT(5) | BIT(6));
-       wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+       ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+       if (ret < 0)
+               return ret;
 
        /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
-       wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
-                            WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
+       ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
+                                  WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
+       if (ret < 0)
+               return ret;
 
        /* Delay execution for 15msec, to let the HW settle */
        mdelay(15);
@@ -740,8 +787,12 @@ static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
 static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
 {
        u16 tcxo_detection;
+       int ret;
+
+       ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection);
+       if (ret < 0)
+               return false;
 
-       tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG);
        if (tcxo_detection & TCXO_DET_FAILED)
                return false;
 
@@ -751,8 +802,12 @@ static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
 static bool wl128x_is_fref_valid(struct wl1271 *wl)
 {
        u16 fref_detection;
+       int ret;
+
+       ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection);
+       if (ret < 0)
+               return false;
 
-       fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG);
        if (fref_detection & FREF_CLK_DETECT_FAIL)
                return false;
 
@@ -761,11 +816,21 @@ static bool wl128x_is_fref_valid(struct wl1271 *wl)
 
 static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
 {
-       wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
-       wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
-       wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
+       int ret;
 
-       return 0;
+       ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
+       if (ret < 0)
+               goto out;
+
+       ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
+       if (ret < 0)
+               goto out;
+
+       ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG,
+                                  MCS_PLL_CONFIG_REG_VAL);
+
+out:
+       return ret;
 }
 
 static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
@@ -773,30 +838,40 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
        u16 spare_reg;
        u16 pll_config;
        u8 input_freq;
+       struct wl12xx_priv *priv = wl->priv;
+       int ret;
 
        /* Mask bits [3:1] in the sys_clk_cfg register */
-       spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
+       ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
+       if (ret < 0)
+               return ret;
+
        if (spare_reg == 0xFFFF)
                return -EFAULT;
        spare_reg |= BIT(2);
-       wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+       ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+       if (ret < 0)
+               return ret;
 
        /* Handle special cases of the TCXO clock */
-       if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
-           wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
+       if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
+           priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
                return wl128x_manually_configure_mcs_pll(wl);
 
        /* Set the input frequency according to the selected clock source */
        input_freq = (clk & 1) + 1;
 
-       pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG);
+       ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config);
+       if (ret < 0)
+               return ret;
+
        if (pll_config == 0xFFFF)
                return -EFAULT;
        pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
        pll_config |= MCS_PLL_ENABLE_HP;
-       wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
+       ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -808,26 +883,31 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
  */
 static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
 {
+       struct wl12xx_priv *priv = wl->priv;
        u16 sys_clk_cfg;
+       int ret;
 
        /* For XTAL-only modes, FREF will be used after switching from TCXO */
-       if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
-           wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
+       if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
+           priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
                if (!wl128x_switch_tcxo_to_fref(wl))
                        return -EINVAL;
                goto fref_clk;
        }
 
        /* Query the HW, to determine which clock source we should use */
-       sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG);
+       ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg);
+       if (ret < 0)
+               return ret;
+
        if (sys_clk_cfg == 0xFFFF)
                return -EINVAL;
        if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
                goto fref_clk;
 
        /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
-       if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
-           wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
+       if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
+           priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
                if (!wl128x_switch_tcxo_to_fref(wl))
                        return -EINVAL;
                goto fref_clk;
@@ -836,14 +916,14 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
        /* TCXO clock is selected */
        if (!wl128x_is_tcxo_valid(wl))
                return -EINVAL;
-       *selected_clock = wl->tcxo_clock;
+       *selected_clock = priv->tcxo_clock;
        goto config_mcs_pll;
 
 fref_clk:
        /* FREF clock is selected */
        if (!wl128x_is_fref_valid(wl))
                return -EINVAL;
-       *selected_clock = wl->ref_clock;
+       *selected_clock = priv->ref_clock;
 
 config_mcs_pll:
        return wl128x_configure_mcs_pll(wl, *selected_clock);
@@ -851,69 +931,98 @@ config_mcs_pll:
 
 static int wl127x_boot_clk(struct wl1271 *wl)
 {
+       struct wl12xx_priv *priv = wl->priv;
        u32 pause;
        u32 clk;
+       int ret;
 
        if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
                wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
 
-       if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
-           wl->ref_clock == CONF_REF_CLK_38_4_E ||
-           wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
+       if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
+           priv->ref_clock == CONF_REF_CLK_38_4_E ||
+           priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
                /* ref clk: 19.2/38.4/38.4-XTAL */
                clk = 0x3;
-       else if (wl->ref_clock == CONF_REF_CLK_26_E ||
-                wl->ref_clock == CONF_REF_CLK_52_E)
+       else if (priv->ref_clock == CONF_REF_CLK_26_E ||
+                priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
+                priv->ref_clock == CONF_REF_CLK_52_E)
                /* ref clk: 26/52 */
                clk = 0x5;
        else
                return -EINVAL;
 
-       if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
+       if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
                u16 val;
                /* Set clock type (open drain) */
-               val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE);
+               ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val);
+               if (ret < 0)
+                       goto out;
+
                val &= FREF_CLK_TYPE_BITS;
-               wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+               ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+               if (ret < 0)
+                       goto out;
 
                /* Set clock pull mode (no pull) */
-               val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL);
+               ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val);
+               if (ret < 0)
+                       goto out;
+
                val |= NO_PULL;
-               wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
+               ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
+               if (ret < 0)
+                       goto out;
        } else {
                u16 val;
                /* Set clock polarity */
-               val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY);
+               ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val);
+               if (ret < 0)
+                       goto out;
+
                val &= FREF_CLK_POLARITY_BITS;
                val |= CLK_REQ_OUTN_SEL;
-               wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
+               ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
+               if (ret < 0)
+                       goto out;
        }
 
-       wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk);
+       ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk);
+       if (ret < 0)
+               goto out;
 
-       pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS);
+       ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause);
+       if (ret < 0)
+               goto out;
 
        wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
 
        pause &= ~(WU_COUNTER_PAUSE_VAL);
        pause |= WU_COUNTER_PAUSE_VAL;
-       wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause);
+       ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause);
 
-       return 0;
+out:
+       return ret;
 }
 
 static int wl1271_boot_soft_reset(struct wl1271 *wl)
 {
        unsigned long timeout;
        u32 boot_data;
+       int ret = 0;
 
        /* perform soft reset */
-       wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+       ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+       if (ret < 0)
+               goto out;
 
        /* SOFT_RESET is self clearing */
        timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
        while (1) {
-               boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET);
+               ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data);
+               if (ret < 0)
+                       goto out;
+
                wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
                if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
                        break;
@@ -929,16 +1038,20 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
        }
 
        /* disable Rx/Tx */
-       wl1271_write32(wl, WL12XX_ENABLE, 0x0);
+       ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0);
+       if (ret < 0)
+               goto out;
 
        /* disable auto calibration on start*/
-       wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff);
+       ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff);
 
-       return 0;
+out:
+       return ret;
 }
 
 static int wl12xx_pre_boot(struct wl1271 *wl)
 {
+       struct wl12xx_priv *priv = wl->priv;
        int ret = 0;
        u32 clk;
        int selected_clock = -1;
@@ -954,30 +1067,43 @@ static int wl12xx_pre_boot(struct wl1271 *wl)
        }
 
        /* Continue the ELP wake up sequence */
-       wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+       ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+       if (ret < 0)
+               goto out;
+
        udelay(500);
 
-       wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
+       if (ret < 0)
+               goto out;
 
        /* 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 */
 
-       clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START);
+       ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk);
+       if (ret < 0)
+               goto out;
 
        wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
 
        if (wl->chip.id == CHIP_ID_1283_PG20)
                clk |= ((selected_clock & 0x3) << 1) << 4;
        else
-               clk |= (wl->ref_clock << 1) << 4;
+               clk |= (priv->ref_clock << 1) << 4;
 
-       wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
+       ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
+       if (ret < 0)
+               goto out;
 
-       wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+       if (ret < 0)
+               goto out;
 
        /* Disable interrupts */
-       wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+       if (ret < 0)
+               goto out;
 
        ret = wl1271_boot_soft_reset(wl);
        if (ret < 0)
@@ -987,47 +1113,72 @@ out:
        return ret;
 }
 
-static void wl12xx_pre_upload(struct wl1271 *wl)
+static int wl12xx_pre_upload(struct wl1271 *wl)
 {
        u32 tmp;
+       u16 polarity;
+       int ret;
 
        /* write firmware's last address (ie. it's length) to
         * ACX_EEPROMLESS_IND_REG */
        wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
 
-       wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND);
+       ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND);
+       if (ret < 0)
+               goto out;
 
-       tmp = wlcore_read_reg(wl, REG_CHIP_ID_B);
+       ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
+       if (ret < 0)
+               goto out;
 
        wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
 
        /* 6. read the EEPROM parameters */
-       tmp = wl1271_read32(wl, WL12XX_SCR_PAD2);
+       ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp);
+       if (ret < 0)
+               goto out;
 
        /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
         * to upload_fw) */
 
-       if (wl->chip.id == CHIP_ID_1283_PG20)
-               wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
-}
-
-static void wl12xx_enable_interrupts(struct wl1271 *wl)
-{
-       u32 polarity;
+       if (wl->chip.id == CHIP_ID_1283_PG20) {
+               ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
+               if (ret < 0)
+                       goto out;
+       }
 
-       polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
+       /* polarity must be set before the firmware is loaded */
+       ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity);
+       if (ret < 0)
+               goto out;
 
        /* We use HIGH polarity, so unset the LOW bit */
        polarity &= ~POLARITY_LOW;
-       wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
+       ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
 
-       wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR);
+out:
+       return ret;
+}
+
+static int wl12xx_enable_interrupts(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
+                              WL12XX_ACX_ALL_EVENTS_VECTOR);
+       if (ret < 0)
+               goto out;
 
        wlcore_enable_interrupts(wl);
-       wlcore_write_reg(wl, REG_INTERRUPT_MASK,
-                        WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
+                              WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
 
-       wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
+out:
+       return ret;
 }
 
 static int wl12xx_boot(struct wl1271 *wl)
@@ -1042,7 +1193,9 @@ static int wl12xx_boot(struct wl1271 *wl)
        if (ret < 0)
                goto out;
 
-       wl12xx_pre_upload(wl);
+       ret = wl12xx_pre_upload(wl);
+       if (ret < 0)
+               goto out;
 
        ret = wlcore_boot_upload_firmware(wl);
        if (ret < 0)
@@ -1052,22 +1205,30 @@ static int wl12xx_boot(struct wl1271 *wl)
        if (ret < 0)
                goto out;
 
-       wl12xx_enable_interrupts(wl);
+       ret = wl12xx_enable_interrupts(wl);
 
 out:
        return ret;
 }
 
-static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
+static int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
                               void *buf, size_t len)
 {
-       wl1271_write(wl, cmd_box_addr, buf, len, false);
-       wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
+       int ret;
+
+       ret = wlcore_write(wl, cmd_box_addr, buf, len, false);
+       if (ret < 0)
+               return ret;
+
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
+
+       return ret;
 }
 
-static void wl12xx_ack_event(struct wl1271 *wl)
+static int wl12xx_ack_event(struct wl1271 *wl)
 {
-       wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK);
+       return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
+                               WL12XX_INTR_TRIG_EVENT_ACK);
 }
 
 static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
@@ -1147,12 +1308,13 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
        return data_len - sizeof(*desc) - desc->pad_len;
 }
 
-static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
+static int wl12xx_tx_delayed_compl(struct wl1271 *wl)
 {
-       if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff))
-               return;
+       if (wl->fw_status_1->tx_results_counter ==
+           (wl->tx_results_count & 0xff))
+               return 0;
 
-       wl1271_tx_complete(wl);
+       return wlcore_tx_complete(wl);
 }
 
 static int wl12xx_hw_init(struct wl1271 *wl)
@@ -1253,45 +1415,144 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
        return supported;
 }
 
-static void wl12xx_get_fuse_mac(struct wl1271 *wl)
+static int wl12xx_get_fuse_mac(struct wl1271 *wl)
 {
        u32 mac1, mac2;
+       int ret;
 
-       wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
+       if (ret < 0)
+               goto out;
 
-       mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
-       mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
+       ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2);
+       if (ret < 0)
+               goto out;
 
        /* these are the two parts of the BD_ADDR */
        wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
                ((mac1 & 0xff000000) >> 24);
        wl->fuse_nic_addr = mac1 & 0xffffff;
 
-       wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
+
+out:
+       return ret;
 }
 
-static s8 wl12xx_get_pg_ver(struct wl1271 *wl)
+static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
 {
-       u32 die_info;
+       u16 die_info;
+       int ret;
 
        if (wl->chip.id == CHIP_ID_1283_PG20)
-               die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
+               ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1,
+                                         &die_info);
        else
-               die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
+               ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1,
+                                         &die_info);
+
+       if (ret >= 0 && ver)
+               *ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET);
 
-       return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
+       return ret;
 }
 
-static void wl12xx_get_mac(struct wl1271 *wl)
+static int wl12xx_get_mac(struct wl1271 *wl)
 {
        if (wl12xx_mac_in_fuse(wl))
-               wl12xx_get_fuse_mac(wl);
+               return wl12xx_get_fuse_mac(wl);
+
+       return 0;
+}
+
+static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
+                                   struct wl1271_tx_hw_descr *desc,
+                                   struct sk_buff *skb)
+{
+       desc->wl12xx_reserved = 0;
+}
+
+static int wl12xx_plt_init(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wl->ops->boot(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl->ops->hw_init(wl);
+       if (ret < 0)
+               goto out_irq_disable;
+
+       ret = wl1271_acx_init_mem_config(wl);
+       if (ret < 0)
+               goto out_irq_disable;
+
+       ret = wl12xx_acx_mem_cfg(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       /* Enable data path */
+       ret = wl1271_cmd_data_path(wl, 1);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       /* Configure for CAM power saving (ie. always active) */
+       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       /* configure PM */
+       ret = wl1271_acx_pm_config(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       goto out;
+
+out_free_memmap:
+       kfree(wl->target_mem_map);
+       wl->target_mem_map = NULL;
+
+out_irq_disable:
+       mutex_unlock(&wl->mutex);
+       /* Unlocking the mutex in the middle of handling is
+          inherently unsafe. In this case we deem it safe to do,
+          because we need to let any possibly pending IRQ out of
+          the system (and while we are WL1271_STATE_OFF the IRQ
+          work function will not do anything.) Also, any other
+          possible concurrent operations will fail due to the
+          current state, hence the wl1271 struct should be safe. */
+       wlcore_disable_interrupts(wl);
+       mutex_lock(&wl->mutex);
+out:
+       return ret;
+}
+
+static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+       if (is_gem)
+               return WL12XX_TX_HW_BLOCK_GEM_SPARE;
+
+       return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
+}
+
+static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_sta *sta,
+                         struct ieee80211_key_conf *key_conf)
+{
+       return wlcore_set_key(wl, cmd, vif, sta, key_conf);
 }
 
 static struct wlcore_ops wl12xx_ops = {
        .identify_chip          = wl12xx_identify_chip,
        .identify_fw            = wl12xx_identify_fw,
        .boot                   = wl12xx_boot,
+       .plt_init               = wl12xx_plt_init,
        .trigger_cmd            = wl12xx_trigger_cmd,
        .ack_event              = wl12xx_ack_event,
        .calc_tx_blocks         = wl12xx_calc_tx_blocks,
@@ -1306,6 +1567,13 @@ static struct wlcore_ops wl12xx_ops = {
        .sta_get_ap_rate_mask   = wl12xx_sta_get_ap_rate_mask,
        .get_pg_ver             = wl12xx_get_pg_ver,
        .get_mac                = wl12xx_get_mac,
+       .set_tx_desc_csum       = wl12xx_set_tx_desc_csum,
+       .set_rx_csum            = NULL,
+       .ap_get_mimo_wide_rate_mask = NULL,
+       .debugfs_init           = wl12xx_debugfs_add_files,
+       .get_spare_blocks       = wl12xx_get_spare_blocks,
+       .set_key                = wl12xx_set_key,
+       .pre_pkt_send           = NULL,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
@@ -1323,6 +1591,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 
 static int __devinit wl12xx_probe(struct platform_device *pdev)
 {
+       struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
        struct wl1271 *wl;
        struct ieee80211_hw *hw;
        struct wl12xx_priv *priv;
@@ -1334,19 +1603,63 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
        }
 
        wl = hw->priv;
+       priv = wl->priv;
        wl->ops = &wl12xx_ops;
        wl->ptable = wl12xx_ptable;
        wl->rtable = wl12xx_rtable;
        wl->num_tx_desc = 16;
-       wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
-       wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE;
+       wl->num_rx_desc = 8;
        wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
        wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
        wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
        wl->fw_status_priv_len = 0;
-       memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap));
+       wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
+       wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap);
+       wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap);
        wl12xx_conf_init(wl);
 
+       if (!fref_param) {
+               priv->ref_clock = pdata->board_ref_clock;
+       } else {
+               if (!strcmp(fref_param, "19.2"))
+                       priv->ref_clock = WL12XX_REFCLOCK_19;
+               else if (!strcmp(fref_param, "26"))
+                       priv->ref_clock = WL12XX_REFCLOCK_26;
+               else if (!strcmp(fref_param, "26x"))
+                       priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
+               else if (!strcmp(fref_param, "38.4"))
+                       priv->ref_clock = WL12XX_REFCLOCK_38;
+               else if (!strcmp(fref_param, "38.4x"))
+                       priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
+               else if (!strcmp(fref_param, "52"))
+                       priv->ref_clock = WL12XX_REFCLOCK_52;
+               else
+                       wl1271_error("Invalid fref parameter %s", fref_param);
+       }
+
+       if (!tcxo_param) {
+               priv->tcxo_clock = pdata->board_tcxo_clock;
+       } else {
+               if (!strcmp(tcxo_param, "19.2"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
+               else if (!strcmp(tcxo_param, "26"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
+               else if (!strcmp(tcxo_param, "38.4"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
+               else if (!strcmp(tcxo_param, "52"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
+               else if (!strcmp(tcxo_param, "16.368"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
+               else if (!strcmp(tcxo_param, "32.736"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
+               else if (!strcmp(tcxo_param, "16.8"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
+               else if (!strcmp(tcxo_param, "33.6"))
+                       priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
+               else
+                       wl1271_error("Invalid tcxo parameter %s", tcxo_param);
+       }
+
        return wlcore_probe(wl, pdev);
 }
 
@@ -1378,6 +1691,13 @@ static void __exit wl12xx_exit(void)
 }
 module_exit(wl12xx_exit);
 
+module_param_named(fref, fref_param, charp, 0);
+MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
+
+module_param_named(tcxo, tcxo_param, charp, 0);
+MODULE_PARM_DESC(tcxo,
+                "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
index 74cd332e23ef49c54accb3fd5eeb874d9b16cc58..de1132410876b976aa31e72b4412ac3a9b166465 100644 (file)
 
 #include "conf.h"
 
+struct wl127x_rx_mem_pool_addr {
+       u32 addr;
+       u32 addr_extra;
+};
+
 struct wl12xx_priv {
        struct wl12xx_priv_conf conf;
+
+       int ref_clock;
+       int tcxo_clock;
 };
 
 #endif /* __WL12XX_PRIV_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/Kconfig b/drivers/net/wireless/ti/wl18xx/Kconfig
new file mode 100644 (file)
index 0000000..1cfdb25
--- /dev/null
@@ -0,0 +1,7 @@
+config WL18XX
+       tristate "TI wl18xx support"
+       depends on MAC80211
+       select WLCORE
+       ---help---
+         This module adds support for wireless adapters based on TI
+         WiLink 8 chipsets.
diff --git a/drivers/net/wireless/ti/wl18xx/Makefile b/drivers/net/wireless/ti/wl18xx/Makefile
new file mode 100644 (file)
index 0000000..67c0987
--- /dev/null
@@ -0,0 +1,3 @@
+wl18xx-objs    = main.o acx.o tx.o io.o debugfs.o
+
+obj-$(CONFIG_WL18XX)           += wl18xx.o
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
new file mode 100644 (file)
index 0000000..72840e2
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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
+ *
+ */
+
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/acx.h"
+
+#include "acx.h"
+
+int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
+                                 u32 sdio_blk_size, u32 extra_mem_blks,
+                                 u32 len_field_size)
+{
+       struct wl18xx_acx_host_config_bitmap *bitmap_conf;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
+                    host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
+                    len_field_size);
+
+       bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
+       if (!bitmap_conf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
+       bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
+       bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
+       bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
+
+       ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
+                                  bitmap_conf, sizeof(*bitmap_conf));
+       if (ret < 0) {
+               wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(bitmap_conf);
+
+       return ret;
+}
+
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
+{
+       struct wl18xx_acx_checksum_state *acx;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx checksum state");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
+
+       ret = wl1271_cmd_configure(wl, ACX_CHECKSUM_CONFIG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("failed to set Tx checksum state: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl18xx_acx_clear_statistics(struct wl1271 *wl)
+{
+       struct wl18xx_acx_clear_statistics *acx;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx clear statistics");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("failed to clear firmware statistics: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
new file mode 100644 (file)
index 0000000..e2609a6
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * 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 __WL18XX_ACX_H__
+#define __WL18XX_ACX_H__
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/acx.h"
+
+enum {
+       ACX_CLEAR_STATISTICS             = 0x0047,
+};
+
+/* numbers of bits the length field takes (add 1 for the actual number) */
+#define WL18XX_HOST_IF_LEN_SIZE_FIELD 15
+
+#define WL18XX_ACX_EVENTS_VECTOR       (WL1271_ACX_INTR_WATCHDOG       | \
+                                        WL1271_ACX_INTR_INIT_COMPLETE  | \
+                                        WL1271_ACX_INTR_EVENT_A        | \
+                                        WL1271_ACX_INTR_EVENT_B        | \
+                                        WL1271_ACX_INTR_CMD_COMPLETE   | \
+                                        WL1271_ACX_INTR_HW_AVAILABLE   | \
+                                        WL1271_ACX_INTR_DATA           | \
+                                        WL1271_ACX_SW_INTR_WATCHDOG)
+
+#define WL18XX_INTR_MASK               (WL1271_ACX_INTR_WATCHDOG       | \
+                                        WL1271_ACX_INTR_EVENT_A        | \
+                                        WL1271_ACX_INTR_EVENT_B        | \
+                                        WL1271_ACX_INTR_HW_AVAILABLE   | \
+                                        WL1271_ACX_INTR_DATA           | \
+                                        WL1271_ACX_SW_INTR_WATCHDOG)
+
+struct wl18xx_acx_host_config_bitmap {
+       struct acx_header header;
+
+       __le32 host_cfg_bitmap;
+
+       __le32 host_sdio_block_size;
+
+       /* extra mem blocks per frame in TX. */
+       __le32 extra_mem_blocks;
+
+       /*
+        * number of bits of the length field in the first TX word
+        * (up to 15 - for using the entire 16 bits).
+        */
+       __le32 length_field_size;
+
+} __packed;
+
+enum {
+       CHECKSUM_OFFLOAD_DISABLED = 0,
+       CHECKSUM_OFFLOAD_ENABLED  = 1,
+       CHECKSUM_OFFLOAD_FAKE_RX  = 2,
+       CHECKSUM_OFFLOAD_INVALID  = 0xFF
+};
+
+struct wl18xx_acx_checksum_state {
+       struct acx_header header;
+
+        /* enum acx_checksum_state */
+       u8 checksum_state;
+       u8 pad[3];
+} __packed;
+
+
+struct wl18xx_acx_error_stats {
+       u32 error_frame;
+       u32 error_null_Frame_tx_start;
+       u32 error_numll_frame_cts_start;
+       u32 error_bar_retry;
+       u32 error_frame_cts_nul_flid;
+} __packed;
+
+struct wl18xx_acx_debug_stats {
+       u32 debug1;
+       u32 debug2;
+       u32 debug3;
+       u32 debug4;
+       u32 debug5;
+       u32 debug6;
+} __packed;
+
+struct wl18xx_acx_ring_stats {
+       u32 prepared_descs;
+       u32 tx_cmplt;
+} __packed;
+
+struct wl18xx_acx_tx_stats {
+       u32 tx_prepared_descs;
+       u32 tx_cmplt;
+       u32 tx_template_prepared;
+       u32 tx_data_prepared;
+       u32 tx_template_programmed;
+       u32 tx_data_programmed;
+       u32 tx_burst_programmed;
+       u32 tx_starts;
+       u32 tx_imm_resp;
+       u32 tx_start_templates;
+       u32 tx_start_int_templates;
+       u32 tx_start_fw_gen;
+       u32 tx_start_data;
+       u32 tx_start_null_frame;
+       u32 tx_exch;
+       u32 tx_retry_template;
+       u32 tx_retry_data;
+       u32 tx_exch_pending;
+       u32 tx_exch_expiry;
+       u32 tx_done_template;
+       u32 tx_done_data;
+       u32 tx_done_int_template;
+       u32 tx_frame_checksum;
+       u32 tx_checksum_result;
+       u32 frag_called;
+       u32 frag_mpdu_alloc_failed;
+       u32 frag_init_called;
+       u32 frag_in_process_called;
+       u32 frag_tkip_called;
+       u32 frag_key_not_found;
+       u32 frag_need_fragmentation;
+       u32 frag_bad_mblk_num;
+       u32 frag_failed;
+       u32 frag_cache_hit;
+       u32 frag_cache_miss;
+} __packed;
+
+struct wl18xx_acx_rx_stats {
+       u32 rx_beacon_early_term;
+       u32 rx_out_of_mpdu_nodes;
+       u32 rx_hdr_overflow;
+       u32 rx_dropped_frame;
+       u32 rx_done_stage;
+       u32 rx_done;
+       u32 rx_defrag;
+       u32 rx_defrag_end;
+       u32 rx_cmplt;
+       u32 rx_pre_complt;
+       u32 rx_cmplt_task;
+       u32 rx_phy_hdr;
+       u32 rx_timeout;
+       u32 rx_timeout_wa;
+       u32 rx_wa_density_dropped_frame;
+       u32 rx_wa_ba_not_expected;
+       u32 rx_frame_checksum;
+       u32 rx_checksum_result;
+       u32 defrag_called;
+       u32 defrag_init_called;
+       u32 defrag_in_process_called;
+       u32 defrag_tkip_called;
+       u32 defrag_need_defrag;
+       u32 defrag_decrypt_failed;
+       u32 decrypt_key_not_found;
+       u32 defrag_need_decrypt;
+       u32 rx_tkip_replays;
+} __packed;
+
+struct wl18xx_acx_isr_stats {
+       u32 irqs;
+} __packed;
+
+#define PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD 10
+
+struct wl18xx_acx_pwr_stats {
+       u32 missing_bcns_cnt;
+       u32 rcvd_bcns_cnt;
+       u32 connection_out_of_sync;
+       u32 cont_miss_bcns_spread[PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD];
+       u32 rcvd_awake_bcns_cnt;
+} __packed;
+
+struct wl18xx_acx_event_stats {
+       u32 calibration;
+       u32 rx_mismatch;
+       u32 rx_mem_empty;
+} __packed;
+
+struct wl18xx_acx_ps_poll_stats {
+       u32 ps_poll_timeouts;
+       u32 upsd_timeouts;
+       u32 upsd_max_ap_turn;
+       u32 ps_poll_max_ap_turn;
+       u32 ps_poll_utilization;
+       u32 upsd_utilization;
+} __packed;
+
+struct wl18xx_acx_rx_filter_stats {
+       u32 beacon_filter;
+       u32 arp_filter;
+       u32 mc_filter;
+       u32 dup_filter;
+       u32 data_filter;
+       u32 ibss_filter;
+       u32 protection_filter;
+       u32 accum_arp_pend_requests;
+       u32 max_arp_queue_dep;
+} __packed;
+
+struct wl18xx_acx_rx_rate_stats {
+       u32 rx_frames_per_rates[50];
+} __packed;
+
+#define AGGR_STATS_TX_AGG      16
+#define AGGR_STATS_TX_RATE     16
+#define AGGR_STATS_RX_SIZE_LEN 16
+
+struct wl18xx_acx_aggr_stats {
+       u32 tx_agg_vs_rate[AGGR_STATS_TX_AGG * AGGR_STATS_TX_RATE];
+       u32 rx_size[AGGR_STATS_RX_SIZE_LEN];
+} __packed;
+
+#define PIPE_STATS_HW_FIFO     11
+
+struct wl18xx_acx_pipeline_stats {
+       u32 hs_tx_stat_fifo_int;
+       u32 hs_rx_stat_fifo_int;
+       u32 tcp_tx_stat_fifo_int;
+       u32 tcp_rx_stat_fifo_int;
+       u32 enc_tx_stat_fifo_int;
+       u32 enc_rx_stat_fifo_int;
+       u32 rx_complete_stat_fifo_int;
+       u32 pre_proc_swi;
+       u32 post_proc_swi;
+       u32 sec_frag_swi;
+       u32 pre_to_defrag_swi;
+       u32 defrag_to_csum_swi;
+       u32 csum_to_rx_xfer_swi;
+       u32 dec_packet_in;
+       u32 dec_packet_in_fifo_full;
+       u32 dec_packet_out;
+       u32 cs_rx_packet_in;
+       u32 cs_rx_packet_out;
+       u16 pipeline_fifo_full[PIPE_STATS_HW_FIFO];
+} __packed;
+
+struct wl18xx_acx_mem_stats {
+       u32 rx_free_mem_blks;
+       u32 tx_free_mem_blks;
+       u32 fwlog_free_mem_blks;
+       u32 fw_gen_free_mem_blks;
+} __packed;
+
+struct wl18xx_acx_statistics {
+       struct acx_header header;
+
+       struct wl18xx_acx_error_stats           error;
+       struct wl18xx_acx_debug_stats           debug;
+       struct wl18xx_acx_tx_stats              tx;
+       struct wl18xx_acx_rx_stats              rx;
+       struct wl18xx_acx_isr_stats             isr;
+       struct wl18xx_acx_pwr_stats             pwr;
+       struct wl18xx_acx_ps_poll_stats         ps_poll;
+       struct wl18xx_acx_rx_filter_stats       rx_filter;
+       struct wl18xx_acx_rx_rate_stats         rx_rate;
+       struct wl18xx_acx_aggr_stats            aggr_size;
+       struct wl18xx_acx_pipeline_stats        pipeline;
+       struct wl18xx_acx_mem_stats             mem;
+} __packed;
+
+struct wl18xx_acx_clear_statistics {
+       struct acx_header header;
+};
+
+int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
+                                 u32 sdio_blk_size, u32 extra_mem_blks,
+                                 u32 len_field_size);
+int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
+int wl18xx_acx_clear_statistics(struct wl1271 *wl);
+
+#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
new file mode 100644 (file)
index 0000000..fac0b7e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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 __WL18XX_CONF_H__
+#define __WL18XX_CONF_H__
+
+#define WL18XX_CONF_MAGIC      0x10e100ca
+#define WL18XX_CONF_VERSION    (WLCORE_CONF_VERSION | 0x0002)
+#define WL18XX_CONF_MASK       0x0000ffff
+#define WL18XX_CONF_SIZE       (WLCORE_CONF_SIZE + \
+                                sizeof(struct wl18xx_priv_conf))
+
+#define NUM_OF_CHANNELS_11_ABG 150
+#define NUM_OF_CHANNELS_11_P 7
+#define WL18XX_NUM_OF_SUB_BANDS 9
+#define SRF_TABLE_LEN 16
+#define PIN_MUXING_SIZE 2
+
+struct wl18xx_mac_and_phy_params {
+       u8 phy_standalone;
+       u8 rdl;
+       u8 enable_clpc;
+       u8 enable_tx_low_pwr_on_siso_rdl;
+       u8 auto_detect;
+       u8 dedicated_fem;
+
+       u8 low_band_component;
+
+       /* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
+       u8 low_band_component_type;
+
+       u8 high_band_component;
+
+       /* Bit 0: One Hot, Bit 1: Control Enable, Bit 2: 1.8V, Bit 3: 3V */
+       u8 high_band_component_type;
+       u8 number_of_assembled_ant2_4;
+       u8 number_of_assembled_ant5;
+       u8 pin_muxing_platform_options[PIN_MUXING_SIZE];
+       u8 external_pa_dc2dc;
+       u8 tcxo_ldo_voltage;
+       u8 xtal_itrim_val;
+       u8 srf_state;
+       u8 srf1[SRF_TABLE_LEN];
+       u8 srf2[SRF_TABLE_LEN];
+       u8 srf3[SRF_TABLE_LEN];
+       u8 io_configuration;
+       u8 sdio_configuration;
+       u8 settings;
+       u8 rx_profile;
+       u8 per_chan_pwr_limit_arr_11abg[NUM_OF_CHANNELS_11_ABG];
+       u8 pwr_limit_reference_11_abg;
+       u8 per_chan_pwr_limit_arr_11p[NUM_OF_CHANNELS_11_P];
+       u8 pwr_limit_reference_11p;
+       u8 per_sub_band_tx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+       u8 per_sub_band_rx_trace_loss[WL18XX_NUM_OF_SUB_BANDS];
+       u8 primary_clock_setting_time;
+       u8 clock_valid_on_wake_up;
+       u8 secondary_clock_setting_time;
+       u8 board_type;
+       /* enable point saturation */
+       u8 psat;
+       /* low/medium/high Tx power in dBm */
+       s8 low_power_val;
+       s8 med_power_val;
+       s8 high_power_val;
+       u8 padding[1];
+} __packed;
+
+struct wl18xx_priv_conf {
+       /* this structure is copied wholesale to FW */
+       struct wl18xx_mac_and_phy_params phy;
+} __packed;
+
+#endif /* __WL18XX_CONF_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c
new file mode 100644 (file)
index 0000000..3ce6f10
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2011-2012 Texas Instruments
+ *
+ * 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
+ *
+ */
+
+#include "../wlcore/debugfs.h"
+#include "../wlcore/wlcore.h"
+
+#include "wl18xx.h"
+#include "acx.h"
+#include "debugfs.h"
+
+#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
+       DEBUGFS_FWSTATS_FILE(a, b, c, wl18xx_acx_statistics)
+#define WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c) \
+       DEBUGFS_FWSTATS_FILE_ARRAY(a, b, c, wl18xx_acx_statistics)
+
+
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug1, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug2, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug3, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug4, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug5, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(debug, debug6, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_null_Frame_tx_start, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_numll_frame_cts_start, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_bar_retry, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(error, error_frame_cts_nul_flid, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_prepared_descs, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_cmplt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_prepared, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_prepared, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_template_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_data_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_burst_programmed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_starts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_imm_resp, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_templates, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_int_templates, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_fw_gen, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_start_null_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_retry_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_pending, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_exch_expiry, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_data, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_done_int_template, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_frame_checksum, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, tx_checksum_result, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_mpdu_alloc_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_init_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_in_process_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_tkip_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_key_not_found, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_need_fragmentation, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_bad_mblk_num, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_hit, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(tx, frag_cache_miss, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_beacon_early_term, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_out_of_mpdu_nodes, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_hdr_overflow, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_dropped_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_done, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_defrag_end, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_pre_complt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_cmplt_task, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_phy_hdr, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_timeout_wa, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_density_dropped_frame, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_wa_ba_not_expected, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_frame_checksum, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_checksum_result, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_init_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_in_process_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_tkip_called, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_defrag, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_decrypt_failed, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, decrypt_key_not_found, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, defrag_need_decrypt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx, rx_tkip_replays, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, missing_bcns_cnt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_bcns_cnt, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, connection_out_of_sync, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pwr, cont_miss_bcns_spread,
+                                 PWR_STAT_MAX_CONT_MISSED_BCNS_SPREAD);
+WL18XX_DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_bcns_cnt, "%u");
+
+
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_timeouts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_timeouts, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_max_ap_turn, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_max_ap_turn, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, ps_poll_utilization, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(ps_poll, upsd_utilization, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, beacon_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, arp_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, mc_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, dup_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, data_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, ibss_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate,
+                                 AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE);
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, rx_size,
+                                 AGGR_STATS_RX_SIZE_LEN);
+
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, hs_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, tcp_rx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_tx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, enc_rx_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, rx_complete_stat_fifo_int, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_proc_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, post_proc_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, sec_frag_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, pre_to_defrag_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, defrag_to_csum_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, csum_to_rx_xfer_swi, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_in_fifo_full, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, dec_packet_out, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_in, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(pipeline, cs_rx_packet_out, "%u");
+
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(pipeline, pipeline_fifo_full,
+                                 PIPE_STATS_HW_FIFO);
+
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, rx_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, tx_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, fwlog_free_mem_blks, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE(mem, fw_gen_free_mem_blks, "%u");
+
+static ssize_t conf_read(struct file *file, char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       struct wl18xx_priv *priv = wl->priv;
+       struct wlcore_conf_header header;
+       char *buf, *pos;
+       size_t len;
+       int ret;
+
+       len = WL18XX_CONF_SIZE;
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       header.magic    = cpu_to_le32(WL18XX_CONF_MAGIC);
+       header.version  = cpu_to_le32(WL18XX_CONF_VERSION);
+       header.checksum = 0;
+
+       mutex_lock(&wl->mutex);
+
+       pos = buf;
+       memcpy(pos, &header, sizeof(header));
+       pos += sizeof(header);
+       memcpy(pos, &wl->conf, sizeof(wl->conf));
+       pos += sizeof(wl->conf);
+       memcpy(pos, &priv->conf, sizeof(priv->conf));
+
+       mutex_unlock(&wl->mutex);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations conf_ops = {
+       .read = conf_read,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+static ssize_t clear_fw_stats_write(struct file *file,
+                             const char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       int ret;
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       ret = wl18xx_acx_clear_statistics(wl);
+       if (ret < 0) {
+               count = ret;
+               goto out;
+       }
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations clear_fw_stats_ops = {
+       .write = clear_fw_stats_write,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+int wl18xx_debugfs_add_files(struct wl1271 *wl,
+                            struct dentry *rootdir)
+{
+       int ret = 0;
+       struct dentry *entry, *stats, *moddir;
+
+       moddir = debugfs_create_dir(KBUILD_MODNAME, rootdir);
+       if (!moddir || IS_ERR(moddir)) {
+               entry = moddir;
+               goto err;
+       }
+
+       stats = debugfs_create_dir("fw_stats", moddir);
+       if (!stats || IS_ERR(stats)) {
+               entry = stats;
+               goto err;
+       }
+
+       DEBUGFS_ADD(clear_fw_stats, stats);
+
+       DEBUGFS_FWSTATS_ADD(debug, debug1);
+       DEBUGFS_FWSTATS_ADD(debug, debug2);
+       DEBUGFS_FWSTATS_ADD(debug, debug3);
+       DEBUGFS_FWSTATS_ADD(debug, debug4);
+       DEBUGFS_FWSTATS_ADD(debug, debug5);
+       DEBUGFS_FWSTATS_ADD(debug, debug6);
+
+       DEBUGFS_FWSTATS_ADD(error, error_frame);
+       DEBUGFS_FWSTATS_ADD(error, error_null_Frame_tx_start);
+       DEBUGFS_FWSTATS_ADD(error, error_numll_frame_cts_start);
+       DEBUGFS_FWSTATS_ADD(error, error_bar_retry);
+       DEBUGFS_FWSTATS_ADD(error, error_frame_cts_nul_flid);
+
+       DEBUGFS_FWSTATS_ADD(tx, tx_prepared_descs);
+       DEBUGFS_FWSTATS_ADD(tx, tx_cmplt);
+       DEBUGFS_FWSTATS_ADD(tx, tx_template_prepared);
+       DEBUGFS_FWSTATS_ADD(tx, tx_data_prepared);
+       DEBUGFS_FWSTATS_ADD(tx, tx_template_programmed);
+       DEBUGFS_FWSTATS_ADD(tx, tx_data_programmed);
+       DEBUGFS_FWSTATS_ADD(tx, tx_burst_programmed);
+       DEBUGFS_FWSTATS_ADD(tx, tx_starts);
+       DEBUGFS_FWSTATS_ADD(tx, tx_imm_resp);
+       DEBUGFS_FWSTATS_ADD(tx, tx_start_templates);
+       DEBUGFS_FWSTATS_ADD(tx, tx_start_int_templates);
+       DEBUGFS_FWSTATS_ADD(tx, tx_start_fw_gen);
+       DEBUGFS_FWSTATS_ADD(tx, tx_start_data);
+       DEBUGFS_FWSTATS_ADD(tx, tx_start_null_frame);
+       DEBUGFS_FWSTATS_ADD(tx, tx_exch);
+       DEBUGFS_FWSTATS_ADD(tx, tx_retry_template);
+       DEBUGFS_FWSTATS_ADD(tx, tx_retry_data);
+       DEBUGFS_FWSTATS_ADD(tx, tx_exch_pending);
+       DEBUGFS_FWSTATS_ADD(tx, tx_exch_expiry);
+       DEBUGFS_FWSTATS_ADD(tx, tx_done_template);
+       DEBUGFS_FWSTATS_ADD(tx, tx_done_data);
+       DEBUGFS_FWSTATS_ADD(tx, tx_done_int_template);
+       DEBUGFS_FWSTATS_ADD(tx, tx_frame_checksum);
+       DEBUGFS_FWSTATS_ADD(tx, tx_checksum_result);
+       DEBUGFS_FWSTATS_ADD(tx, frag_called);
+       DEBUGFS_FWSTATS_ADD(tx, frag_mpdu_alloc_failed);
+       DEBUGFS_FWSTATS_ADD(tx, frag_init_called);
+       DEBUGFS_FWSTATS_ADD(tx, frag_in_process_called);
+       DEBUGFS_FWSTATS_ADD(tx, frag_tkip_called);
+       DEBUGFS_FWSTATS_ADD(tx, frag_key_not_found);
+       DEBUGFS_FWSTATS_ADD(tx, frag_need_fragmentation);
+       DEBUGFS_FWSTATS_ADD(tx, frag_bad_mblk_num);
+       DEBUGFS_FWSTATS_ADD(tx, frag_failed);
+       DEBUGFS_FWSTATS_ADD(tx, frag_cache_hit);
+       DEBUGFS_FWSTATS_ADD(tx, frag_cache_miss);
+
+       DEBUGFS_FWSTATS_ADD(rx, rx_beacon_early_term);
+       DEBUGFS_FWSTATS_ADD(rx, rx_out_of_mpdu_nodes);
+       DEBUGFS_FWSTATS_ADD(rx, rx_hdr_overflow);
+       DEBUGFS_FWSTATS_ADD(rx, rx_dropped_frame);
+       DEBUGFS_FWSTATS_ADD(rx, rx_done);
+       DEBUGFS_FWSTATS_ADD(rx, rx_defrag);
+       DEBUGFS_FWSTATS_ADD(rx, rx_defrag_end);
+       DEBUGFS_FWSTATS_ADD(rx, rx_cmplt);
+       DEBUGFS_FWSTATS_ADD(rx, rx_pre_complt);
+       DEBUGFS_FWSTATS_ADD(rx, rx_cmplt_task);
+       DEBUGFS_FWSTATS_ADD(rx, rx_phy_hdr);
+       DEBUGFS_FWSTATS_ADD(rx, rx_timeout);
+       DEBUGFS_FWSTATS_ADD(rx, rx_timeout_wa);
+       DEBUGFS_FWSTATS_ADD(rx, rx_wa_density_dropped_frame);
+       DEBUGFS_FWSTATS_ADD(rx, rx_wa_ba_not_expected);
+       DEBUGFS_FWSTATS_ADD(rx, rx_frame_checksum);
+       DEBUGFS_FWSTATS_ADD(rx, rx_checksum_result);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_called);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_init_called);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_in_process_called);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_tkip_called);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_need_defrag);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_decrypt_failed);
+       DEBUGFS_FWSTATS_ADD(rx, decrypt_key_not_found);
+       DEBUGFS_FWSTATS_ADD(rx, defrag_need_decrypt);
+       DEBUGFS_FWSTATS_ADD(rx, rx_tkip_replays);
+
+       DEBUGFS_FWSTATS_ADD(isr, irqs);
+
+       DEBUGFS_FWSTATS_ADD(pwr, missing_bcns_cnt);
+       DEBUGFS_FWSTATS_ADD(pwr, rcvd_bcns_cnt);
+       DEBUGFS_FWSTATS_ADD(pwr, connection_out_of_sync);
+       DEBUGFS_FWSTATS_ADD(pwr, cont_miss_bcns_spread);
+       DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_bcns_cnt);
+
+       DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_timeouts);
+       DEBUGFS_FWSTATS_ADD(ps_poll, upsd_timeouts);
+       DEBUGFS_FWSTATS_ADD(ps_poll, upsd_max_ap_turn);
+       DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_max_ap_turn);
+       DEBUGFS_FWSTATS_ADD(ps_poll, ps_poll_utilization);
+       DEBUGFS_FWSTATS_ADD(ps_poll, upsd_utilization);
+
+       DEBUGFS_FWSTATS_ADD(rx_filter, beacon_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, arp_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, mc_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, dup_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, data_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, ibss_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, protection_filter);
+       DEBUGFS_FWSTATS_ADD(rx_filter, accum_arp_pend_requests);
+       DEBUGFS_FWSTATS_ADD(rx_filter, max_arp_queue_dep);
+
+       DEBUGFS_FWSTATS_ADD(rx_rate, rx_frames_per_rates);
+
+       DEBUGFS_FWSTATS_ADD(aggr_size, tx_agg_vs_rate);
+       DEBUGFS_FWSTATS_ADD(aggr_size, rx_size);
+
+       DEBUGFS_FWSTATS_ADD(pipeline, hs_tx_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, tcp_tx_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, tcp_rx_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, enc_tx_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, enc_rx_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, rx_complete_stat_fifo_int);
+       DEBUGFS_FWSTATS_ADD(pipeline, pre_proc_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, post_proc_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, sec_frag_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, pre_to_defrag_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, defrag_to_csum_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, csum_to_rx_xfer_swi);
+       DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in);
+       DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_in_fifo_full);
+       DEBUGFS_FWSTATS_ADD(pipeline, dec_packet_out);
+       DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_in);
+       DEBUGFS_FWSTATS_ADD(pipeline, cs_rx_packet_out);
+       DEBUGFS_FWSTATS_ADD(pipeline, pipeline_fifo_full);
+
+       DEBUGFS_FWSTATS_ADD(mem, rx_free_mem_blks);
+       DEBUGFS_FWSTATS_ADD(mem, tx_free_mem_blks);
+       DEBUGFS_FWSTATS_ADD(mem, fwlog_free_mem_blks);
+       DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);
+
+       DEBUGFS_ADD(conf, moddir);
+
+       return 0;
+
+err:
+       if (IS_ERR(entry))
+               ret = PTR_ERR(entry);
+       else
+               ret = -ENOMEM;
+
+       return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.h b/drivers/net/wireless/ti/wl18xx/debugfs.h
new file mode 100644 (file)
index 0000000..ed679be
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2012 Texas Instruments. All rights reserved.
+ *
+ * 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 __WL18XX_DEBUGFS_H__
+#define __WL18XX_DEBUGFS_H__
+
+int wl18xx_debugfs_add_files(struct wl1271 *wl,
+                            struct dentry *rootdir);
+
+#endif /* __WL18XX_DEBUGFS_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/io.c b/drivers/net/wireless/ti/wl18xx/io.c
new file mode 100644 (file)
index 0000000..0c06ccf
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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
+ *
+ */
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/io.h"
+
+#include "io.h"
+
+int wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
+{
+       u32 tmp;
+       int ret;
+
+       if (WARN_ON(addr % 2))
+               return -EINVAL;
+
+       if ((addr % 4) == 0) {
+               ret = wlcore_read32(wl, addr, &tmp);
+               if (ret < 0)
+                       goto out;
+
+               tmp = (tmp & 0xffff0000) | val;
+               ret = wlcore_write32(wl, addr, tmp);
+       } else {
+               ret = wlcore_read32(wl, addr - 2, &tmp);
+               if (ret < 0)
+                       goto out;
+
+               tmp = (tmp & 0xffff) | (val << 16);
+               ret = wlcore_write32(wl, addr - 2, tmp);
+       }
+
+out:
+       return ret;
+}
+
+int wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out)
+{
+       u32 val;
+       int ret;
+
+       if (WARN_ON(addr % 2))
+               return -EINVAL;
+
+       if ((addr % 4) == 0) {
+               /* address is 4-bytes aligned */
+               ret = wlcore_read32(wl, addr, &val);
+               if (ret >= 0 && out)
+                       *out = val & 0xffff;
+       } else {
+               ret = wlcore_read32(wl, addr - 2, &val);
+               if (ret >= 0 && out)
+                       *out = (val & 0xffff0000) >> 16;
+       }
+
+       return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/io.h b/drivers/net/wireless/ti/wl18xx/io.h
new file mode 100644 (file)
index 0000000..c32ae30
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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 __WL18XX_IO_H__
+#define __WL18XX_IO_H__
+
+int __must_check wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+int __must_check wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out);
+
+#endif /* __WL18XX_IO_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
new file mode 100644 (file)
index 0000000..5e583be
--- /dev/null
@@ -0,0 +1,1542 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ip.h>
+#include <linux/firmware.h>
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/io.h"
+#include "../wlcore/acx.h"
+#include "../wlcore/tx.h"
+#include "../wlcore/rx.h"
+#include "../wlcore/io.h"
+#include "../wlcore/boot.h"
+
+#include "reg.h"
+#include "conf.h"
+#include "acx.h"
+#include "tx.h"
+#include "wl18xx.h"
+#include "io.h"
+#include "debugfs.h"
+
+#define WL18XX_RX_CHECKSUM_MASK      0x40
+
+static char *ht_mode_param = "default";
+static char *board_type_param = "hdk";
+static bool checksum_param = false;
+static bool enable_11a_param = true;
+static int num_rx_desc_param = -1;
+
+/* phy paramters */
+static int dc2dc_param = -1;
+static int n_antennas_2_param = -1;
+static int n_antennas_5_param = -1;
+static int low_band_component_param = -1;
+static int low_band_component_type_param = -1;
+static int high_band_component_param = -1;
+static int high_band_component_type_param = -1;
+static int pwr_limit_reference_11_abg_param = -1;
+
+static const u8 wl18xx_rate_to_idx_2ghz[] = {
+       /* MCS rates are used only with 11n */
+       15,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
+       14,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
+       13,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
+       12,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
+       11,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
+       10,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
+       9,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
+       8,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
+       7,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
+       6,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
+       5,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
+       4,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
+       3,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
+       2,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
+       1,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
+       0,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
+
+       11,                            /* WL18XX_CONF_HW_RXTX_RATE_54   */
+       10,                            /* WL18XX_CONF_HW_RXTX_RATE_48   */
+       9,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
+       8,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
+
+       7,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
+       6,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
+       3,                             /* WL18XX_CONF_HW_RXTX_RATE_11   */
+       5,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
+       4,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
+       2,                             /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
+       1,                             /* WL18XX_CONF_HW_RXTX_RATE_2    */
+       0                              /* WL18XX_CONF_HW_RXTX_RATE_1    */
+};
+
+static const u8 wl18xx_rate_to_idx_5ghz[] = {
+       /* MCS rates are used only with 11n */
+       15,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
+       14,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
+       13,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
+       12,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
+       11,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
+       10,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
+       9,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
+       8,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
+       7,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
+       6,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
+       5,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
+       4,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
+       3,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
+       2,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
+       1,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
+       0,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
+
+       7,                             /* WL18XX_CONF_HW_RXTX_RATE_54   */
+       6,                             /* WL18XX_CONF_HW_RXTX_RATE_48   */
+       5,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
+       4,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
+
+       3,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
+       2,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11   */
+       1,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
+       0,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1    */
+};
+
+static const u8 *wl18xx_band_rate_to_idx[] = {
+       [IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz,
+       [IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz
+};
+
+enum wl18xx_hw_rates {
+       WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0,
+       WL18XX_CONF_HW_RXTX_RATE_MCS14,
+       WL18XX_CONF_HW_RXTX_RATE_MCS13,
+       WL18XX_CONF_HW_RXTX_RATE_MCS12,
+       WL18XX_CONF_HW_RXTX_RATE_MCS11,
+       WL18XX_CONF_HW_RXTX_RATE_MCS10,
+       WL18XX_CONF_HW_RXTX_RATE_MCS9,
+       WL18XX_CONF_HW_RXTX_RATE_MCS8,
+       WL18XX_CONF_HW_RXTX_RATE_MCS7,
+       WL18XX_CONF_HW_RXTX_RATE_MCS6,
+       WL18XX_CONF_HW_RXTX_RATE_MCS5,
+       WL18XX_CONF_HW_RXTX_RATE_MCS4,
+       WL18XX_CONF_HW_RXTX_RATE_MCS3,
+       WL18XX_CONF_HW_RXTX_RATE_MCS2,
+       WL18XX_CONF_HW_RXTX_RATE_MCS1,
+       WL18XX_CONF_HW_RXTX_RATE_MCS0,
+       WL18XX_CONF_HW_RXTX_RATE_54,
+       WL18XX_CONF_HW_RXTX_RATE_48,
+       WL18XX_CONF_HW_RXTX_RATE_36,
+       WL18XX_CONF_HW_RXTX_RATE_24,
+       WL18XX_CONF_HW_RXTX_RATE_22,
+       WL18XX_CONF_HW_RXTX_RATE_18,
+       WL18XX_CONF_HW_RXTX_RATE_12,
+       WL18XX_CONF_HW_RXTX_RATE_11,
+       WL18XX_CONF_HW_RXTX_RATE_9,
+       WL18XX_CONF_HW_RXTX_RATE_6,
+       WL18XX_CONF_HW_RXTX_RATE_5_5,
+       WL18XX_CONF_HW_RXTX_RATE_2,
+       WL18XX_CONF_HW_RXTX_RATE_1,
+       WL18XX_CONF_HW_RXTX_RATE_MAX,
+};
+
+static struct wlcore_conf wl18xx_conf = {
+       .sg = {
+               .params = {
+                       [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
+                       [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
+                       [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
+                       [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
+                       [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
+                       [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
+                       [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
+                       [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
+                       [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
+                       [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
+                       [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
+                       [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
+                       [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
+                       [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
+                       [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
+                       [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
+                       [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
+                       [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
+                       [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
+                       [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
+                       [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
+                       [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
+                       [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
+                       [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
+                       [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
+                       [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
+                       /* active scan params */
+                       [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+                       [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+                       [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+                       /* passive scan params */
+                       [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
+                       [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
+                       [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+                       /* passive scan in dual antenna params */
+                       [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
+                       [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
+                       [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
+                       /* general params */
+                       [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
+                       [CONF_SG_ANTENNA_CONFIGURATION] = 0,
+                       [CONF_SG_BEACON_MISS_PERCENT] = 60,
+                       [CONF_SG_DHCP_TIME] = 5000,
+                       [CONF_SG_RXT] = 1200,
+                       [CONF_SG_TXT] = 1000,
+                       [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+                       [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
+                       [CONF_SG_HV3_MAX_SERVED] = 6,
+                       [CONF_SG_PS_POLL_TIMEOUT] = 10,
+                       [CONF_SG_UPSD_TIMEOUT] = 10,
+                       [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
+                       [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
+                       [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
+                       /* AP params */
+                       [CONF_AP_BEACON_MISS_TX] = 3,
+                       [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
+                       [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
+                       [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
+                       [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
+                       [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
+                       /* CTS Diluting params */
+                       [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
+                       [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
+               },
+               .state = CONF_SG_PROTECTIVE,
+       },
+       .rx = {
+               .rx_msdu_life_time           = 512000,
+               .packet_detection_threshold  = 0,
+               .ps_poll_timeout             = 15,
+               .upsd_timeout                = 15,
+               .rts_threshold               = IEEE80211_MAX_RTS_THRESHOLD,
+               .rx_cca_threshold            = 0,
+               .irq_blk_threshold           = 0xFFFF,
+               .irq_pkt_threshold           = 0,
+               .irq_timeout                 = 600,
+               .queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
+       },
+       .tx = {
+               .tx_energy_detection         = 0,
+               .sta_rc_conf                 = {
+                       .enabled_rates       = 0,
+                       .short_retry_limit   = 10,
+                       .long_retry_limit    = 10,
+                       .aflags              = 0,
+               },
+               .ac_conf_count               = 4,
+               .ac_conf                     = {
+                       [CONF_TX_AC_BE] = {
+                               .ac          = CONF_TX_AC_BE,
+                               .cw_min      = 15,
+                               .cw_max      = 63,
+                               .aifsn       = 3,
+                               .tx_op_limit = 0,
+                       },
+                       [CONF_TX_AC_BK] = {
+                               .ac          = CONF_TX_AC_BK,
+                               .cw_min      = 15,
+                               .cw_max      = 63,
+                               .aifsn       = 7,
+                               .tx_op_limit = 0,
+                       },
+                       [CONF_TX_AC_VI] = {
+                               .ac          = CONF_TX_AC_VI,
+                               .cw_min      = 15,
+                               .cw_max      = 63,
+                               .aifsn       = CONF_TX_AIFS_PIFS,
+                               .tx_op_limit = 3008,
+                       },
+                       [CONF_TX_AC_VO] = {
+                               .ac          = CONF_TX_AC_VO,
+                               .cw_min      = 15,
+                               .cw_max      = 63,
+                               .aifsn       = CONF_TX_AIFS_PIFS,
+                               .tx_op_limit = 1504,
+                       },
+               },
+               .max_tx_retries = 100,
+               .ap_aging_period = 300,
+               .tid_conf_count = 4,
+               .tid_conf = {
+                       [CONF_TX_AC_BE] = {
+                               .queue_id    = CONF_TX_AC_BE,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_BE,
+                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
+                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
+                               .apsd_conf   = {0, 0},
+                       },
+                       [CONF_TX_AC_BK] = {
+                               .queue_id    = CONF_TX_AC_BK,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_BK,
+                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
+                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
+                               .apsd_conf   = {0, 0},
+                       },
+                       [CONF_TX_AC_VI] = {
+                               .queue_id    = CONF_TX_AC_VI,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_VI,
+                               .ps_scheme   = CONF_PS_SCHEME_LEGACY,
+                               .ack_policy  = CONF_ACK_POLICY_LEGACY,
+                               .apsd_conf   = {0, 0},
+                       },
+                       [CONF_TX_AC_VO] = {
+                               .queue_id    = CONF_TX_AC_VO,
+                               .channel_type = CONF_CHANNEL_TYPE_EDCF,
+                               .tsid        = CONF_TX_AC_VO,
+                               .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            = 350,
+               .tx_compl_threshold          = 10,
+               .basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
+               .basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
+               .tmpl_short_retry_limit      = 10,
+               .tmpl_long_retry_limit       = 10,
+               .tx_watchdog_timeout         = 5000,
+       },
+       .conn = {
+               .wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
+               .listen_interval             = 1,
+               .suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
+               .suspend_listen_interval     = 3,
+               .bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
+               .bcn_filt_ie_count           = 3,
+               .bcn_filt_ie = {
+                       [0] = {
+                               .ie          = WLAN_EID_CHANNEL_SWITCH,
+                               .rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
+                       },
+                       [1] = {
+                               .ie          = WLAN_EID_HT_OPERATION,
+                               .rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
+                       },
+                       [2] = {
+                               .ie          = WLAN_EID_ERP_INFO,
+                               .rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
+                       },
+               },
+               .synch_fail_thold            = 12,
+               .bss_lose_timeout            = 400,
+               .beacon_rx_timeout           = 10000,
+               .broadcast_timeout           = 20000,
+               .rx_broadcast_in_ps          = 1,
+               .ps_poll_threshold           = 10,
+               .bet_enable                  = CONF_BET_MODE_ENABLE,
+               .bet_max_consecutive         = 50,
+               .psm_entry_retries           = 8,
+               .psm_exit_retries            = 16,
+               .psm_entry_nullfunc_retries  = 3,
+               .dynamic_ps_timeout          = 200,
+               .forced_ps                   = false,
+               .keep_alive_interval         = 55000,
+               .max_listen_interval         = 20,
+               .sta_sleep_auth              = WL1271_PSM_ILLEGAL,
+       },
+       .itrim = {
+               .enable = false,
+               .timeout = 50000,
+       },
+       .pm_config = {
+               .host_clk_settling_time = 5000,
+               .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
+       },
+       .roam_trigger = {
+               .trigger_pacing               = 1,
+               .avg_weight_rssi_beacon       = 20,
+               .avg_weight_rssi_data         = 10,
+               .avg_weight_snr_beacon        = 20,
+               .avg_weight_snr_data          = 10,
+       },
+       .scan = {
+               .min_dwell_time_active        = 7500,
+               .max_dwell_time_active        = 30000,
+               .min_dwell_time_passive       = 100000,
+               .max_dwell_time_passive       = 100000,
+               .num_probe_reqs               = 2,
+               .split_scan_timeout           = 50000,
+       },
+       .sched_scan = {
+               /*
+                * Values are in TU/1000 but since sched scan FW command
+                * params are in TUs rounding up may occur.
+                */
+               .base_dwell_time                = 7500,
+               .max_dwell_time_delta           = 22500,
+               /* based on 250bits per probe @1Mbps */
+               .dwell_time_delta_per_probe     = 2000,
+               /* based on 250bits per probe @6Mbps (plus a bit more) */
+               .dwell_time_delta_per_probe_5   = 350,
+               .dwell_time_passive             = 100000,
+               .dwell_time_dfs                 = 150000,
+               .num_probe_reqs                 = 2,
+               .rssi_threshold                 = -90,
+               .snr_threshold                  = 0,
+       },
+       .ht = {
+               .rx_ba_win_size = 10,
+               .tx_ba_win_size = 64,
+               .inactivity_timeout = 10000,
+               .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
+       },
+       .mem = {
+               .num_stations                 = 1,
+               .ssid_profiles                = 1,
+               .rx_block_num                 = 40,
+               .tx_min_block_num             = 40,
+               .dynamic_memory               = 1,
+               .min_req_tx_blocks            = 45,
+               .min_req_rx_blocks            = 22,
+               .tx_min                       = 27,
+       },
+       .fm_coex = {
+               .enable                       = true,
+               .swallow_period               = 5,
+               .n_divider_fref_set_1         = 0xff,       /* default */
+               .n_divider_fref_set_2         = 12,
+               .m_divider_fref_set_1         = 0xffff,
+               .m_divider_fref_set_2         = 148,        /* default */
+               .coex_pll_stabilization_time  = 0xffffffff, /* default */
+               .ldo_stabilization_time       = 0xffff,     /* default */
+               .fm_disturbed_band_margin     = 0xff,       /* default */
+               .swallow_clk_diff             = 0xff,       /* default */
+       },
+       .rx_streaming = {
+               .duration                      = 150,
+               .queues                        = 0x1,
+               .interval                      = 20,
+               .always                        = 0,
+       },
+       .fwlog = {
+               .mode                         = WL12XX_FWLOG_ON_DEMAND,
+               .mem_blocks                   = 2,
+               .severity                     = 0,
+               .timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
+               .output                       = WL12XX_FWLOG_OUTPUT_HOST,
+               .threshold                    = 0,
+       },
+       .rate = {
+               .rate_retry_score = 32000,
+               .per_add = 8192,
+               .per_th1 = 2048,
+               .per_th2 = 4096,
+               .max_per = 8100,
+               .inverse_curiosity_factor = 5,
+               .tx_fail_low_th = 4,
+               .tx_fail_high_th = 10,
+               .per_alpha_shift = 4,
+               .per_add_shift = 13,
+               .per_beta1_shift = 10,
+               .per_beta2_shift = 8,
+               .rate_check_up = 2,
+               .rate_check_down = 12,
+               .rate_retry_policy = {
+                       0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00,
+               },
+       },
+       .hangover = {
+               .recover_time               = 0,
+               .hangover_period            = 20,
+               .dynamic_mode               = 1,
+               .early_termination_mode     = 1,
+               .max_period                 = 20,
+               .min_period                 = 1,
+               .increase_delta             = 1,
+               .decrease_delta             = 2,
+               .quiet_time                 = 4,
+               .increase_time              = 1,
+               .window_size                = 16,
+       },
+};
+
+static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
+       .phy = {
+               .phy_standalone                 = 0x00,
+               .primary_clock_setting_time     = 0x05,
+               .clock_valid_on_wake_up         = 0x00,
+               .secondary_clock_setting_time   = 0x05,
+               .rdl                            = 0x01,
+               .auto_detect                    = 0x00,
+               .dedicated_fem                  = FEM_NONE,
+               .low_band_component             = COMPONENT_2_WAY_SWITCH,
+               .low_band_component_type        = 0x05,
+               .high_band_component            = COMPONENT_2_WAY_SWITCH,
+               .high_band_component_type       = 0x09,
+               .tcxo_ldo_voltage               = 0x00,
+               .xtal_itrim_val                 = 0x04,
+               .srf_state                      = 0x00,
+               .io_configuration               = 0x01,
+               .sdio_configuration             = 0x00,
+               .settings                       = 0x00,
+               .enable_clpc                    = 0x00,
+               .enable_tx_low_pwr_on_siso_rdl  = 0x00,
+               .rx_profile                     = 0x00,
+               .pwr_limit_reference_11_abg     = 0xc8,
+               .psat                           = 0,
+               .low_power_val                  = 0x00,
+               .med_power_val                  = 0x0a,
+               .high_power_val                 = 0x1e,
+               .external_pa_dc2dc              = 0,
+               .number_of_assembled_ant2_4     = 1,
+               .number_of_assembled_ant5       = 1,
+       },
+};
+
+static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
+       [PART_TOP_PRCM_ELP_SOC] = {
+               .mem  = { .start = 0x00A02000, .size  = 0x00010000 },
+               .reg  = { .start = 0x00807000, .size  = 0x00005000 },
+               .mem2 = { .start = 0x00800000, .size  = 0x0000B000 },
+               .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+       },
+       [PART_DOWN] = {
+               .mem  = { .start = 0x00000000, .size  = 0x00014000 },
+               .reg  = { .start = 0x00810000, .size  = 0x0000BFFF },
+               .mem2 = { .start = 0x00000000, .size  = 0x00000000 },
+               .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+       },
+       [PART_BOOT] = {
+               .mem  = { .start = 0x00700000, .size = 0x0000030c },
+               .reg  = { .start = 0x00802000, .size = 0x00014578 },
+               .mem2 = { .start = 0x00B00404, .size = 0x00001000 },
+               .mem3 = { .start = 0x00C00000, .size = 0x00000400 },
+       },
+       [PART_WORK] = {
+               .mem  = { .start = 0x00800000, .size  = 0x000050FC },
+               .reg  = { .start = 0x00B00404, .size  = 0x00001000 },
+               .mem2 = { .start = 0x00C00000, .size  = 0x00000400 },
+               .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+       },
+       [PART_PHY_INIT] = {
+               .mem  = { .start = 0x80926000,
+                         .size = sizeof(struct wl18xx_mac_and_phy_params) },
+               .reg  = { .start = 0x00000000, .size = 0x00000000 },
+               .mem2 = { .start = 0x00000000, .size = 0x00000000 },
+               .mem3 = { .start = 0x00000000, .size = 0x00000000 },
+       },
+};
+
+static const int wl18xx_rtable[REG_TABLE_LEN] = {
+       [REG_ECPU_CONTROL]              = WL18XX_REG_ECPU_CONTROL,
+       [REG_INTERRUPT_NO_CLEAR]        = WL18XX_REG_INTERRUPT_NO_CLEAR,
+       [REG_INTERRUPT_ACK]             = WL18XX_REG_INTERRUPT_ACK,
+       [REG_COMMAND_MAILBOX_PTR]       = WL18XX_REG_COMMAND_MAILBOX_PTR,
+       [REG_EVENT_MAILBOX_PTR]         = WL18XX_REG_EVENT_MAILBOX_PTR,
+       [REG_INTERRUPT_TRIG]            = WL18XX_REG_INTERRUPT_TRIG_H,
+       [REG_INTERRUPT_MASK]            = WL18XX_REG_INTERRUPT_MASK,
+       [REG_PC_ON_RECOVERY]            = WL18XX_SCR_PAD4,
+       [REG_CHIP_ID_B]                 = WL18XX_REG_CHIP_ID_B,
+       [REG_CMD_MBOX_ADDRESS]          = WL18XX_CMD_MBOX_ADDRESS,
+
+       /* data access memory addresses, used with partition translation */
+       [REG_SLV_MEM_DATA]              = WL18XX_SLV_MEM_DATA,
+       [REG_SLV_REG_DATA]              = WL18XX_SLV_REG_DATA,
+
+       /* raw data access memory addresses */
+       [REG_RAW_FW_STATUS_ADDR]        = WL18XX_FW_STATUS_ADDR,
+};
+
+static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
+       [CLOCK_CONFIG_16_2_M]   = { 7,  104,  801, 4,  true },
+       [CLOCK_CONFIG_16_368_M] = { 9,  132, 3751, 4,  true },
+       [CLOCK_CONFIG_16_8_M]   = { 7,  100,    0, 0, false },
+       [CLOCK_CONFIG_19_2_M]   = { 8,  100,    0, 0, false },
+       [CLOCK_CONFIG_26_M]     = { 13, 120,    0, 0, false },
+       [CLOCK_CONFIG_32_736_M] = { 9,  132, 3751, 4,  true },
+       [CLOCK_CONFIG_33_6_M]   = { 7,  100,    0, 0, false },
+       [CLOCK_CONFIG_38_468_M] = { 8,  100,    0, 0, false },
+       [CLOCK_CONFIG_52_M]     = { 13, 120,    0, 0, false },
+};
+
+/* TODO: maybe move to a new header file? */
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin"
+
+static int wl18xx_identify_chip(struct wl1271 *wl)
+{
+       int ret = 0;
+
+       switch (wl->chip.id) {
+       case CHIP_ID_185x_PG20:
+               wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
+                                wl->chip.id);
+               wl->sr_fw_name = WL18XX_FW_NAME;
+               /* wl18xx uses the same firmware for PLT */
+               wl->plt_fw_name = WL18XX_FW_NAME;
+               wl->quirks |= WLCORE_QUIRK_NO_ELP |
+                             WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
+                             WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
+                             WLCORE_QUIRK_TX_PAD_LAST_FRAME;
+               break;
+       case CHIP_ID_185x_PG10:
+               wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
+                              wl->chip.id);
+               ret = -ENODEV;
+               goto out;
+
+       default:
+               wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
+               ret = -ENODEV;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static int wl18xx_set_clk(struct wl1271 *wl)
+{
+       u16 clk_freq;
+       int ret;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+       if (ret < 0)
+               goto out;
+
+       /* TODO: PG2: apparently we need to read the clk type */
+
+       ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq);
+       if (ret < 0)
+               goto out;
+
+       wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
+                    wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
+                    wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
+                    wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
+
+       ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
+                                  wl18xx_clk_table[clk_freq].n);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M,
+                                  wl18xx_clk_table[clk_freq].m);
+       if (ret < 0)
+               goto out;
+
+       if (wl18xx_clk_table[clk_freq].swallow) {
+               /* first the 16 lower bits */
+               ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
+                                          wl18xx_clk_table[clk_freq].q &
+                                          PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
+               if (ret < 0)
+                       goto out;
+
+               /* then the 16 higher bits, masked out */
+               ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
+                                       (wl18xx_clk_table[clk_freq].q >> 16) &
+                                       PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
+               if (ret < 0)
+                       goto out;
+
+               /* first the 16 lower bits */
+               ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
+                                          wl18xx_clk_table[clk_freq].p &
+                                          PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
+               if (ret < 0)
+                       goto out;
+
+               /* then the 16 higher bits, masked out */
+               ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
+                                       (wl18xx_clk_table[clk_freq].p >> 16) &
+                                       PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
+       } else {
+               ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
+                                          PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
+       }
+
+out:
+       return ret;
+}
+
+static int wl18xx_boot_soft_reset(struct wl1271 *wl)
+{
+       int ret;
+
+       /* disable Rx/Tx */
+       ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
+       if (ret < 0)
+               goto out;
+
+       /* disable auto calibration on start*/
+       ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff);
+
+out:
+       return ret;
+}
+
+static int wl18xx_pre_boot(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wl18xx_set_clk(wl);
+       if (ret < 0)
+               goto out;
+
+       /* Continue the ELP wake up sequence */
+       ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+       if (ret < 0)
+               goto out;
+
+       udelay(500);
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       if (ret < 0)
+               goto out;
+
+       /* Disable interrupts */
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_boot_soft_reset(wl);
+
+out:
+       return ret;
+}
+
+static int wl18xx_pre_upload(struct wl1271 *wl)
+{
+       u32 tmp;
+       int ret;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       if (ret < 0)
+               goto out;
+
+       /* TODO: check if this is all needed */
+       ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
+       if (ret < 0)
+               goto out;
+
+       wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
+
+       ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
+
+out:
+       return ret;
+}
+
+static int wl18xx_set_mac_and_phy(struct wl1271 *wl)
+{
+       struct wl18xx_priv *priv = wl->priv;
+       int ret;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy,
+                          sizeof(struct wl18xx_mac_and_phy_params), false);
+
+out:
+       return ret;
+}
+
+static int wl18xx_enable_interrupts(struct wl1271 *wl)
+{
+       u32 event_mask, intr_mask;
+       int ret;
+
+       event_mask = WL18XX_ACX_EVENTS_VECTOR;
+       intr_mask = WL18XX_INTR_MASK;
+
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
+       if (ret < 0)
+               goto out;
+
+       wlcore_enable_interrupts(wl);
+
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
+                              WL1271_ACX_INTR_ALL & ~intr_mask);
+
+out:
+       return ret;
+}
+
+static int wl18xx_boot(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wl18xx_pre_boot(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_pre_upload(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_boot_upload_firmware(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_set_mac_and_phy(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_boot_run_firmware(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_enable_interrupts(wl);
+
+out:
+       return ret;
+}
+
+static int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
+                              void *buf, size_t len)
+{
+       struct wl18xx_priv *priv = wl->priv;
+
+       memcpy(priv->cmd_buf, buf, len);
+       memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
+
+       return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
+                           WL18XX_CMD_MAX_SIZE, false);
+}
+
+static int wl18xx_ack_event(struct wl1271 *wl)
+{
+       return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
+                               WL18XX_INTR_TRIG_EVENT_ACK);
+}
+
+static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
+{
+       u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE;
+       return (len + blk_size - 1) / blk_size + spare_blks;
+}
+
+static void
+wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
+                         u32 blks, u32 spare_blks)
+{
+       desc->wl18xx_mem.total_mem_blocks = blks;
+}
+
+static void
+wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
+                           struct sk_buff *skb)
+{
+       desc->length = cpu_to_le16(skb->len);
+
+       /* if only the last frame is to be padded, we unset this bit on Tx */
+       if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
+               desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
+       else
+               desc->wl18xx_mem.ctrl = 0;
+
+       wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
+                    "len: %d life: %d mem: %d", desc->hlid,
+                    le16_to_cpu(desc->length),
+                    le16_to_cpu(desc->life_time),
+                    desc->wl18xx_mem.total_mem_blocks);
+}
+
+static enum wl_rx_buf_align
+wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
+{
+       if (rx_desc & RX_BUF_PADDED_PAYLOAD)
+               return WLCORE_RX_BUF_PADDED;
+
+       return WLCORE_RX_BUF_ALIGNED;
+}
+
+static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
+                                   u32 data_len)
+{
+       struct wl1271_rx_descriptor *desc = rx_data;
+
+       /* invalid packet */
+       if (data_len < sizeof(*desc))
+               return 0;
+
+       return data_len - sizeof(*desc);
+}
+
+static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
+{
+       wl18xx_tx_immediate_complete(wl);
+}
+
+static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
+{
+       int ret;
+       u32 sdio_align_size = 0;
+       u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
+                             HOST_IF_CFG_ADD_RX_ALIGNMENT;
+
+       /* Enable Tx SDIO padding */
+       if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
+               host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
+               sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
+       }
+
+       /* Enable Rx SDIO padding */
+       if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) {
+               host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK;
+               sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
+       }
+
+       ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
+                                           sdio_align_size, extra_mem_blk,
+                                           WL18XX_HOST_IF_LEN_SIZE_FIELD);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int wl18xx_hw_init(struct wl1271 *wl)
+{
+       int ret;
+       struct wl18xx_priv *priv = wl->priv;
+
+       /* (re)init private structures. Relevant on recovery as well. */
+       priv->last_fw_rls_idx = 0;
+       priv->extra_spare_vif_count = 0;
+
+       /* set the default amount of spare blocks in the bitmap */
+       ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
+       if (ret < 0)
+               return ret;
+
+       if (checksum_param) {
+               ret = wl18xx_acx_set_checksum_state(wl);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
+                                   struct wl1271_tx_hw_descr *desc,
+                                   struct sk_buff *skb)
+{
+       u32 ip_hdr_offset;
+       struct iphdr *ip_hdr;
+
+       if (!checksum_param) {
+               desc->wl18xx_checksum_data = 0;
+               return;
+       }
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
+               desc->wl18xx_checksum_data = 0;
+               return;
+       }
+
+       ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
+       if (WARN_ON(ip_hdr_offset >= (1<<7))) {
+               desc->wl18xx_checksum_data = 0;
+               return;
+       }
+
+       desc->wl18xx_checksum_data = ip_hdr_offset << 1;
+
+       /* FW is interested only in the LSB of the protocol  TCP=0 UDP=1 */
+       ip_hdr = (void *)skb_network_header(skb);
+       desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
+}
+
+static void wl18xx_set_rx_csum(struct wl1271 *wl,
+                              struct wl1271_rx_descriptor *desc,
+                              struct sk_buff *skb)
+{
+       if (desc->status & WL18XX_RX_CHECKSUM_MASK)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
+/*
+ * TODO: instead of having these two functions to get the rate mask,
+ * we should modify the wlvif->rate_set instead
+ */
+static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl,
+                                      struct wl12xx_vif *wlvif)
+{
+       u32 hw_rate_set = wlvif->rate_set;
+
+       if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+           wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
+               wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
+               hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN;
+
+               /* we don't support MIMO in wide-channel mode */
+               hw_rate_set &= ~CONF_TX_MIMO_RATES;
+       }
+
+       return hw_rate_set;
+}
+
+static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
+                                            struct wl12xx_vif *wlvif)
+{
+       if ((wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
+            wlvif->channel_type == NL80211_CHAN_HT40PLUS) &&
+           !strcmp(ht_mode_param, "wide")) {
+               wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
+               return CONF_TX_RATE_USE_WIDE_CHAN;
+       } else if (!strcmp(ht_mode_param, "mimo")) {
+               wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
+
+               return CONF_TX_MIMO_RATES;
+       } else {
+               return 0;
+       }
+}
+
+static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
+{
+       u32 fuse;
+       int ret;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
+       if (ret < 0)
+               goto out;
+
+       if (ver)
+               *ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+
+out:
+       return ret;
+}
+
+#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
+static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
+{
+       struct wl18xx_priv *priv = wl->priv;
+       struct wlcore_conf_file *conf_file;
+       const struct firmware *fw;
+       int ret;
+
+       ret = request_firmware(&fw, WL18XX_CONF_FILE_NAME, dev);
+       if (ret < 0) {
+               wl1271_error("could not get configuration binary %s: %d",
+                            WL18XX_CONF_FILE_NAME, ret);
+               goto out_fallback;
+       }
+
+       if (fw->size != WL18XX_CONF_SIZE) {
+               wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
+                            WL18XX_CONF_SIZE, fw->size);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       conf_file = (struct wlcore_conf_file *) fw->data;
+
+       if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) {
+               wl1271_error("configuration binary file magic number mismatch, "
+                            "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
+                            conf_file->header.magic);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
+               wl1271_error("configuration binary file version not supported, "
+                            "expected 0x%08x got 0x%08x",
+                            WL18XX_CONF_VERSION, conf_file->header.version);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf));
+       memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf));
+
+       goto out;
+
+out_fallback:
+       wl1271_warning("falling back to default config");
+
+       /* apply driver default configuration */
+       memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf));
+       /* apply default private configuration */
+       memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf));
+
+       /* For now we just fallback */
+       return 0;
+
+out:
+       release_firmware(fw);
+       return ret;
+}
+
+static int wl18xx_plt_init(struct wl1271 *wl)
+{
+       int ret;
+
+       ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
+       if (ret < 0)
+               return ret;
+
+       return wl->ops->boot(wl);
+}
+
+static int wl18xx_get_mac(struct wl1271 *wl)
+{
+       u32 mac1, mac2;
+       int ret;
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2);
+       if (ret < 0)
+               goto out;
+
+       /* these are the two parts of the BD_ADDR */
+       wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
+               ((mac1 & 0xff000000) >> 24);
+       wl->fuse_nic_addr = (mac1 & 0xffffff);
+
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
+
+out:
+       return ret;
+}
+
+static int wl18xx_handle_static_data(struct wl1271 *wl,
+                                    struct wl1271_static_data *static_data)
+{
+       struct wl18xx_static_data_priv *static_data_priv =
+               (struct wl18xx_static_data_priv *) static_data->priv;
+
+       wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
+
+       return 0;
+}
+
+static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+       struct wl18xx_priv *priv = wl->priv;
+
+       /* If we have VIFs requiring extra spare, indulge them */
+       if (priv->extra_spare_vif_count)
+               return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
+
+       return WL18XX_TX_HW_BLOCK_SPARE;
+}
+
+static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_sta *sta,
+                         struct ieee80211_key_conf *key_conf)
+{
+       struct wl18xx_priv *priv = wl->priv;
+       bool change_spare = false;
+       int ret;
+
+       /*
+        * when adding the first or removing the last GEM/TKIP interface,
+        * we have to adjust the number of spare blocks.
+        */
+       change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
+               key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
+               ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
+                (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
+
+       /* no need to change spare - just regular set_key */
+       if (!change_spare)
+               return wlcore_set_key(wl, cmd, vif, sta, key_conf);
+
+       /*
+        * stop the queues and flush to ensure the next packets are
+        * in sync with FW spare block accounting
+        */
+       wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
+       wl1271_tx_flush(wl);
+
+       ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
+       if (ret < 0)
+               goto out;
+
+       /* key is now set, change the spare blocks */
+       if (cmd == SET_KEY) {
+               ret = wl18xx_set_host_cfg_bitmap(wl,
+                                       WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
+               if (ret < 0)
+                       goto out;
+
+               priv->extra_spare_vif_count++;
+       } else {
+               ret = wl18xx_set_host_cfg_bitmap(wl,
+                                       WL18XX_TX_HW_BLOCK_SPARE);
+               if (ret < 0)
+                       goto out;
+
+               priv->extra_spare_vif_count--;
+       }
+
+out:
+       wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
+       return ret;
+}
+
+static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
+                              u32 buf_offset, u32 last_len)
+{
+       if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
+               struct wl1271_tx_hw_descr *last_desc;
+
+               /* get the last TX HW descriptor written to the aggr buf */
+               last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
+                                                       buf_offset - last_len);
+
+               /* the last frame is padded up to an SDIO block */
+               last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
+               return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
+       }
+
+       /* no modifications */
+       return buf_offset;
+}
+
+static struct wlcore_ops wl18xx_ops = {
+       .identify_chip  = wl18xx_identify_chip,
+       .boot           = wl18xx_boot,
+       .plt_init       = wl18xx_plt_init,
+       .trigger_cmd    = wl18xx_trigger_cmd,
+       .ack_event      = wl18xx_ack_event,
+       .calc_tx_blocks = wl18xx_calc_tx_blocks,
+       .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
+       .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
+       .get_rx_buf_align = wl18xx_get_rx_buf_align,
+       .get_rx_packet_len = wl18xx_get_rx_packet_len,
+       .tx_immediate_compl = wl18xx_tx_immediate_completion,
+       .tx_delayed_compl = NULL,
+       .hw_init        = wl18xx_hw_init,
+       .set_tx_desc_csum = wl18xx_set_tx_desc_csum,
+       .get_pg_ver     = wl18xx_get_pg_ver,
+       .set_rx_csum = wl18xx_set_rx_csum,
+       .sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask,
+       .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
+       .get_mac        = wl18xx_get_mac,
+       .debugfs_init   = wl18xx_debugfs_add_files,
+       .handle_static_data     = wl18xx_handle_static_data,
+       .get_spare_blocks = wl18xx_get_spare_blocks,
+       .set_key        = wl18xx_set_key,
+       .pre_pkt_send   = wl18xx_pre_pkt_send,
+};
+
+/* HT cap appropriate for wide channels in 2Ghz */
+static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
+       .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
+              IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40,
+       .ht_supported = true,
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+       .mcs = {
+               .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+               .rx_highest = cpu_to_le16(150),
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               },
+};
+
+/* HT cap appropriate for wide channels in 5Ghz */
+static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
+       .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
+              IEEE80211_HT_CAP_SUP_WIDTH_20_40,
+       .ht_supported = true,
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+       .mcs = {
+               .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+               .rx_highest = cpu_to_le16(150),
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               },
+};
+
+/* HT cap appropriate for SISO 20 */
+static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
+       .cap = IEEE80211_HT_CAP_SGI_20,
+       .ht_supported = true,
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+       .mcs = {
+               .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+               .rx_highest = cpu_to_le16(72),
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               },
+};
+
+/* HT cap appropriate for MIMO rates in 20mhz channel */
+static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
+       .cap = IEEE80211_HT_CAP_SGI_20,
+       .ht_supported = true,
+       .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
+       .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+       .mcs = {
+               .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, },
+               .rx_highest = cpu_to_le16(144),
+               .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               },
+};
+
+static int __devinit wl18xx_probe(struct platform_device *pdev)
+{
+       struct wl1271 *wl;
+       struct ieee80211_hw *hw;
+       struct wl18xx_priv *priv;
+       int ret;
+
+       hw = wlcore_alloc_hw(sizeof(*priv));
+       if (IS_ERR(hw)) {
+               wl1271_error("can't allocate hw");
+               ret = PTR_ERR(hw);
+               goto out;
+       }
+
+       wl = hw->priv;
+       priv = wl->priv;
+       wl->ops = &wl18xx_ops;
+       wl->ptable = wl18xx_ptable;
+       wl->rtable = wl18xx_rtable;
+       wl->num_tx_desc = 32;
+       wl->num_rx_desc = 32;
+       wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
+       wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
+       wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
+       wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
+       wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
+       wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
+
+       if (num_rx_desc_param != -1)
+               wl->num_rx_desc = num_rx_desc_param;
+
+       ret = wl18xx_conf_init(wl, &pdev->dev);
+       if (ret < 0)
+               goto out_free;
+
+       if (!strcmp(board_type_param, "fpga")) {
+               priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX;
+       } else if (!strcmp(board_type_param, "hdk")) {
+               priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX;
+               /* HACK! Just for now we hardcode HDK to 0x06 */
+               priv->conf.phy.low_band_component_type = 0x06;
+       } else if (!strcmp(board_type_param, "dvp")) {
+               priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX;
+       } else if (!strcmp(board_type_param, "evb")) {
+               priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX;
+       } else if (!strcmp(board_type_param, "com8")) {
+               priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX;
+               /* HACK! Just for now we hardcode COM8 to 0x06 */
+               priv->conf.phy.low_band_component_type = 0x06;
+       } else {
+               wl1271_error("invalid board type '%s'", board_type_param);
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       /* If the module param is set, update it in conf */
+       if (low_band_component_param != -1)
+               priv->conf.phy.low_band_component = low_band_component_param;
+       if (low_band_component_type_param != -1)
+               priv->conf.phy.low_band_component_type =
+                       low_band_component_type_param;
+       if (high_band_component_param != -1)
+               priv->conf.phy.high_band_component = high_band_component_param;
+       if (high_band_component_type_param != -1)
+               priv->conf.phy.high_band_component_type =
+                       high_band_component_type_param;
+       if (pwr_limit_reference_11_abg_param != -1)
+               priv->conf.phy.pwr_limit_reference_11_abg =
+                       pwr_limit_reference_11_abg_param;
+       if (n_antennas_2_param != -1)
+               priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param;
+       if (n_antennas_5_param != -1)
+               priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param;
+       if (dc2dc_param != -1)
+               priv->conf.phy.external_pa_dc2dc = dc2dc_param;
+
+       if (!strcmp(ht_mode_param, "default")) {
+               /*
+                * Only support mimo with multiple antennas. Fall back to
+                * siso20.
+                */
+               if (priv->conf.phy.number_of_assembled_ant2_4 >= 2)
+                       wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+                                         &wl18xx_mimo_ht_cap_2ghz);
+               else
+                       wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+                                         &wl18xx_siso20_ht_cap);
+
+               /* 5Ghz is always wide */
+               wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+                                 &wl18xx_siso40_ht_cap_5ghz);
+       } else if (!strcmp(ht_mode_param, "wide")) {
+               wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+                                 &wl18xx_siso40_ht_cap_2ghz);
+               wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+                                 &wl18xx_siso40_ht_cap_5ghz);
+       } else if (!strcmp(ht_mode_param, "siso20")) {
+               wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
+                                 &wl18xx_siso20_ht_cap);
+               wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
+                                 &wl18xx_siso20_ht_cap);
+       } else {
+               wl1271_error("invalid ht_mode '%s'", ht_mode_param);
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       if (!checksum_param) {
+               wl18xx_ops.set_rx_csum = NULL;
+               wl18xx_ops.init_vif = NULL;
+       }
+
+       wl->enable_11a = enable_11a_param;
+
+       return wlcore_probe(wl, pdev);
+
+out_free:
+       wlcore_free_hw(wl);
+out:
+       return ret;
+}
+
+static const struct platform_device_id wl18xx_id_table[] __devinitconst = {
+       { "wl18xx", 0 },
+       {  } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, wl18xx_id_table);
+
+static struct platform_driver wl18xx_driver = {
+       .probe          = wl18xx_probe,
+       .remove         = __devexit_p(wlcore_remove),
+       .id_table       = wl18xx_id_table,
+       .driver = {
+               .name   = "wl18xx_driver",
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init wl18xx_init(void)
+{
+       return platform_driver_register(&wl18xx_driver);
+}
+module_init(wl18xx_init);
+
+static void __exit wl18xx_exit(void)
+{
+       platform_driver_unregister(&wl18xx_driver);
+}
+module_exit(wl18xx_exit);
+
+module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
+MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
+
+module_param_named(board_type, board_type_param, charp, S_IRUSR);
+MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
+                "dvp");
+
+module_param_named(checksum, checksum_param, bool, S_IRUSR);
+MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
+
+module_param_named(enable_11a, enable_11a_param, bool, S_IRUSR);
+MODULE_PARM_DESC(enable_11a, "Enable 11a (5GHz): boolean (defaults to true)");
+
+module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
+MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
+
+module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR);
+MODULE_PARM_DESC(n_antennas_2,
+                "Number of installed 2.4GHz antennas: 1 (default) or 2");
+
+module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR);
+MODULE_PARM_DESC(n_antennas_5,
+                "Number of installed 5GHz antennas: 1 (default) or 2");
+
+module_param_named(low_band_component, low_band_component_param, int,
+                  S_IRUSR);
+MODULE_PARM_DESC(low_band_component, "Low band component: u8 "
+                "(default is 0x01)");
+
+module_param_named(low_band_component_type, low_band_component_type_param,
+                  int, S_IRUSR);
+MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
+                "(default is 0x05 or 0x06 depending on the board_type)");
+
+module_param_named(high_band_component, high_band_component_param, int,
+                  S_IRUSR);
+MODULE_PARM_DESC(high_band_component, "High band component: u8, "
+                "(default is 0x01)");
+
+module_param_named(high_band_component_type, high_band_component_type_param,
+                  int, S_IRUSR);
+MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
+                "(default is 0x09)");
+
+module_param_named(pwr_limit_reference_11_abg,
+                  pwr_limit_reference_11_abg_param, int, S_IRUSR);
+MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
+                "(default is 0xc8)");
+
+module_param_named(num_rx_desc,
+                  num_rx_desc_param, int, S_IRUSR);
+MODULE_PARM_DESC(num_rx_desc_param,
+                "Number of Rx descriptors: u8 (default is 32)");
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
+MODULE_FIRMWARE(WL18XX_FW_NAME);
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
new file mode 100644 (file)
index 0000000..937b71d
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * This file is part of wlcore
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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 __REG_H__
+#define __REG_H__
+
+#define WL18XX_REGISTERS_BASE      0x00800000
+#define WL18XX_CODE_BASE           0x00000000
+#define WL18XX_DATA_BASE           0x00400000
+#define WL18XX_DOUBLE_BUFFER_BASE  0x00600000
+#define WL18XX_MCU_KEY_SEARCH_BASE 0x00700000
+#define WL18XX_PHY_BASE            0x00900000
+#define WL18XX_TOP_OCP_BASE        0x00A00000
+#define WL18XX_PACKET_RAM_BASE     0x00B00000
+#define WL18XX_HOST_BASE           0x00C00000
+
+#define WL18XX_REGISTERS_DOWN_SIZE 0x0000B000
+
+#define WL18XX_REG_BOOT_PART_START 0x00802000
+#define WL18XX_REG_BOOT_PART_SIZE  0x00014578
+
+#define WL18XX_PHY_INIT_MEM_ADDR   0x80926000
+
+#define WL18XX_SDIO_WSPI_BASE          (WL18XX_REGISTERS_BASE)
+#define WL18XX_REG_CONFIG_BASE         (WL18XX_REGISTERS_BASE + 0x02000)
+#define WL18XX_WGCM_REGS_BASE          (WL18XX_REGISTERS_BASE + 0x03000)
+#define WL18XX_ENC_BASE                        (WL18XX_REGISTERS_BASE + 0x04000)
+#define WL18XX_INTERRUPT_BASE          (WL18XX_REGISTERS_BASE + 0x05000)
+#define WL18XX_UART_BASE               (WL18XX_REGISTERS_BASE + 0x06000)
+#define WL18XX_WELP_BASE               (WL18XX_REGISTERS_BASE + 0x07000)
+#define WL18XX_TCP_CKSM_BASE           (WL18XX_REGISTERS_BASE + 0x08000)
+#define WL18XX_FIFO_BASE               (WL18XX_REGISTERS_BASE + 0x09000)
+#define WL18XX_OCP_BRIDGE_BASE         (WL18XX_REGISTERS_BASE + 0x0A000)
+#define WL18XX_PMAC_RX_BASE            (WL18XX_REGISTERS_BASE + 0x14800)
+#define WL18XX_PMAC_ACM_BASE           (WL18XX_REGISTERS_BASE + 0x14C00)
+#define WL18XX_PMAC_TX_BASE            (WL18XX_REGISTERS_BASE + 0x15000)
+#define WL18XX_PMAC_CSR_BASE           (WL18XX_REGISTERS_BASE + 0x15400)
+
+#define WL18XX_REG_ECPU_CONTROL                (WL18XX_REGISTERS_BASE + 0x02004)
+#define WL18XX_REG_INTERRUPT_NO_CLEAR  (WL18XX_REGISTERS_BASE + 0x050E8)
+#define WL18XX_REG_INTERRUPT_ACK       (WL18XX_REGISTERS_BASE + 0x050F0)
+#define WL18XX_REG_INTERRUPT_TRIG      (WL18XX_REGISTERS_BASE + 0x5074)
+#define WL18XX_REG_INTERRUPT_TRIG_H    (WL18XX_REGISTERS_BASE + 0x5078)
+#define WL18XX_REG_INTERRUPT_MASK      (WL18XX_REGISTERS_BASE + 0x0050DC)
+
+#define WL18XX_REG_CHIP_ID_B           (WL18XX_REGISTERS_BASE + 0x01542C)
+
+#define WL18XX_SLV_MEM_DATA            (WL18XX_HOST_BASE + 0x0018)
+#define WL18XX_SLV_REG_DATA            (WL18XX_HOST_BASE + 0x0008)
+
+/* Scratch Pad registers*/
+#define WL18XX_SCR_PAD0                        (WL18XX_REGISTERS_BASE + 0x0154EC)
+#define WL18XX_SCR_PAD1                        (WL18XX_REGISTERS_BASE + 0x0154F0)
+#define WL18XX_SCR_PAD2                        (WL18XX_REGISTERS_BASE + 0x0154F4)
+#define WL18XX_SCR_PAD3                        (WL18XX_REGISTERS_BASE + 0x0154F8)
+#define WL18XX_SCR_PAD4                        (WL18XX_REGISTERS_BASE + 0x0154FC)
+#define WL18XX_SCR_PAD4_SET            (WL18XX_REGISTERS_BASE + 0x015504)
+#define WL18XX_SCR_PAD4_CLR            (WL18XX_REGISTERS_BASE + 0x015500)
+#define WL18XX_SCR_PAD5                        (WL18XX_REGISTERS_BASE + 0x015508)
+#define WL18XX_SCR_PAD5_SET            (WL18XX_REGISTERS_BASE + 0x015510)
+#define WL18XX_SCR_PAD5_CLR            (WL18XX_REGISTERS_BASE + 0x01550C)
+#define WL18XX_SCR_PAD6                        (WL18XX_REGISTERS_BASE + 0x015514)
+#define WL18XX_SCR_PAD7                        (WL18XX_REGISTERS_BASE + 0x015518)
+#define WL18XX_SCR_PAD8                        (WL18XX_REGISTERS_BASE + 0x01551C)
+#define WL18XX_SCR_PAD9                        (WL18XX_REGISTERS_BASE + 0x015520)
+
+/* Spare registers*/
+#define WL18XX_SPARE_A1                        (WL18XX_REGISTERS_BASE + 0x002194)
+#define WL18XX_SPARE_A2                        (WL18XX_REGISTERS_BASE + 0x002198)
+#define WL18XX_SPARE_A3                        (WL18XX_REGISTERS_BASE + 0x00219C)
+#define WL18XX_SPARE_A4                        (WL18XX_REGISTERS_BASE + 0x0021A0)
+#define WL18XX_SPARE_A5                        (WL18XX_REGISTERS_BASE + 0x0021A4)
+#define WL18XX_SPARE_A6                        (WL18XX_REGISTERS_BASE + 0x0021A8)
+#define WL18XX_SPARE_A7                        (WL18XX_REGISTERS_BASE + 0x0021AC)
+#define WL18XX_SPARE_A8                        (WL18XX_REGISTERS_BASE + 0x0021B0)
+#define WL18XX_SPARE_B1                        (WL18XX_REGISTERS_BASE + 0x015524)
+#define WL18XX_SPARE_B2                        (WL18XX_REGISTERS_BASE + 0x015528)
+#define WL18XX_SPARE_B3                        (WL18XX_REGISTERS_BASE + 0x01552C)
+#define WL18XX_SPARE_B4                        (WL18XX_REGISTERS_BASE + 0x015530)
+#define WL18XX_SPARE_B5                        (WL18XX_REGISTERS_BASE + 0x015534)
+#define WL18XX_SPARE_B6                        (WL18XX_REGISTERS_BASE + 0x015538)
+#define WL18XX_SPARE_B7                        (WL18XX_REGISTERS_BASE + 0x01553C)
+#define WL18XX_SPARE_B8                        (WL18XX_REGISTERS_BASE + 0x015540)
+
+#define WL18XX_REG_COMMAND_MAILBOX_PTR (WL18XX_SCR_PAD0)
+#define WL18XX_REG_EVENT_MAILBOX_PTR   (WL18XX_SCR_PAD1)
+#define WL18XX_EEPROMLESS_IND          (WL18XX_SCR_PAD4)
+
+#define WL18XX_WELP_ARM_COMMAND                (WL18XX_REGISTERS_BASE + 0x7100)
+#define WL18XX_ENABLE                  (WL18XX_REGISTERS_BASE + 0x01543C)
+
+/* PRCM registers */
+#define PLATFORM_DETECTION             0xA0E3E0
+#define OCS_EN                         0xA02080
+#define PRIMARY_CLK_DETECT             0xA020A6
+#define PLLSH_WCS_PLL_N                        0xA02362
+#define PLLSH_WCS_PLL_M                        0xA02360
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1   0xA02364
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2   0xA02366
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_1   0xA02368
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_2   0xA0236A
+#define PLLSH_WCS_PLL_SWALLOW_EN       0xA0236C
+#define PLLSH_WL_PLL_EN                        0xA02392
+
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK      0xFFFF
+#define PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK      0x007F
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK      0xFFFF
+#define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK      0x000F
+
+#define PLLSH_WCS_PLL_SWALLOW_EN_VAL1  0x1
+#define PLLSH_WCS_PLL_SWALLOW_EN_VAL2  0x12
+
+#define WL18XX_REG_FUSE_DATA_1_3       0xA0260C
+#define WL18XX_PG_VER_MASK             0x70
+#define WL18XX_PG_VER_OFFSET           4
+
+#define WL18XX_REG_FUSE_BD_ADDR_1      0xA02602
+#define WL18XX_REG_FUSE_BD_ADDR_2      0xA02606
+
+#define WL18XX_CMD_MBOX_ADDRESS                0xB007B4
+
+#define WL18XX_FW_STATUS_ADDR          0x50F8
+
+#define CHIP_ID_185x_PG10              (0x06030101)
+#define CHIP_ID_185x_PG20              (0x06030111)
+
+/*
+ * Host Command Interrupt. Setting this bit masks
+ * the interrupt that the host issues to inform
+ * the FW that it has sent a command
+ * to the Wlan hardware Command Mailbox.
+ */
+#define WL18XX_INTR_TRIG_CMD       BIT(28)
+
+/*
+ * Host Event Acknowlegde Interrupt. The host
+ * sets this bit to acknowledge that it received
+ * the unsolicited information from the event
+ * mailbox.
+ */
+#define WL18XX_INTR_TRIG_EVENT_ACK BIT(29)
+
+/*
+ * To boot the firmware in PLT mode we need to write this value in
+ * SCR_PAD8 before starting.
+ */
+#define WL18XX_SCR_PAD8_PLT    0xBABABEBE
+
+enum {
+       COMPONENT_NO_SWITCH     = 0x0,
+       COMPONENT_2_WAY_SWITCH  = 0x1,
+       COMPONENT_3_WAY_SWITCH  = 0x2,
+       COMPONENT_MATCHING      = 0x3,
+};
+
+enum {
+       FEM_NONE        = 0x0,
+       FEM_VENDOR_1    = 0x1,
+       FEM_VENDOR_2    = 0x2,
+       FEM_VENDOR_3    = 0x3,
+};
+
+enum {
+       BOARD_TYPE_EVB_18XX     = 0,
+       BOARD_TYPE_DVP_18XX     = 1,
+       BOARD_TYPE_HDK_18XX     = 2,
+       BOARD_TYPE_FPGA_18XX    = 3,
+       BOARD_TYPE_COM8_18XX    = 4,
+
+       NUM_BOARD_TYPES,
+};
+
+#endif /* __REG_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/tx.c b/drivers/net/wireless/ti/wl18xx/tx.c
new file mode 100644 (file)
index 0000000..5b1fb10
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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
+ *
+ */
+
+#include "../wlcore/wlcore.h"
+#include "../wlcore/cmd.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/acx.h"
+#include "../wlcore/tx.h"
+
+#include "wl18xx.h"
+#include "tx.h"
+
+static void wl18xx_tx_complete_packet(struct wl1271 *wl, u8 tx_stat_byte)
+{
+       struct ieee80211_tx_info *info;
+       struct sk_buff *skb;
+       int id = tx_stat_byte & WL18XX_TX_STATUS_DESC_ID_MASK;
+       bool tx_success;
+
+       /* check for id legality */
+       if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
+               wl1271_warning("illegal id in tx completion: %d", id);
+               return;
+       }
+
+       /* a zero bit indicates Tx success */
+       tx_success = !(tx_stat_byte & BIT(WL18XX_TX_STATUS_STAT_BIT_IDX));
+
+
+       skb = wl->tx_frames[id];
+       info = IEEE80211_SKB_CB(skb);
+
+       if (wl12xx_is_dummy_packet(wl, skb)) {
+               wl1271_free_tx_id(wl, id);
+               return;
+       }
+
+       /* update the TX status info */
+       if (tx_success && !(info->flags & IEEE80211_TX_CTL_NO_ACK))
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
+       /* no real data about Tx completion */
+       info->status.rates[0].idx = -1;
+       info->status.rates[0].count = 0;
+       info->status.rates[0].flags = 0;
+       info->status.ack_signal = -1;
+
+       if (!tx_success)
+               wl->stats.retry_count++;
+
+       /*
+        * TODO: update sequence number for encryption? seems to be
+        * unsupported for now. needed for recovery with encryption.
+        */
+
+       /* remove private header from packet */
+       skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
+       /* remove TKIP header space if present */
+       if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+           info->control.hw_key &&
+           info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+               int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+               memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, hdrlen);
+               skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
+       }
+
+       wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p success %d",
+                    id, skb, tx_success);
+
+       /* return the packet to the stack */
+       skb_queue_tail(&wl->deferred_tx_queue, skb);
+       queue_work(wl->freezable_wq, &wl->netstack_work);
+       wl1271_free_tx_id(wl, id);
+}
+
+void wl18xx_tx_immediate_complete(struct wl1271 *wl)
+{
+       struct wl18xx_fw_status_priv *status_priv =
+               (struct wl18xx_fw_status_priv *)wl->fw_status_2->priv;
+       struct wl18xx_priv *priv = wl->priv;
+       u8 i;
+
+       /* nothing to do here */
+       if (priv->last_fw_rls_idx == status_priv->fw_release_idx)
+               return;
+
+       /* freed Tx descriptors */
+       wl1271_debug(DEBUG_TX, "last released desc = %d, current idx = %d",
+                    priv->last_fw_rls_idx, status_priv->fw_release_idx);
+
+       if (status_priv->fw_release_idx >= WL18XX_FW_MAX_TX_STATUS_DESC) {
+               wl1271_error("invalid desc release index %d",
+                            status_priv->fw_release_idx);
+               WARN_ON(1);
+               return;
+       }
+
+       for (i = priv->last_fw_rls_idx;
+            i != status_priv->fw_release_idx;
+            i = (i + 1) % WL18XX_FW_MAX_TX_STATUS_DESC) {
+               wl18xx_tx_complete_packet(wl,
+                       status_priv->released_tx_desc[i]);
+
+               wl->tx_results_count++;
+       }
+
+       priv->last_fw_rls_idx = status_priv->fw_release_idx;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/tx.h b/drivers/net/wireless/ti/wl18xx/tx.h
new file mode 100644 (file)
index 0000000..ccddc54
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments. All rights reserved.
+ *
+ * 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 __WL18XX_TX_H__
+#define __WL18XX_TX_H__
+
+#include "../wlcore/wlcore.h"
+
+#define WL18XX_TX_HW_BLOCK_SPARE        1
+/* for special cases - namely, TKIP and GEM */
+#define WL18XX_TX_HW_EXTRA_BLOCK_SPARE  2
+#define WL18XX_TX_HW_BLOCK_SIZE         268
+
+#define WL18XX_TX_STATUS_DESC_ID_MASK    0x7F
+#define WL18XX_TX_STATUS_STAT_BIT_IDX    7
+
+/* Indicates this TX HW frame is not padded to SDIO block size */
+#define WL18XX_TX_CTRL_NOT_PADDED      BIT(7)
+
+/*
+ * The FW uses a special bit to indicate a wide channel should be used in
+ * the rate policy.
+ */
+#define CONF_TX_RATE_USE_WIDE_CHAN BIT(31)
+
+void wl18xx_tx_immediate_complete(struct wl1271 *wl);
+
+#endif /* __WL12XX_TX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
new file mode 100644 (file)
index 0000000..bc67a47
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file is part of wl18xx
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.
+ *
+ * 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 __WL18XX_PRIV_H__
+#define __WL18XX_PRIV_H__
+
+#include "conf.h"
+
+#define WL18XX_CMD_MAX_SIZE          740
+
+struct wl18xx_priv {
+       /* buffer for sending commands to FW */
+       u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
+
+       struct wl18xx_priv_conf conf;
+
+       /* Index of last released Tx desc in FW */
+       u8 last_fw_rls_idx;
+
+       /* number of VIFs requiring extra spare mem-blocks */
+       int extra_spare_vif_count;
+};
+
+#define WL18XX_FW_MAX_TX_STATUS_DESC 33
+
+struct wl18xx_fw_status_priv {
+       /*
+        * Index in released_tx_desc for first byte that holds
+        * released tx host desc
+        */
+       u8 fw_release_idx;
+
+       /*
+        * Array of host Tx descriptors, where fw_release_idx
+        * indicated the first released idx.
+        */
+       u8 released_tx_desc[WL18XX_FW_MAX_TX_STATUS_DESC];
+
+       u8 padding[2];
+};
+
+#define WL18XX_PHY_VERSION_MAX_LEN 20
+
+struct wl18xx_static_data_priv {
+       char phy_version[WL18XX_PHY_VERSION_MAX_LEN];
+};
+
+struct wl18xx_clk_cfg {
+       u32 n;
+       u32 m;
+       u32 p;
+       u32 q;
+       bool swallow;
+};
+
+enum {
+       CLOCK_CONFIG_16_2_M     = 1,
+       CLOCK_CONFIG_16_368_M,
+       CLOCK_CONFIG_16_8_M,
+       CLOCK_CONFIG_19_2_M,
+       CLOCK_CONFIG_26_M,
+       CLOCK_CONFIG_32_736_M,
+       CLOCK_CONFIG_33_6_M,
+       CLOCK_CONFIG_38_468_M,
+       CLOCK_CONFIG_52_M,
+
+       NUM_CLOCK_CONFIGS,
+};
+
+#endif /* __WL18XX_PRIV_H__ */
index f3d6fa5082696c145b30b453fd027ce4cdd88a11..ce108a736bd0a3bdc5b1832fa09f02bdb82f412f 100644 (file)
@@ -70,7 +70,7 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
        struct acx_sleep_auth *auth;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx sleep auth");
+       wl1271_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth);
 
        auth = kzalloc(sizeof(*auth), GFP_KERNEL);
        if (!auth) {
@@ -81,11 +81,18 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth)
        auth->sleep_auth = sleep_auth;
 
        ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+       if (ret < 0) {
+               wl1271_error("could not configure sleep_auth to %d: %d",
+                            sleep_auth, ret);
+               goto out;
+       }
 
+       wl->sleep_auth = sleep_auth;
 out:
        kfree(auth);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_sleep_auth);
 
 int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                        int power)
@@ -708,14 +715,14 @@ out:
        return ret;
 }
 
-int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
+int wl1271_acx_statistics(struct wl1271 *wl, void *stats)
 {
        int ret;
 
        wl1271_debug(DEBUG_ACX, "acx statistics");
 
        ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats,
-                                    sizeof(*stats));
+                                    wl->stats.fw_stats_len);
        if (ret < 0) {
                wl1271_warning("acx statistics failed: %d", ret);
                return -ENOMEM;
@@ -997,6 +1004,7 @@ out:
        kfree(mem_conf);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl12xx_acx_mem_cfg);
 
 int wl1271_acx_init_mem_config(struct wl1271 *wl)
 {
@@ -1027,6 +1035,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_init_mem_config);
 
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
 {
@@ -1150,6 +1159,7 @@ out:
        kfree(acx);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_pm_config);
 
 int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                               bool enable)
index e6a74869a5ff539df5589e90e73bb12d98f34747..d03215d6b3bd2bc698cb38b465e51427798d37ec 100644 (file)
 #define WL1271_ACX_INTR_TRACE_A            BIT(7)
 /* Trace message on MBOX #B */
 #define WL1271_ACX_INTR_TRACE_B            BIT(8)
+/* SW FW Initiated interrupt Watchdog timer expiration */
+#define WL1271_ACX_SW_INTR_WATCHDOG        BIT(9)
 
-#define WL1271_ACX_INTR_ALL               0xFFFFFFFF
-#define WL1271_ACX_ALL_EVENTS_VECTOR       (WL1271_ACX_INTR_WATCHDOG      | \
-                                           WL1271_ACX_INTR_INIT_COMPLETE | \
-                                           WL1271_ACX_INTR_EVENT_A       | \
-                                           WL1271_ACX_INTR_EVENT_B       | \
-                                           WL1271_ACX_INTR_CMD_COMPLETE  | \
-                                           WL1271_ACX_INTR_HW_AVAILABLE  | \
-                                           WL1271_ACX_INTR_DATA)
-
-#define WL1271_INTR_MASK                   (WL1271_ACX_INTR_WATCHDOG     | \
-                                           WL1271_ACX_INTR_EVENT_A      | \
-                                           WL1271_ACX_INTR_EVENT_B      | \
-                                           WL1271_ACX_INTR_HW_AVAILABLE | \
-                                           WL1271_ACX_INTR_DATA)
+#define WL1271_ACX_INTR_ALL             0xFFFFFFFF
+
+/* all possible interrupts - only appropriate ones will be masked in */
+#define WLCORE_ALL_INTR_MASK           (WL1271_ACX_INTR_WATCHDOG     | \
+                                       WL1271_ACX_INTR_EVENT_A       | \
+                                       WL1271_ACX_INTR_EVENT_B       | \
+                                       WL1271_ACX_INTR_HW_AVAILABLE  | \
+                                       WL1271_ACX_INTR_DATA          | \
+                                       WL1271_ACX_SW_INTR_WATCHDOG)
 
 /* Target's information element */
 struct acx_header {
@@ -121,6 +118,11 @@ enum wl1271_psm_mode {
 
        /* Extreme low power */
        WL1271_PSM_ELP = 2,
+
+       WL1271_PSM_MAX = WL1271_PSM_ELP,
+
+       /* illegal out of band value of PSM mode */
+       WL1271_PSM_ILLEGAL = 0xff
 };
 
 struct acx_sleep_auth {
@@ -417,228 +419,6 @@ struct acx_ctsprotect {
        u8 padding[2];
 } __packed;
 
-struct acx_tx_statistics {
-       __le32 internal_desc_overflow;
-}  __packed;
-
-struct acx_rx_statistics {
-       __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;
-} __packed;
-
-struct acx_dma_statistics {
-       __le32 rx_requested;
-       __le32 rx_errors;
-       __le32 tx_requested;
-       __le32 tx_errors;
-}  __packed;
-
-struct acx_isr_statistics {
-       /* host command complete */
-       __le32 cmd_cmplt;
-
-       /* fiqisr() */
-       __le32 fiqs;
-
-       /* (INT_STS_ND & INT_TRIG_RX_HEADER) */
-       __le32 rx_headers;
-
-       /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
-       __le32 rx_completes;
-
-       /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
-       __le32 rx_mem_overflow;
-
-       /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
-       __le32 rx_rdys;
-
-       /* irqisr() */
-       __le32 irqs;
-
-       /* (INT_STS_ND & INT_TRIG_TX_PROC) */
-       __le32 tx_procs;
-
-       /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
-       __le32 decrypt_done;
-
-       /* (INT_STS_ND & INT_TRIG_DMA0) */
-       __le32 dma0_done;
-
-       /* (INT_STS_ND & INT_TRIG_DMA1) */
-       __le32 dma1_done;
-
-       /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
-       __le32 tx_exch_complete;
-
-       /* (INT_STS_ND & INT_TRIG_COMMAND) */
-       __le32 commands;
-
-       /* (INT_STS_ND & INT_TRIG_RX_PROC) */
-       __le32 rx_procs;
-
-       /* (INT_STS_ND & INT_TRIG_PM_802) */
-       __le32 hw_pm_mode_changes;
-
-       /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
-       __le32 host_acknowledges;
-
-       /* (INT_STS_ND & INT_TRIG_PM_PCI) */
-       __le32 pci_pm;
-
-       /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
-       __le32 wakeups;
-
-       /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
-       __le32 low_rssi;
-} __packed;
-
-struct acx_wep_statistics {
-       /* WEP address keys configured */
-       __le32 addr_key_count;
-
-       /* default keys configured */
-       __le32 default_key_count;
-
-       __le32 reserved;
-
-       /* number of times that WEP key not found on lookup */
-       __le32 key_not_found;
-
-       /* number of times that WEP key decryption failed */
-       __le32 decrypt_fail;
-
-       /* WEP packets decrypted */
-       __le32 packets;
-
-       /* WEP decrypt interrupts */
-       __le32 interrupt;
-} __packed;
-
-#define ACX_MISSED_BEACONS_SPREAD 10
-
-struct acx_pwr_statistics {
-       /* the amount of enters into power save mode (both PD & ELP) */
-       __le32 ps_enter;
-
-       /* the amount of enters into ELP mode */
-       __le32 elp_enter;
-
-       /* the amount of missing beacon interrupts to the host */
-       __le32 missing_bcns;
-
-       /* the amount of wake on host-access times */
-       __le32 wake_on_host;
-
-       /* the amount of wake on timer-expire */
-       __le32 wake_on_timer_exp;
-
-       /* the number of packets that were transmitted with PS bit set */
-       __le32 tx_with_ps;
-
-       /* the number of packets that were transmitted with PS bit clear */
-       __le32 tx_without_ps;
-
-       /* the number of received beacons */
-       __le32 rcvd_beacons;
-
-       /* the number of entering into PowerOn (power save off) */
-       __le32 power_save_off;
-
-       /* the number of entries into power save mode */
-       __le16 enable_ps;
-
-       /*
-        * the number of exits from power save, not including failed PS
-        * transitions
-        */
-       __le16 disable_ps;
-
-       /*
-        * the number of times the TSF counter was adjusted because
-        * of drift
-        */
-       __le32 fix_tsf_ps;
-
-       /* Gives statistics about the spread continuous missed beacons.
-        * The 16 LSB are dedicated for the PS mode.
-        * The 16 MSB are dedicated for the PS mode.
-        * cont_miss_bcns_spread[0] - single missed beacon.
-        * cont_miss_bcns_spread[1] - two continuous missed beacons.
-        * cont_miss_bcns_spread[2] - three continuous missed beacons.
-        * ...
-        * cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
-       */
-       __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
-
-       /* the number of beacons in awake mode */
-       __le32 rcvd_awake_beacons;
-} __packed;
-
-struct acx_mic_statistics {
-       __le32 rx_pkts;
-       __le32 calc_failure;
-} __packed;
-
-struct acx_aes_statistics {
-       __le32 encrypt_fail;
-       __le32 decrypt_fail;
-       __le32 encrypt_packets;
-       __le32 decrypt_packets;
-       __le32 encrypt_interrupt;
-       __le32 decrypt_interrupt;
-} __packed;
-
-struct acx_event_statistics {
-       __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;
-} __packed;
-
-struct acx_ps_statistics {
-       __le32 pspoll_timeouts;
-       __le32 upsd_timeouts;
-       __le32 upsd_max_sptime;
-       __le32 upsd_max_apturn;
-       __le32 pspoll_max_apturn;
-       __le32 pspoll_utilization;
-       __le32 upsd_utilization;
-} __packed;
-
-struct acx_rxpipe_statistics {
-       __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;
-} __packed;
-
-struct acx_statistics {
-       struct acx_header header;
-
-       struct acx_tx_statistics tx;
-       struct acx_rx_statistics rx;
-       struct acx_dma_statistics dma;
-       struct acx_isr_statistics isr;
-       struct acx_wep_statistics wep;
-       struct acx_pwr_statistics pwr;
-       struct acx_aes_statistics aes;
-       struct acx_mic_statistics mic;
-       struct acx_event_statistics event;
-       struct acx_ps_statistics ps;
-       struct acx_rxpipe_statistics rxpipe;
-} __packed;
-
 struct acx_rate_class {
        __le32 enabled_rates;
        u8 short_retry_limit;
@@ -828,6 +608,8 @@ struct wl1271_acx_keep_alive_config {
 #define HOST_IF_CFG_RX_FIFO_ENABLE     BIT(0)
 #define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
 #define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
+#define HOST_IF_CFG_RX_PAD_TO_SDIO_BLK BIT(4)
+#define HOST_IF_CFG_ADD_RX_ALIGNMENT   BIT(6)
 
 enum {
        WL1271_ACX_TRIG_TYPE_LEVEL = 0,
@@ -946,7 +728,7 @@ struct wl1271_acx_ht_information {
        u8 padding[2];
 } __packed;
 
-#define RX_BA_MAX_SESSIONS 2
+#define RX_BA_MAX_SESSIONS 3
 
 struct wl1271_acx_ba_initiator_policy {
        struct acx_header header;
@@ -1243,6 +1025,7 @@ enum {
        ACX_CONFIG_HANGOVER              = 0x0042,
        ACX_FEATURE_CFG                  = 0x0043,
        ACX_PROTECTION_CFG               = 0x0044,
+       ACX_CHECKSUM_CONFIG              = 0x0045,
 };
 
 
@@ -1281,7 +1064,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                            enum acx_preamble_type preamble);
 int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                           enum acx_ctsprotect_type ctsprotect);
-int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
+int wl1271_acx_statistics(struct wl1271 *wl, void *stats);
 int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif);
 int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
                      u8 idx);
index 9b98230f84cecd9ae14b29c028b0e2b4bbb49a67..8965960b841a2b35c0be34c823a9a6a08aee7082 100644 (file)
 #include "rx.h"
 #include "hw_ops.h"
 
-static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
+static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
 {
        u32 cpu_ctrl;
+       int ret;
 
        /* 10.5.0 run the firmware (I) */
-       cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL);
+       ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl);
+       if (ret < 0)
+               goto out;
 
        /* 10.5.1 run the firmware (II) */
        cpu_ctrl |= flag;
-       wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
+       ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl);
+
+out:
+       return ret;
 }
 
-static int wlcore_parse_fw_ver(struct wl1271 *wl)
+static int wlcore_boot_parse_fw_ver(struct wl1271 *wl,
+                                   struct wl1271_static_data *static_data)
 {
        int ret;
 
+       strncpy(wl->chip.fw_ver_str, static_data->fw_version,
+               sizeof(wl->chip.fw_ver_str));
+
+       /* make sure the string is NULL-terminated */
+       wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
+
        ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u",
                     &wl->chip.fw_ver[0], &wl->chip.fw_ver[1],
                     &wl->chip.fw_ver[2], &wl->chip.fw_ver[3],
@@ -57,43 +70,45 @@ static int wlcore_parse_fw_ver(struct wl1271 *wl)
        if (ret != 5) {
                wl1271_warning("fw version incorrect value");
                memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver));
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        ret = wlcore_identify_fw(wl);
        if (ret < 0)
-               return ret;
-
-       return 0;
+               goto out;
+out:
+       return ret;
 }
 
-static int wlcore_boot_fw_version(struct wl1271 *wl)
+static int wlcore_boot_static_data(struct wl1271 *wl)
 {
        struct wl1271_static_data *static_data;
+       size_t len = sizeof(*static_data) + wl->static_data_priv_len;
        int ret;
 
-       static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
+       static_data = kmalloc(len, GFP_KERNEL);
        if (!static_data) {
-               wl1271_error("Couldn't allocate memory for static data!");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
-       wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data),
-                   false);
-
-       strncpy(wl->chip.fw_ver_str, static_data->fw_version,
-               sizeof(wl->chip.fw_ver_str));
-
-       kfree(static_data);
+       ret = wlcore_read(wl, wl->cmd_box_addr, static_data, len, false);
+       if (ret < 0)
+               goto out_free;
 
-       /* make sure the string is NULL-terminated */
-       wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0';
+       ret = wlcore_boot_parse_fw_ver(wl, static_data);
+       if (ret < 0)
+               goto out_free;
 
-       ret = wlcore_parse_fw_ver(wl);
+       ret = wlcore_handle_static_data(wl, static_data);
        if (ret < 0)
-               return ret;
+               goto out_free;
 
-       return 0;
+out_free:
+       kfree(static_data);
+out:
+       return ret;
 }
 
 static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
@@ -102,6 +117,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
        struct wlcore_partition_set partition;
        int addr, chunk_num, partition_limit;
        u8 *p, *chunk;
+       int ret;
 
        /* whal_FwCtrl_LoadFwImageSm() */
 
@@ -123,7 +139,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
 
        memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition));
        partition.mem.start = dest;
-       wlcore_set_partition(wl, &partition);
+       ret = wlcore_set_partition(wl, &partition);
+       if (ret < 0)
+               return ret;
 
        /* 10.1 set partition limit and chunk num */
        chunk_num = 0;
@@ -137,7 +155,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
                        partition_limit = chunk_num * CHUNK_SIZE +
                                wl->ptable[PART_DOWN].mem.size;
                        partition.mem.start = addr;
-                       wlcore_set_partition(wl, &partition);
+                       ret = wlcore_set_partition(wl, &partition);
+                       if (ret < 0)
+                               return ret;
                }
 
                /* 10.3 upload the chunk */
@@ -146,7 +166,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
                memcpy(chunk, p, CHUNK_SIZE);
                wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
                             p, addr);
-               wl1271_write(wl, addr, chunk, CHUNK_SIZE, false);
+               ret = wlcore_write(wl, addr, chunk, CHUNK_SIZE, false);
+               if (ret < 0)
+                       goto out;
 
                chunk_num++;
        }
@@ -157,10 +179,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
        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_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
+       ret = wlcore_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
 
+out:
        kfree(chunk);
-       return 0;
+       return ret;
 }
 
 int wlcore_boot_upload_firmware(struct wl1271 *wl)
@@ -203,9 +226,12 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
        int i;
        u32 dest_addr, val;
        u8 *nvs_ptr, *nvs_aligned;
+       int ret;
 
-       if (wl->nvs == NULL)
+       if (wl->nvs == NULL) {
+               wl1271_error("NVS file is needed during boot");
                return -ENODEV;
+       }
 
        if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) {
                struct wl1271_nvs_file *nvs =
@@ -298,7 +324,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
                        wl1271_debug(DEBUG_BOOT,
                                     "nvs burst write 0x%x: 0x%x",
                                     dest_addr, val);
-                       wl1271_write32(wl, dest_addr, val);
+                       ret = wlcore_write32(wl, dest_addr, val);
+                       if (ret < 0)
+                               return ret;
 
                        nvs_ptr += 4;
                        dest_addr += 4;
@@ -324,7 +352,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
        nvs_len -= nvs_ptr - (u8 *)wl->nvs;
 
        /* Now we must set the partition correctly */
-       wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+       if (ret < 0)
+               return ret;
 
        /* Copy the NVS tables to a new block to ensure alignment */
        nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);
@@ -332,11 +362,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl)
                return -ENOMEM;
 
        /* And finally we upload the NVS tables */
-       wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS,
-                         nvs_aligned, nvs_len, false);
+       ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len,
+                               false);
 
        kfree(nvs_aligned);
-       return 0;
+       return ret;
 
 out_badnvs:
        wl1271_error("nvs data is malformed");
@@ -350,11 +380,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
        u32 chip_id, intr;
 
        /* Make sure we have the boot partition */
-       wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       if (ret < 0)
+               return ret;
 
-       wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
+       ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
+       if (ret < 0)
+               return ret;
 
-       chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B);
+       ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id);
+       if (ret < 0)
+               return ret;
 
        wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
 
@@ -367,7 +403,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
        loop = 0;
        while (loop++ < INIT_LOOP) {
                udelay(INIT_LOOP_DELAY);
-               intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
+               ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
+               if (ret < 0)
+                       return ret;
 
                if (intr == 0xffffffff) {
                        wl1271_error("error reading hardware complete "
@@ -376,8 +414,10 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
                }
                /* check that ACX_INTR_INIT_COMPLETE is enabled */
                else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
-                       wlcore_write_reg(wl, REG_INTERRUPT_ACK,
-                                        WL1271_ACX_INTR_INIT_COMPLETE);
+                       ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
+                                              WL1271_ACX_INTR_INIT_COMPLETE);
+                       if (ret < 0)
+                               return ret;
                        break;
                }
        }
@@ -389,20 +429,25 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
        }
 
        /* get hardware config command mail box */
-       wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR);
+       ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr);
+       if (ret < 0)
+               return ret;
 
        wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr);
 
        /* get hardware config event mail box */
-       wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR);
+       ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]);
+       if (ret < 0)
+               return ret;
+
        wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
 
        wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x",
                     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 
-       ret = wlcore_boot_fw_version(wl);
+       ret = wlcore_boot_static_data(wl);
        if (ret < 0) {
-               wl1271_error("couldn't boot firmware");
+               wl1271_error("error getting static data");
                return ret;
        }
 
@@ -436,9 +481,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
        }
 
        /* set the working partition to its "running" mode offset */
-       wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
 
        /* firmware startup completed */
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware);
index 094981dd22272d8b860be372fac1468ab6a80bc4..a525225f990cd151ac51264998897eb58494782d 100644 (file)
@@ -40,6 +40,7 @@ struct wl1271_static_data {
        u8 fw_version[WL1271_FW_VERSION_MAX_LEN];
        u32 hw_version;
        u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS];
+       u8 priv[0];
 };
 
 /* number of times we try to read the INIT interrupt */
index 5b128a971449a560911fab5e5a8c360338ea3576..56c7a2342fdfc54e7487f262d4237ca93a6e0cbd 100644 (file)
@@ -36,6 +36,7 @@
 #include "cmd.h"
 #include "event.h"
 #include "tx.h"
+#include "hw_ops.h"
 
 #define WL1271_CMD_FAST_POLL_COUNT       50
 
@@ -64,17 +65,24 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
        WARN_ON(len % 4 != 0);
        WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
 
-       wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
+       ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false);
+       if (ret < 0)
+               goto fail;
 
        /*
         * TODO: we just need this because one bit is in a different
         * place.  Is there any better way?
         */
-       wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
+       ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len);
+       if (ret < 0)
+               goto fail;
 
        timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
 
-       intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
+       ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
+       if (ret < 0)
+               goto fail;
+
        while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
                if (time_after(jiffies, timeout)) {
                        wl1271_error("command complete timeout");
@@ -88,13 +96,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                else
                        msleep(1);
 
-               intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR);
+               ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr);
+               if (ret < 0)
+                       goto fail;
        }
 
        /* read back the status code of the command */
        if (res_len == 0)
                res_len = sizeof(struct wl1271_cmd_header);
-       wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
+
+       ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false);
+       if (ret < 0)
+               goto fail;
 
        status = le16_to_cpu(cmd->status);
        if (status != CMD_STATUS_SUCCESS) {
@@ -103,11 +116,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                goto fail;
        }
 
-       wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE);
+       ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK,
+                              WL1271_ACX_INTR_CMD_COMPLETE);
+       if (ret < 0)
+               goto fail;
+
        return 0;
 
 fail:
-       WARN_ON(1);
        wl12xx_queue_recovery_work(wl);
        return ret;
 }
@@ -116,35 +132,45 @@ fail:
  * Poll the mailbox event field until any of the bits in the mask is set or a
  * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
  */
-static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
+static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+                                               u32 mask, bool *timeout)
 {
        u32 *events_vector;
        u32 event;
-       unsigned long timeout;
+       unsigned long timeout_time;
        int ret = 0;
 
+       *timeout = false;
+
        events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
        if (!events_vector)
                return -ENOMEM;
 
-       timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
+       timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
 
        do {
-               if (time_after(jiffies, timeout)) {
+               if (time_after(jiffies, timeout_time)) {
                        wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
                                     (int)mask);
-                       ret = -ETIMEDOUT;
+                       *timeout = true;
                        goto out;
                }
 
                msleep(1);
 
                /* read from both event fields */
-               wl1271_read(wl, wl->mbox_ptr[0], events_vector,
-                           sizeof(*events_vector), false);
+               ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector,
+                                 sizeof(*events_vector), false);
+               if (ret < 0)
+                       goto out;
+
                event = *events_vector & mask;
-               wl1271_read(wl, wl->mbox_ptr[1], events_vector,
-                           sizeof(*events_vector), false);
+
+               ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector,
+                                 sizeof(*events_vector), false);
+               if (ret < 0)
+                       goto out;
+
                event |= *events_vector & mask;
        } while (!event);
 
@@ -156,9 +182,10 @@ out:
 static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
 {
        int ret;
+       bool timeout = false;
 
-       ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
-       if (ret != 0) {
+       ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
+       if (ret != 0 || timeout) {
                wl12xx_queue_recovery_work(wl);
                return ret;
        }
@@ -291,6 +318,23 @@ static int wl12xx_get_new_session_id(struct wl1271 *wl,
        return wlvif->session_counter;
 }
 
+static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
+{
+       switch (nl_channel_type) {
+       case NL80211_CHAN_NO_HT:
+               return WLCORE_CHAN_NO_HT;
+       case NL80211_CHAN_HT20:
+               return WLCORE_CHAN_HT20;
+       case NL80211_CHAN_HT40MINUS:
+               return WLCORE_CHAN_HT40MINUS;
+       case NL80211_CHAN_HT40PLUS:
+               return WLCORE_CHAN_HT40PLUS;
+       default:
+               WARN_ON(1);
+               return WLCORE_CHAN_NO_HT;
+       }
+}
+
 static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
                                     struct wl12xx_vif *wlvif)
 {
@@ -407,6 +451,7 @@ int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len);
        memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN);
        cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set);
+       cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
        if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) {
                ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid);
@@ -482,6 +527,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        struct wl12xx_cmd_role_start *cmd;
        struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       u32 supported_rates;
        int ret;
 
        wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id);
@@ -519,6 +565,7 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        /* FIXME: Change when adding DFS */
        cmd->ap.reset_tsf = 1;  /* By default reset AP TSF */
        cmd->channel = wlvif->channel;
+       cmd->channel_type = wlcore_get_native_channel_type(wlvif->channel_type);
 
        if (!bss_conf->hidden_ssid) {
                /* take the SSID from the beacon for backward compatibility */
@@ -531,7 +578,13 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
        }
 
-       cmd->ap.local_rates = cpu_to_le32(0xffffffff);
+       supported_rates = CONF_TX_AP_ENABLED_RATES | CONF_TX_MCS_RATES |
+               wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+
+       wl1271_debug(DEBUG_CMD, "cmd role start ap with supported_rates 0x%08x",
+                    supported_rates);
+
+       cmd->ap.local_rates = cpu_to_le32(supported_rates);
 
        switch (wlvif->band) {
        case IEEE80211_BAND_2GHZ:
@@ -797,6 +850,7 @@ out:
        kfree(cmd);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_cmd_data_path);
 
 int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                       u8 ps_mode, u16 auto_ps_timeout)
@@ -1018,7 +1072,7 @@ out:
 
 int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
-       int ret, extra;
+       int ret, extra = 0;
        u16 fc;
        struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
        struct sk_buff *skb;
@@ -1057,7 +1111,8 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        /* encryption space */
        switch (wlvif->encryption_type) {
        case KEY_TKIP:
-               extra = WL1271_EXTRA_SPACE_TKIP;
+               if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
+                       extra = WL1271_EXTRA_SPACE_TKIP;
                break;
        case KEY_AES:
                extra = WL1271_EXTRA_SPACE_AES;
@@ -1346,13 +1401,18 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
        for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
                if (sta->wme && (sta->uapsd_queues & BIT(i)))
-                       cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
+                       cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
+                                       WL1271_PSD_UPSD_TRIGGER;
                else
-                       cmd->psd_type[i] = WL1271_PSD_LEGACY;
+                       cmd->psd_type[NUM_ACCESS_CATEGORIES_COPY-1-i] =
+                                       WL1271_PSD_LEGACY;
+
 
        sta_rates = sta->supp_rates[wlvif->band];
        if (sta->ht_cap.ht_supported)
-               sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
+               sta_rates |=
+                       (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
+                       (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
 
        cmd->supported_rates =
                cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
@@ -1378,6 +1438,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
 {
        struct wl12xx_cmd_remove_peer *cmd;
        int ret;
+       bool timeout = false;
 
        wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
 
@@ -1398,12 +1459,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
                goto out_free;
        }
 
+       ret = wl1271_cmd_wait_for_event_or_timeout(wl,
+                                          PEER_REMOVE_COMPLETE_EVENT_ID,
+                                          &timeout);
        /*
         * We are ok with a timeout here. The event is sometimes not sent
-        * due to a firmware bug.
+        * due to a firmware bug. In case of another error (like SDIO timeout)
+        * queue a recovery.
         */
-       wl1271_cmd_wait_for_event_or_timeout(wl,
-                                            PEER_REMOVE_COMPLETE_EVENT_ID);
+       if (ret)
+               wl12xx_queue_recovery_work(wl);
 
 out_free:
        kfree(cmd);
@@ -1573,19 +1638,25 @@ out:
 int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id)
 {
        int ret = 0;
+       bool is_first_roc;
 
        if (WARN_ON(test_bit(role_id, wl->roc_map)))
                return 0;
 
+       is_first_roc = (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >=
+                       WL12XX_MAX_ROLES);
+
        ret = wl12xx_cmd_roc(wl, wlvif, role_id);
        if (ret < 0)
                goto out;
 
-       ret = wl1271_cmd_wait_for_event(wl,
-                                       REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
-       if (ret < 0) {
-               wl1271_error("cmd roc event completion error");
-               goto out;
+       if (is_first_roc) {
+               ret = wl1271_cmd_wait_for_event(wl,
+                                          REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
+               if (ret < 0) {
+                       wl1271_error("cmd roc event completion error");
+                       goto out;
+               }
        }
 
        __set_bit(role_id, wl->roc_map);
@@ -1714,7 +1785,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                return -EINVAL;
 
        /* flush all pending packets */
-       wl1271_tx_work_locked(wl);
+       ret = wlcore_tx_work_locked(wl);
+       if (ret < 0)
+               goto out;
 
        if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
                ret = wl12xx_croc(wl, wlvif->dev_role_id);
index a46ae07cb77eb8243a27251c7c5859916de908f4..c8a6510c72cb6a5ef47d7d9844a19449b743665a 100644 (file)
@@ -192,7 +192,7 @@ enum cmd_templ {
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_DFLT_SIZE 252
 #define WL1271_CMD_TEMPL_MAX_SIZE  512
-#define WL1271_EVENT_TIMEOUT       750
+#define WL1271_EVENT_TIMEOUT       1000
 
 struct wl1271_cmd_header {
        __le16 id;
@@ -266,13 +266,22 @@ enum wlcore_band {
        WLCORE_BAND_MAX_RADIO           = 0x7F,
 };
 
+enum wlcore_channel_type {
+       WLCORE_CHAN_NO_HT,
+       WLCORE_CHAN_HT20,
+       WLCORE_CHAN_HT40MINUS,
+       WLCORE_CHAN_HT40PLUS
+};
+
 struct wl12xx_cmd_role_start {
        struct wl1271_cmd_header header;
 
        u8 role_id;
        u8 band;
        u8 channel;
-       u8 padding;
+
+       /* enum wlcore_channel_type */
+       u8 channel_type;
 
        union {
                struct {
@@ -643,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch {
        struct wl1271_cmd_header header;
 } __packed;
 
+/* Used to check radio status after calibration */
+#define MAX_TLV_LENGTH         500
+#define TEST_CMD_P2G_CAL       2       /* TX BiP */
+
+struct wl1271_cmd_cal_p2g {
+       struct wl1271_cmd_header header;
+
+       struct wl1271_cmd_test_header test;
+
+       __le32 ver;
+       __le16 len;
+       u8 buf[MAX_TLV_LENGTH];
+       u8 type;
+       u8 padding;
+
+       __le16 radio_status;
+
+       u8 sub_band_mask;
+       u8 padding2;
+} __packed;
+
 #endif /* __WL1271_CMD_H__ */
index fef0db4213bc4c83d3cf51b5092d8fbe004bfe0e..d77224f2ac6bcbccfa6377f85c49a620a8fd2234 100644 (file)
@@ -45,7 +45,15 @@ enum {
        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)
+       CONF_HW_BIT_RATE_MCS_7   = BIT(20),
+       CONF_HW_BIT_RATE_MCS_8   = BIT(21),
+       CONF_HW_BIT_RATE_MCS_9   = BIT(22),
+       CONF_HW_BIT_RATE_MCS_10  = BIT(23),
+       CONF_HW_BIT_RATE_MCS_11  = BIT(24),
+       CONF_HW_BIT_RATE_MCS_12  = BIT(25),
+       CONF_HW_BIT_RATE_MCS_13  = BIT(26),
+       CONF_HW_BIT_RATE_MCS_14  = BIT(27),
+       CONF_HW_BIT_RATE_MCS_15  = BIT(28),
 };
 
 enum {
@@ -310,7 +318,7 @@ enum {
 struct conf_sg_settings {
        u32 params[CONF_SG_PARAMS_MAX];
        u8 state;
-};
+} __packed;
 
 enum conf_rx_queue_type {
        CONF_RX_QUEUE_TYPE_LOW_PRIORITY,  /* All except the high priority */
@@ -394,7 +402,7 @@ struct conf_rx_settings {
         * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
         */
        u8 queue_type;
-};
+} __packed;
 
 #define CONF_TX_MAX_RATE_CLASSES       10
 
@@ -435,6 +443,12 @@ struct conf_rx_settings {
        CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 |        \
        CONF_HW_BIT_RATE_MCS_7)
 
+#define CONF_TX_MIMO_RATES (CONF_HW_BIT_RATE_MCS_8 |             \
+       CONF_HW_BIT_RATE_MCS_9 | CONF_HW_BIT_RATE_MCS_10 |       \
+       CONF_HW_BIT_RATE_MCS_11 | CONF_HW_BIT_RATE_MCS_12 |      \
+       CONF_HW_BIT_RATE_MCS_13 | CONF_HW_BIT_RATE_MCS_14 |      \
+       CONF_HW_BIT_RATE_MCS_15)
+
 /*
  * Default rates for management traffic when operating in AP mode. This
  * should be configured according to the basic rate set of the AP
@@ -487,7 +501,7 @@ struct conf_tx_rate_class {
         *               the policy (0 - long preamble, 1 - short preamble.
         */
        u8 aflags;
-};
+} __packed;
 
 #define CONF_TX_MAX_AC_COUNT 4
 
@@ -504,7 +518,7 @@ enum conf_tx_ac {
        CONF_TX_AC_VI = 2,         /* video */
        CONF_TX_AC_VO = 3,         /* voice */
        CONF_TX_AC_CTS2SELF = 4,   /* fictitious AC, follows AC_VO */
-       CONF_TX_AC_ANY_TID = 0x1f
+       CONF_TX_AC_ANY_TID = 0xff
 };
 
 struct conf_tx_ac_category {
@@ -544,7 +558,7 @@ struct conf_tx_ac_category {
         * Range: u16
         */
        u16 tx_op_limit;
-};
+} __packed;
 
 #define CONF_TX_MAX_TID_COUNT 8
 
@@ -578,7 +592,7 @@ struct conf_tx_tid {
        u8 ps_scheme;
        u8 ack_policy;
        u32 apsd_conf[2];
-};
+} __packed;
 
 struct conf_tx_settings {
        /*
@@ -664,7 +678,7 @@ struct conf_tx_settings {
 
        /* Time in ms for Tx watchdog timer to expire */
        u32 tx_watchdog_timeout;
-};
+} __packed;
 
 enum {
        CONF_WAKE_UP_EVENT_BEACON    = 0x01, /* Wake on every Beacon*/
@@ -711,7 +725,7 @@ struct conf_bcn_filt_rule {
         * Version for the vendor specifie IE (221)
         */
        u8 version[CONF_BCN_IE_VER_LEN];
-};
+} __packed;
 
 #define CONF_MAX_RSSI_SNR_TRIGGERS 8
 
@@ -762,7 +776,7 @@ struct conf_sig_weights {
         * Range: u8
         */
        u8 snr_pkt_avg_weight;
-};
+} __packed;
 
 enum conf_bcn_filt_mode {
        CONF_BCN_FILT_MODE_DISABLED = 0,
@@ -810,7 +824,7 @@ struct conf_conn_settings {
         *
         * Range: CONF_BCN_FILT_MODE_*
         */
-       enum conf_bcn_filt_mode bcn_filt_mode;
+       u8 bcn_filt_mode;
 
        /*
         * Configure Beacon filter pass-thru rules.
@@ -937,7 +951,13 @@ struct conf_conn_settings {
         * Range: u16
         */
        u8 max_listen_interval;
-};
+
+       /*
+        * Default sleep authorization for a new STA interface. This determines
+        * whether we can go to ELP.
+        */
+       u8 sta_sleep_auth;
+} __packed;
 
 enum {
        CONF_REF_CLK_19_2_E,
@@ -965,6 +985,11 @@ struct conf_itrim_settings {
 
        /* moderation timeout in microsecs from the last TX */
        u32 timeout;
+} __packed;
+
+enum conf_fast_wakeup {
+       CONF_FAST_WAKEUP_ENABLE,
+       CONF_FAST_WAKEUP_DISABLE,
 };
 
 struct conf_pm_config_settings {
@@ -978,10 +1003,10 @@ struct conf_pm_config_settings {
        /*
         * Host fast wakeup support
         *
-        * Range: true, false
+        * Range: enum conf_fast_wakeup
         */
-       bool host_fast_wakeup_support;
-};
+       u8 host_fast_wakeup_support;
+} __packed;
 
 struct conf_roam_trigger_settings {
        /*
@@ -1018,7 +1043,7 @@ struct conf_roam_trigger_settings {
         * Range: 0 - 255
         */
        u8 avg_weight_snr_data;
-};
+} __packed;
 
 struct conf_scan_settings {
        /*
@@ -1064,7 +1089,7 @@ struct conf_scan_settings {
         * Range: u32 Microsecs
         */
        u32 split_scan_timeout;
-};
+} __packed;
 
 struct conf_sched_scan_settings {
        /*
@@ -1102,7 +1127,7 @@ struct conf_sched_scan_settings {
 
        /* SNR threshold to be used for filtering */
        s8 snr_threshold;
-};
+} __packed;
 
 struct conf_ht_setting {
        u8 rx_ba_win_size;
@@ -1111,7 +1136,7 @@ struct conf_ht_setting {
 
        /* bitmap of enabled TIDs for TX BA sessions */
        u8 tx_ba_tid_bitmap;
-};
+} __packed;
 
 struct conf_memory_settings {
        /* Number of stations supported in IBSS mode */
@@ -1151,7 +1176,7 @@ struct conf_memory_settings {
         * Range: 0-120
         */
        u8 tx_min;
-};
+} __packed;
 
 struct conf_fm_coex {
        u8 enable;
@@ -1164,7 +1189,7 @@ struct conf_fm_coex {
        u16 ldo_stabilization_time;
        u8 fm_disturbed_band_margin;
        u8 swallow_clk_diff;
-};
+} __packed;
 
 struct conf_rx_streaming_settings {
        /*
@@ -1193,7 +1218,7 @@ struct conf_rx_streaming_settings {
         * enable rx streaming also when there is no coex activity
         */
        u8 always;
-};
+} __packed;
 
 struct conf_fwlog {
        /* Continuous or on-demand */
@@ -1217,7 +1242,7 @@ struct conf_fwlog {
 
        /* Regulates the frequency of log messages */
        u8 threshold;
-};
+} __packed;
 
 #define ACX_RATE_MGMT_NUM_OF_RATES 13
 struct conf_rate_policy_settings {
@@ -1236,7 +1261,7 @@ struct conf_rate_policy_settings {
        u8 rate_check_up;
        u8 rate_check_down;
        u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
-};
+} __packed;
 
 struct conf_hangover_settings {
        u32 recover_time;
@@ -1250,7 +1275,23 @@ struct conf_hangover_settings {
        u8 quiet_time;
        u8 increase_time;
        u8 window_size;
-};
+} __packed;
+
+/*
+ * The conf version consists of 4 bytes.  The two MSB are the wlcore
+ * version, the two LSB are the lower driver's private conf
+ * version.
+ */
+#define WLCORE_CONF_VERSION    (0x0002 << 16)
+#define WLCORE_CONF_MASK       0xffff0000
+#define WLCORE_CONF_SIZE       (sizeof(struct wlcore_conf_header) +    \
+                                sizeof(struct wlcore_conf))
+
+struct wlcore_conf_header {
+       __le32 magic;
+       __le32 version;
+       __le32 checksum;
+} __packed;
 
 struct wlcore_conf {
        struct conf_sg_settings sg;
@@ -1269,6 +1310,12 @@ struct wlcore_conf {
        struct conf_fwlog fwlog;
        struct conf_rate_policy_settings rate;
        struct conf_hangover_settings hangover;
-};
+} __packed;
+
+struct wlcore_conf_file {
+       struct wlcore_conf_header header;
+       struct wlcore_conf core;
+       u8 priv[0];
+} __packed;
 
 #endif
index d5aea1ff5ad196a693930cd4b66fc3376ba4fdc4..80dbc5304facdc5e69f93b55b6fbe442f4a25052 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/skbuff.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "wlcore.h"
 #include "debug.h"
 #include "ps.h"
 #include "io.h"
 #include "tx.h"
+#include "hw_ops.h"
 
 /* ms */
 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
 
+#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
+
 /* debugfs macros idea from mac80211 */
-#define DEBUGFS_FORMAT_BUFFER_SIZE 100
-static int wl1271_format_buffer(char __user *userbuf, size_t count,
-                                   loff_t *ppos, char *fmt, ...)
+int wl1271_format_buffer(char __user *userbuf, size_t count,
+                        loff_t *ppos, char *fmt, ...)
 {
        va_list args;
        char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
@@ -51,59 +54,9 @@ static int wl1271_format_buffer(char __user *userbuf, size_t count,
 
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
+EXPORT_SYMBOL_GPL(wl1271_format_buffer);
 
-#define DEBUGFS_READONLY_FILE(name, fmt, value...)                     \
-static ssize_t name## _read(struct file *file, char __user *userbuf,   \
-                           size_t count, loff_t *ppos)                 \
-{                                                                      \
-       struct wl1271 *wl = file->private_data;                         \
-       return wl1271_format_buffer(userbuf, count, ppos,               \
-                                   fmt "\n", ##value);                 \
-}                                                                      \
-                                                                       \
-static const struct file_operations name## _ops = {                    \
-       .read = name## _read,                                           \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_ADD(name, parent)                                      \
-       entry = debugfs_create_file(#name, 0400, parent,                \
-                                   wl, &name## _ops);                  \
-       if (!entry || IS_ERR(entry))                                    \
-               goto err;                                               \
-
-#define DEBUGFS_ADD_PREFIX(prefix, name, parent)                       \
-       do {                                                            \
-               entry = debugfs_create_file(#name, 0400, parent,        \
-                                   wl, &prefix## _## name## _ops);     \
-               if (!entry || IS_ERR(entry))                            \
-                       goto err;                                       \
-       } while (0);
-
-#define DEBUGFS_FWSTATS_FILE(sub, name, fmt)                           \
-static ssize_t sub## _ ##name## _read(struct file *file,               \
-                                     char __user *userbuf,             \
-                                     size_t count, loff_t *ppos)       \
-{                                                                      \
-       struct wl1271 *wl = file->private_data;                         \
-                                                                       \
-       wl1271_debugfs_update_stats(wl);                                \
-                                                                       \
-       return wl1271_format_buffer(userbuf, count, ppos, fmt "\n",     \
-                                   wl->stats.fw_stats->sub.name);      \
-}                                                                      \
-                                                                       \
-static const struct file_operations sub## _ ##name## _ops = {          \
-       .read = sub## _ ##name## _read,                                 \
-       .open = simple_open,                                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_FWSTATS_ADD(sub, name)                         \
-       DEBUGFS_ADD(sub## _ ##name, stats)
-
-static void wl1271_debugfs_update_stats(struct wl1271 *wl)
+void wl1271_debugfs_update_stats(struct wl1271 *wl)
 {
        int ret;
 
@@ -125,97 +78,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
 out:
        mutex_unlock(&wl->mutex);
 }
-
-DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u");
-
-DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u");
-DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u");
-DEBUGFS_FWSTATS_FILE(rx, dropped, "%u");
-DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u");
-DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u");
-DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u");
-DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u");
-
-DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u");
-DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u");
-DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u");
-
-DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u");
-DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u");
-DEBUGFS_FWSTATS_FILE(isr, irqs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u");
-DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u");
-DEBUGFS_FWSTATS_FILE(isr, commands, "%u");
-DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u");
-DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u");
-DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u");
-DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u");
-DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u");
-DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u");
-
-DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u");
-DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u");
-/* skipping wep.reserved */
-DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u");
-DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(wep, packets, "%u");
-DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u");
-
-DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u");
-DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u");
-/* skipping cont_miss_bcns_spread for now */
-DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u");
-
-DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u");
-DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u");
-
-DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u");
-DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u");
-DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u");
-
-DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u");
-DEBUGFS_FWSTATS_FILE(event, calibration, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u");
-DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u");
-DEBUGFS_FWSTATS_FILE(event, oom_late, "%u");
-DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u");
-DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u");
-
-DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u");
-DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u");
-DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u");
-
-DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u");
-DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u");
+EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats);
 
 DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
 DEBUGFS_READONLY_FILE(excessive_retries, "%u",
@@ -241,6 +104,89 @@ static const struct file_operations tx_queue_len_ops = {
        .llseek = default_llseek,
 };
 
+static void chip_op_handler(struct wl1271 *wl, unsigned long value,
+                           void *arg)
+{
+       int ret;
+       int (*chip_op) (struct wl1271 *wl);
+
+       if (!arg) {
+               wl1271_warning("debugfs chip_op_handler with no callback");
+               return;
+       }
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               return;
+
+       chip_op = arg;
+       chip_op(wl);
+
+       wl1271_ps_elp_sleep(wl);
+}
+
+
+static inline void no_write_handler(struct wl1271 *wl,
+                                   unsigned long value,
+                                   unsigned long param)
+{
+}
+
+#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct,                    \
+                           min_val, max_val, write_handler_locked,     \
+                           write_handler_arg)                          \
+       static ssize_t param##_read(struct file *file,                  \
+                                     char __user *user_buf,            \
+                                     size_t count, loff_t *ppos)       \
+       {                                                               \
+       struct wl1271 *wl = file->private_data;                         \
+       return wl1271_format_buffer(user_buf, count,                    \
+                                   ppos, "%d\n",                       \
+                                   wl->conf.conf_sub_struct.param);    \
+       }                                                               \
+                                                                       \
+       static ssize_t param##_write(struct file *file,                 \
+                                    const char __user *user_buf,       \
+                                    size_t count, loff_t *ppos)        \
+       {                                                               \
+       struct wl1271 *wl = file->private_data;                         \
+       unsigned long value;                                            \
+       int ret;                                                        \
+                                                                       \
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);          \
+       if (ret < 0) {                                                  \
+               wl1271_warning("illegal value for " #param);            \
+               return -EINVAL;                                         \
+       }                                                               \
+                                                                       \
+       if (value < min_val || value > max_val) {                       \
+               wl1271_warning(#param " is not in valid range");        \
+               return -ERANGE;                                         \
+       }                                                               \
+                                                                       \
+       mutex_lock(&wl->mutex);                                         \
+       wl->conf.conf_sub_struct.param = value;                         \
+                                                                       \
+       write_handler_locked(wl, value, write_handler_arg);             \
+                                                                       \
+       mutex_unlock(&wl->mutex);                                       \
+       return count;                                                   \
+       }                                                               \
+                                                                       \
+       static const struct file_operations param##_ops = {             \
+               .read = param##_read,                                   \
+               .write = param##_write,                                 \
+               .open = simple_open,                                    \
+               .llseek = default_llseek,                               \
+       };
+
+WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,
+                   chip_op_handler, wl1271_acx_init_rx_interrupt)
+WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,
+                   chip_op_handler, wl1271_acx_init_rx_interrupt)
+WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,
+                   chip_op_handler, wl1271_acx_init_rx_interrupt)
+
 static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
                          size_t count, loff_t *ppos)
 {
@@ -535,8 +481,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
        DRIVER_STATE_PRINT_LHEX(ap_ps_map);
        DRIVER_STATE_PRINT_HEX(quirks);
        DRIVER_STATE_PRINT_HEX(irq);
-       DRIVER_STATE_PRINT_HEX(ref_clock);
-       DRIVER_STATE_PRINT_HEX(tcxo_clock);
+       /* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
        DRIVER_STATE_PRINT_HEX(hw_pg_ver);
        DRIVER_STATE_PRINT_HEX(platform_quirks);
        DRIVER_STATE_PRINT_HEX(chip.id);
@@ -647,7 +592,6 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
                VIF_STATE_PRINT_INT(last_rssi_event);
                VIF_STATE_PRINT_INT(ba_support);
                VIF_STATE_PRINT_INT(ba_allowed);
-               VIF_STATE_PRINT_INT(is_gem);
                VIF_STATE_PRINT_LLHEX(tx_security_seq);
                VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
        }
@@ -1002,108 +946,281 @@ static const struct file_operations beacon_filtering_ops = {
        .llseek = default_llseek,
 };
 
-static int wl1271_debugfs_add_files(struct wl1271 *wl,
-                                    struct dentry *rootdir)
+static ssize_t fw_stats_raw_read(struct file *file,
+                                char __user *userbuf,
+                                size_t count, loff_t *ppos)
 {
-       int ret = 0;
-       struct dentry *entry, *stats, *streaming;
+       struct wl1271 *wl = file->private_data;
 
-       stats = debugfs_create_dir("fw-statistics", rootdir);
-       if (!stats || IS_ERR(stats)) {
-               entry = stats;
-               goto err;
+       wl1271_debugfs_update_stats(wl);
+
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      wl->stats.fw_stats,
+                                      wl->stats.fw_stats_len);
+}
+
+static const struct file_operations fw_stats_raw_ops = {
+       .read = fw_stats_raw_read,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+static ssize_t sleep_auth_read(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+
+       return wl1271_format_buffer(user_buf, count,
+                                   ppos, "%d\n",
+                                   wl->sleep_auth);
+}
+
+static ssize_t sleep_auth_write(struct file *file,
+                               const char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 0, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in sleep_auth");
+               return -EINVAL;
+       }
+
+       if (value < 0 || value > WL1271_PSM_MAX) {
+               wl1271_warning("sleep_auth must be between 0 and %d",
+                              WL1271_PSM_MAX);
+               return -ERANGE;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       wl->conf.conn.sta_sleep_auth = value;
+
+       if (wl->state == WL1271_STATE_OFF) {
+               /* this will show up on "read" in case we are off */
+               wl->sleep_auth = value;
+               goto out;
        }
 
-       DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow);
-
-       DEBUGFS_FWSTATS_ADD(rx, out_of_mem);
-       DEBUGFS_FWSTATS_ADD(rx, hdr_overflow);
-       DEBUGFS_FWSTATS_ADD(rx, hw_stuck);
-       DEBUGFS_FWSTATS_ADD(rx, dropped);
-       DEBUGFS_FWSTATS_ADD(rx, fcs_err);
-       DEBUGFS_FWSTATS_ADD(rx, xfr_hint_trig);
-       DEBUGFS_FWSTATS_ADD(rx, path_reset);
-       DEBUGFS_FWSTATS_ADD(rx, reset_counter);
-
-       DEBUGFS_FWSTATS_ADD(dma, rx_requested);
-       DEBUGFS_FWSTATS_ADD(dma, rx_errors);
-       DEBUGFS_FWSTATS_ADD(dma, tx_requested);
-       DEBUGFS_FWSTATS_ADD(dma, tx_errors);
-
-       DEBUGFS_FWSTATS_ADD(isr, cmd_cmplt);
-       DEBUGFS_FWSTATS_ADD(isr, fiqs);
-       DEBUGFS_FWSTATS_ADD(isr, rx_headers);
-       DEBUGFS_FWSTATS_ADD(isr, rx_mem_overflow);
-       DEBUGFS_FWSTATS_ADD(isr, rx_rdys);
-       DEBUGFS_FWSTATS_ADD(isr, irqs);
-       DEBUGFS_FWSTATS_ADD(isr, tx_procs);
-       DEBUGFS_FWSTATS_ADD(isr, decrypt_done);
-       DEBUGFS_FWSTATS_ADD(isr, dma0_done);
-       DEBUGFS_FWSTATS_ADD(isr, dma1_done);
-       DEBUGFS_FWSTATS_ADD(isr, tx_exch_complete);
-       DEBUGFS_FWSTATS_ADD(isr, commands);
-       DEBUGFS_FWSTATS_ADD(isr, rx_procs);
-       DEBUGFS_FWSTATS_ADD(isr, hw_pm_mode_changes);
-       DEBUGFS_FWSTATS_ADD(isr, host_acknowledges);
-       DEBUGFS_FWSTATS_ADD(isr, pci_pm);
-       DEBUGFS_FWSTATS_ADD(isr, wakeups);
-       DEBUGFS_FWSTATS_ADD(isr, low_rssi);
-
-       DEBUGFS_FWSTATS_ADD(wep, addr_key_count);
-       DEBUGFS_FWSTATS_ADD(wep, default_key_count);
-       /* skipping wep.reserved */
-       DEBUGFS_FWSTATS_ADD(wep, key_not_found);
-       DEBUGFS_FWSTATS_ADD(wep, decrypt_fail);
-       DEBUGFS_FWSTATS_ADD(wep, packets);
-       DEBUGFS_FWSTATS_ADD(wep, interrupt);
-
-       DEBUGFS_FWSTATS_ADD(pwr, ps_enter);
-       DEBUGFS_FWSTATS_ADD(pwr, elp_enter);
-       DEBUGFS_FWSTATS_ADD(pwr, missing_bcns);
-       DEBUGFS_FWSTATS_ADD(pwr, wake_on_host);
-       DEBUGFS_FWSTATS_ADD(pwr, wake_on_timer_exp);
-       DEBUGFS_FWSTATS_ADD(pwr, tx_with_ps);
-       DEBUGFS_FWSTATS_ADD(pwr, tx_without_ps);
-       DEBUGFS_FWSTATS_ADD(pwr, rcvd_beacons);
-       DEBUGFS_FWSTATS_ADD(pwr, power_save_off);
-       DEBUGFS_FWSTATS_ADD(pwr, enable_ps);
-       DEBUGFS_FWSTATS_ADD(pwr, disable_ps);
-       DEBUGFS_FWSTATS_ADD(pwr, fix_tsf_ps);
-       /* skipping cont_miss_bcns_spread for now */
-       DEBUGFS_FWSTATS_ADD(pwr, rcvd_awake_beacons);
-
-       DEBUGFS_FWSTATS_ADD(mic, rx_pkts);
-       DEBUGFS_FWSTATS_ADD(mic, calc_failure);
-
-       DEBUGFS_FWSTATS_ADD(aes, encrypt_fail);
-       DEBUGFS_FWSTATS_ADD(aes, decrypt_fail);
-       DEBUGFS_FWSTATS_ADD(aes, encrypt_packets);
-       DEBUGFS_FWSTATS_ADD(aes, decrypt_packets);
-       DEBUGFS_FWSTATS_ADD(aes, encrypt_interrupt);
-       DEBUGFS_FWSTATS_ADD(aes, decrypt_interrupt);
-
-       DEBUGFS_FWSTATS_ADD(event, heart_beat);
-       DEBUGFS_FWSTATS_ADD(event, calibration);
-       DEBUGFS_FWSTATS_ADD(event, rx_mismatch);
-       DEBUGFS_FWSTATS_ADD(event, rx_mem_empty);
-       DEBUGFS_FWSTATS_ADD(event, rx_pool);
-       DEBUGFS_FWSTATS_ADD(event, oom_late);
-       DEBUGFS_FWSTATS_ADD(event, phy_transmit_error);
-       DEBUGFS_FWSTATS_ADD(event, tx_stuck);
-
-       DEBUGFS_FWSTATS_ADD(ps, pspoll_timeouts);
-       DEBUGFS_FWSTATS_ADD(ps, upsd_timeouts);
-       DEBUGFS_FWSTATS_ADD(ps, upsd_max_sptime);
-       DEBUGFS_FWSTATS_ADD(ps, upsd_max_apturn);
-       DEBUGFS_FWSTATS_ADD(ps, pspoll_max_apturn);
-       DEBUGFS_FWSTATS_ADD(ps, pspoll_utilization);
-       DEBUGFS_FWSTATS_ADD(ps, upsd_utilization);
-
-       DEBUGFS_FWSTATS_ADD(rxpipe, rx_prep_beacon_drop);
-       DEBUGFS_FWSTATS_ADD(rxpipe, descr_host_int_trig_rx_data);
-       DEBUGFS_FWSTATS_ADD(rxpipe, beacon_buffer_thres_host_int_trig_rx_data);
-       DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data);
-       DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1271_acx_sleep_auth(wl, value);
+       if (ret < 0)
+               goto out_sleep;
+
+out_sleep:
+       wl1271_ps_elp_sleep(wl);
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations sleep_auth_ops = {
+       .read = sleep_auth_read,
+       .write = sleep_auth_write,
+       .open = simple_open,
+       .llseek = default_llseek,
+};
+
+static ssize_t dev_mem_read(struct file *file,
+            char __user *user_buf, size_t count,
+            loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       struct wlcore_partition_set part, old_part;
+       size_t bytes = count;
+       int ret;
+       char *buf;
+
+       /* only requests of dword-aligned size and offset are supported */
+       if (bytes % 4)
+               return -EINVAL;
+
+       if (*ppos % 4)
+               return -EINVAL;
+
+       /* function should return in reasonable time */
+       bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
+
+       if (bytes == 0)
+               return -EINVAL;
+
+       memset(&part, 0, sizeof(part));
+       part.mem.start = file->f_pos;
+       part.mem.size = bytes;
+
+       buf = kmalloc(bytes, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF) {
+               ret = -EFAULT;
+               goto skip_read;
+       }
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto skip_read;
+
+       /* store current partition and switch partition */
+       memcpy(&old_part, &wl->curr_part, sizeof(old_part));
+       ret = wlcore_set_partition(wl, &part);
+       if (ret < 0)
+               goto part_err;
+
+       ret = wlcore_raw_read(wl, 0, buf, bytes, false);
+       if (ret < 0)
+               goto read_err;
+
+read_err:
+       /* recover partition */
+       ret = wlcore_set_partition(wl, &old_part);
+       if (ret < 0)
+               goto part_err;
+
+part_err:
+       wl1271_ps_elp_sleep(wl);
+
+skip_read:
+       mutex_unlock(&wl->mutex);
+
+       if (ret == 0) {
+               ret = copy_to_user(user_buf, buf, bytes);
+               if (ret < bytes) {
+                       bytes -= ret;
+                       *ppos += bytes;
+                       ret = 0;
+               } else {
+                       ret = -EFAULT;
+               }
+       }
+
+       kfree(buf);
+
+       return ((ret == 0) ? bytes : ret);
+}
+
+static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
+               size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       struct wlcore_partition_set part, old_part;
+       size_t bytes = count;
+       int ret;
+       char *buf;
+
+       /* only requests of dword-aligned size and offset are supported */
+       if (bytes % 4)
+               return -EINVAL;
+
+       if (*ppos % 4)
+               return -EINVAL;
+
+       /* function should return in reasonable time */
+       bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
+
+       if (bytes == 0)
+               return -EINVAL;
+
+       memset(&part, 0, sizeof(part));
+       part.mem.start = file->f_pos;
+       part.mem.size = bytes;
+
+       buf = kmalloc(bytes, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = copy_from_user(buf, user_buf, bytes);
+       if (ret) {
+               ret = -EFAULT;
+               goto err_out;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF) {
+               ret = -EFAULT;
+               goto skip_write;
+       }
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto skip_write;
+
+       /* store current partition and switch partition */
+       memcpy(&old_part, &wl->curr_part, sizeof(old_part));
+       ret = wlcore_set_partition(wl, &part);
+       if (ret < 0)
+               goto part_err;
+
+       ret = wlcore_raw_write(wl, 0, buf, bytes, false);
+       if (ret < 0)
+               goto write_err;
+
+write_err:
+       /* recover partition */
+       ret = wlcore_set_partition(wl, &old_part);
+       if (ret < 0)
+               goto part_err;
+
+part_err:
+       wl1271_ps_elp_sleep(wl);
+
+skip_write:
+       mutex_unlock(&wl->mutex);
+
+       if (ret == 0)
+               *ppos += bytes;
+
+err_out:
+       kfree(buf);
+
+       return ((ret == 0) ? bytes : ret);
+}
+
+static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
+{
+       loff_t ret;
+
+       /* only requests of dword-aligned size and offset are supported */
+       if (offset % 4)
+               return -EINVAL;
+
+       switch (orig) {
+       case SEEK_SET:
+               file->f_pos = offset;
+               ret = file->f_pos;
+               break;
+       case SEEK_CUR:
+               file->f_pos += offset;
+               ret = file->f_pos;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct file_operations dev_mem_ops = {
+       .open = simple_open,
+       .read = dev_mem_read,
+       .write = dev_mem_write,
+       .llseek = dev_mem_seek,
+};
+
+static int wl1271_debugfs_add_files(struct wl1271 *wl,
+                                   struct dentry *rootdir)
+{
+       int ret = 0;
+       struct dentry *entry, *streaming;
 
        DEBUGFS_ADD(tx_queue_len, rootdir);
        DEBUGFS_ADD(retry_count, rootdir);
@@ -1120,6 +1237,11 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
        DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
        DEBUGFS_ADD(forced_ps, rootdir);
        DEBUGFS_ADD(split_scan_timeout, rootdir);
+       DEBUGFS_ADD(irq_pkt_threshold, rootdir);
+       DEBUGFS_ADD(irq_blk_threshold, rootdir);
+       DEBUGFS_ADD(irq_timeout, rootdir);
+       DEBUGFS_ADD(fw_stats_raw, rootdir);
+       DEBUGFS_ADD(sleep_auth, rootdir);
 
        streaming = debugfs_create_dir("rx_streaming", rootdir);
        if (!streaming || IS_ERR(streaming))
@@ -1128,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
        DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
        DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
 
+       DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
 
        return 0;
 
@@ -1145,7 +1268,7 @@ void wl1271_debugfs_reset(struct wl1271 *wl)
        if (!wl->stats.fw_stats)
                return;
 
-       memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
+       memset(wl->stats.fw_stats, 0, wl->stats.fw_stats_len);
        wl->stats.retry_count = 0;
        wl->stats.excessive_retries = 0;
 }
@@ -1160,34 +1283,34 @@ int wl1271_debugfs_init(struct wl1271 *wl)
 
        if (IS_ERR(rootdir)) {
                ret = PTR_ERR(rootdir);
-               goto err;
+               goto out;
        }
 
-       wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats),
-                                     GFP_KERNEL);
-
+       wl->stats.fw_stats = kzalloc(wl->stats.fw_stats_len, GFP_KERNEL);
        if (!wl->stats.fw_stats) {
                ret = -ENOMEM;
-               goto err_fw;
+               goto out_remove;
        }
 
        wl->stats.fw_stats_update = jiffies;
 
        ret = wl1271_debugfs_add_files(wl, rootdir);
+       if (ret < 0)
+               goto out_exit;
 
+       ret = wlcore_debugfs_init(wl, rootdir);
        if (ret < 0)
-               goto err_file;
+               goto out_exit;
 
-       return 0;
+       goto out;
 
-err_file:
-       kfree(wl->stats.fw_stats);
-       wl->stats.fw_stats = NULL;
+out_exit:
+       wl1271_debugfs_exit(wl);
 
-err_fw:
+out_remove:
        debugfs_remove_recursive(rootdir);
 
-err:
+out:
        return ret;
 }
 
index a8d3aef011ffc6274f97bfe505ea2d6defca1d47..f7381dd69009a150e1901a876494d225e0267f5e 100644 (file)
 
 #include "wlcore.h"
 
+int wl1271_format_buffer(char __user *userbuf, size_t count,
+                        loff_t *ppos, char *fmt, ...);
+
 int wl1271_debugfs_init(struct wl1271 *wl);
 void wl1271_debugfs_exit(struct wl1271 *wl);
 void wl1271_debugfs_reset(struct wl1271 *wl);
+void wl1271_debugfs_update_stats(struct wl1271 *wl);
+
+#define DEBUGFS_FORMAT_BUFFER_SIZE 256
+
+#define DEBUGFS_READONLY_FILE(name, fmt, value...)                     \
+static ssize_t name## _read(struct file *file, char __user *userbuf,   \
+                           size_t count, loff_t *ppos)                 \
+{                                                                      \
+       struct wl1271 *wl = file->private_data;                         \
+       return wl1271_format_buffer(userbuf, count, ppos,               \
+                                   fmt "\n", ##value);                 \
+}                                                                      \
+                                                                       \
+static const struct file_operations name## _ops = {                    \
+       .read = name## _read,                                           \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_ADD(name, parent)                                      \
+       do {                                                            \
+               entry = debugfs_create_file(#name, 0400, parent,        \
+                                           wl, &name## _ops);          \
+               if (!entry || IS_ERR(entry))                            \
+                       goto err;                                       \
+       } while (0);
+
+
+#define DEBUGFS_ADD_PREFIX(prefix, name, parent)                       \
+       do {                                                            \
+               entry = debugfs_create_file(#name, 0400, parent,        \
+                                   wl, &prefix## _## name## _ops);     \
+               if (!entry || IS_ERR(entry))                            \
+                       goto err;                                       \
+       } while (0);
+
+#define DEBUGFS_FWSTATS_FILE(sub, name, fmt, struct_type)              \
+static ssize_t sub## _ ##name## _read(struct file *file,               \
+                                     char __user *userbuf,             \
+                                     size_t count, loff_t *ppos)       \
+{                                                                      \
+       struct wl1271 *wl = file->private_data;                         \
+       struct struct_type *stats = wl->stats.fw_stats;                 \
+                                                                       \
+       wl1271_debugfs_update_stats(wl);                                \
+                                                                       \
+       return wl1271_format_buffer(userbuf, count, ppos, fmt "\n",     \
+                                   stats->sub.name);                   \
+}                                                                      \
+                                                                       \
+static const struct file_operations sub## _ ##name## _ops = {          \
+       .read = sub## _ ##name## _read,                                 \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_FWSTATS_FILE_ARRAY(sub, name, len, struct_type)                \
+static ssize_t sub## _ ##name## _read(struct file *file,               \
+                                     char __user *userbuf,             \
+                                     size_t count, loff_t *ppos)       \
+{                                                                      \
+       struct wl1271 *wl = file->private_data;                         \
+       struct struct_type *stats = wl->stats.fw_stats;                 \
+       char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = "";                      \
+       int res, i;                                                     \
+                                                                       \
+       wl1271_debugfs_update_stats(wl);                                \
+                                                                       \
+       for (i = 0; i < len; i++)                                       \
+               res = snprintf(buf, sizeof(buf), "%s[%d] = %d\n",       \
+                              buf, i, stats->sub.name[i]);             \
+                                                                       \
+       return wl1271_format_buffer(userbuf, count, ppos, "%s", buf);   \
+}                                                                      \
+                                                                       \
+static const struct file_operations sub## _ ##name## _ops = {          \
+       .read = sub## _ ##name## _read,                                 \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_FWSTATS_ADD(sub, name)                                 \
+       DEBUGFS_ADD(sub## _ ##name, stats)
+
 
 #endif /* WL1271_DEBUGFS_H */
index 28e2a633c3be0eb96689f1414520c03c10de8060..48907054d493134354ad22b0305cbc45a89bde2f 100644 (file)
@@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl)
        u32 vector;
        bool disconnect_sta = false;
        unsigned long sta_bitmap = 0;
+       int ret;
 
        wl1271_event_mbox_dump(mbox);
 
@@ -148,15 +149,33 @@ static int wl1271_event_process(struct wl1271 *wl)
                int delay = wl->conf.conn.synch_fail_thold *
                                        wl->conf.conn.bss_lose_timeout;
                wl1271_info("Beacon loss detected.");
-               cancel_delayed_work_sync(&wl->connection_loss_work);
+
+               /*
+                * if the work is already queued, it should take place. We
+                * don't want to delay the connection loss indication
+                * any more.
+                */
                ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
-                     msecs_to_jiffies(delay));
+                                            msecs_to_jiffies(delay));
+
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       vif = wl12xx_wlvif_to_vif(wlvif);
+
+                       ieee80211_cqm_rssi_notify(
+                                       vif,
+                                       NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+                                       GFP_KERNEL);
+               }
        }
 
        if (vector & REGAINED_BSS_EVENT_ID) {
                /* TODO: check for multi-role */
                wl1271_info("Beacon regained.");
-               cancel_delayed_work_sync(&wl->connection_loss_work);
+               cancel_delayed_work(&wl->connection_loss_work);
+
+               /* sanity check - we can't lose and gain the beacon together */
+               WARN(vector & BSS_LOSE_EVENT_ID,
+                    "Concurrent beacon loss and gain from FW");
        }
 
        if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
@@ -210,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl)
 
        if ((vector & DUMMY_PACKET_EVENT_ID)) {
                wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
-               wl1271_tx_dummy_packet(wl);
+               ret = wl1271_tx_dummy_packet(wl);
+               if (ret < 0)
+                       return ret;
        }
 
        /*
@@ -283,8 +304,10 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
                return -EINVAL;
 
        /* first we read the mbox descriptor */
-       wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
-                   sizeof(*wl->mbox), false);
+       ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
+                         sizeof(*wl->mbox), false);
+       if (ret < 0)
+               return ret;
 
        /* process the descriptor */
        ret = wl1271_event_process(wl);
@@ -295,7 +318,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
         * TODO: we just need this because one bit is in a different
         * place.  Is there any better way?
         */
-       wl->ops->ack_event(wl);
+       ret = wl->ops->ack_event(wl);
 
-       return 0;
+       return ret;
 }
index 9384b4d56c24a9dc1386732c86d1ac74ca75832b..2673d783ec1ecdda33d6dcd6f265f12dc6930c5e 100644 (file)
@@ -65,11 +65,13 @@ wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
        return wl->ops->get_rx_buf_align(wl, rx_desc);
 }
 
-static inline void
+static inline int
 wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
 {
        if (wl->ops->prepare_read)
-               wl->ops->prepare_read(wl, rx_desc, len);
+               return wl->ops->prepare_read(wl, rx_desc, len);
+
+       return 0;
 }
 
 static inline u32
@@ -81,10 +83,12 @@ wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len)
        return wl->ops->get_rx_packet_len(wl, rx_data, data_len);
 }
 
-static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl)
+static inline int wlcore_hw_tx_delayed_compl(struct wl1271 *wl)
 {
        if (wl->ops->tx_delayed_compl)
-               wl->ops->tx_delayed_compl(wl);
+               return wl->ops->tx_delayed_compl(wl);
+
+       return 0;
 }
 
 static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl)
@@ -119,4 +123,82 @@ static inline int wlcore_identify_fw(struct wl1271 *wl)
        return 0;
 }
 
+static inline void
+wlcore_hw_set_tx_desc_csum(struct wl1271 *wl,
+                          struct wl1271_tx_hw_descr *desc,
+                          struct sk_buff *skb)
+{
+       if (!wl->ops->set_tx_desc_csum)
+               BUG_ON(1);
+
+       wl->ops->set_tx_desc_csum(wl, desc, skb);
+}
+
+static inline void
+wlcore_hw_set_rx_csum(struct wl1271 *wl,
+                     struct wl1271_rx_descriptor *desc,
+                     struct sk_buff *skb)
+{
+       if (wl->ops->set_rx_csum)
+               wl->ops->set_rx_csum(wl, desc, skb);
+}
+
+static inline u32
+wlcore_hw_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
+                                    struct wl12xx_vif *wlvif)
+{
+       if (wl->ops->ap_get_mimo_wide_rate_mask)
+               return wl->ops->ap_get_mimo_wide_rate_mask(wl, wlvif);
+
+       return 0;
+}
+
+static inline int
+wlcore_debugfs_init(struct wl1271 *wl, struct dentry *rootdir)
+{
+       if (wl->ops->debugfs_init)
+               return wl->ops->debugfs_init(wl, rootdir);
+
+       return 0;
+}
+
+static inline int
+wlcore_handle_static_data(struct wl1271 *wl, void *static_data)
+{
+       if (wl->ops->handle_static_data)
+               return wl->ops->handle_static_data(wl, static_data);
+
+       return 0;
+}
+
+static inline int
+wlcore_hw_get_spare_blocks(struct wl1271 *wl, bool is_gem)
+{
+       if (!wl->ops->get_spare_blocks)
+               BUG_ON(1);
+
+       return wl->ops->get_spare_blocks(wl, is_gem);
+}
+
+static inline int
+wlcore_hw_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+                 struct ieee80211_vif *vif,
+                 struct ieee80211_sta *sta,
+                 struct ieee80211_key_conf *key_conf)
+{
+       if (!wl->ops->set_key)
+               BUG_ON(1);
+
+       return wl->ops->set_key(wl, cmd, vif, sta, key_conf);
+}
+
+static inline u32
+wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
+{
+       if (wl->ops->pre_pkt_send)
+               return wl->ops->pre_pkt_send(wl, buf_offset, last_len);
+
+       return buf_offset;
+}
+
 #endif
index 4cf9ecc56212322b54ae70d414bcebbc93b96715..d24fe3bbc6726dc8f24a41bf53552a4ba5711cc3 100644 (file)
@@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 {
 
 /* NVS data structure */
 #define WL1271_INI_NVS_SECTION_SIZE                 468
-#define WL1271_INI_FEM_MODULE_COUNT                  2
+
+/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */
+#define WL1271_INI_FEM_MODULE_COUNT                  4
+
+/*
+ * In NVS we only store two FEM module entries -
+ *       FEM modules 0,2,3 are stored in entry 0
+ *       FEM module 1 is stored in entry 1
+ */
+#define WL12XX_NVS_FEM_MODULE_COUNT                  2
+
+#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module)      \
+       ((ini_fem_module) == 1 ? 1 : 0)
 
 #define WL1271_INI_LEGACY_NVS_FILE_SIZE              800
 
@@ -188,13 +200,13 @@ struct wl1271_nvs_file {
        struct {
                struct wl1271_ini_fem_params_2 params;
                u8 padding;
-       } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+       } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
        struct wl1271_ini_band_params_5 stat_radio_params_5;
        u8 padding3;
        struct {
                struct wl1271_ini_fem_params_5 params;
                u8 padding;
-       } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+       } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
 } __packed;
 
 struct wl128x_nvs_file {
@@ -209,12 +221,12 @@ struct wl128x_nvs_file {
        struct {
                struct wl128x_ini_fem_params_2 params;
                u8 padding;
-       } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+       } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT];
        struct wl128x_ini_band_params_5 stat_radio_params_5;
        u8 padding3;
        struct {
                struct wl128x_ini_fem_params_5 params;
                u8 padding;
-       } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+       } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT];
 } __packed;
 #endif
index 9f89255eb6e616e6fd47c2544121584f32156e06..8a8a8971befa9ad0c891ff7aae336bdd808e684d 100644 (file)
@@ -460,6 +460,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        /* unconditionally enable HT rates */
        supported_rates |= CONF_TX_MCS_RATES;
 
+       /* get extra MIMO or wide-chan rates where the HW supports it */
+       supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
+
        /* configure unicast TX rate classes */
        for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
                rc.enabled_rates = supported_rates;
@@ -551,29 +554,28 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
        bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
        int ret, i;
 
-       /*
-        * consider all existing roles before configuring psm.
-        * TODO: reconfigure on interface removal.
-        */
-       if (!wl->ap_count) {
-               if (is_ap) {
-                       /* Configure for power always on */
+       /* consider all existing roles before configuring psm. */
+
+       if (wl->ap_count == 0 && is_ap) { /* first AP */
+               /* Configure for power always on */
+               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+               if (ret < 0)
+                       return ret;
+       /* first STA, no APs */
+       } else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
+               u8 sta_auth = wl->conf.conn.sta_sleep_auth;
+               /* Configure for power according to debugfs */
+               if (sta_auth != WL1271_PSM_ILLEGAL)
+                       ret = wl1271_acx_sleep_auth(wl, sta_auth);
+               /* Configure for power always on */
+               else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
                        ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-                       if (ret < 0)
-                               return ret;
-               } else if (!wl->sta_count) {
-                       if (wl->quirks & WLCORE_QUIRK_NO_ELP) {
-                               /* Configure for power always on */
-                               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-                               if (ret < 0)
-                                       return ret;
-                       } else {
-                               /* Configure for ELP power saving */
-                               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
-                               if (ret < 0)
-                                       return ret;
-                       }
-               }
+               /* Configure for ELP power saving */
+               else
+                       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
+
+               if (ret < 0)
+                       return ret;
        }
 
        /* Mode specific init */
index 7cd0081aede5f77cf6279045240d4622afe389cb..9976219c4e49c8a9b40520bdf1524d8d7abc902c 100644 (file)
@@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl)
 }
 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
 
+void wlcore_disable_interrupts_nosync(struct wl1271 *wl)
+{
+       disable_irq_nosync(wl->irq);
+}
+EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync);
+
 void wlcore_enable_interrupts(struct wl1271 *wl)
 {
        enable_irq(wl->irq);
@@ -122,9 +128,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr);
  *                                    |    |
  *
  */
-void wlcore_set_partition(struct wl1271 *wl,
-                         const struct wlcore_partition_set *p)
+int wlcore_set_partition(struct wl1271 *wl,
+                        const struct wlcore_partition_set *p)
 {
+       int ret;
+
        /* copy partition info */
        memcpy(&wl->curr_part, p, sizeof(*p));
 
@@ -137,28 +145,41 @@ void wlcore_set_partition(struct wl1271 *wl,
        wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X",
                     p->mem3.start, p->mem3.size);
 
-       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);
+       ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
+       if (ret < 0)
+               goto out;
+
        /*
         * We don't need the size of the last partition, as it is
         * automatically calculated based on the total memory size and
         * the sizes of the previous partitions.
         */
-       wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
-}
-EXPORT_SYMBOL_GPL(wlcore_set_partition);
+       ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
 
-void wlcore_select_partition(struct wl1271 *wl, u8 part)
-{
-       wl1271_debug(DEBUG_IO, "setting partition %d", part);
-
-       wlcore_set_partition(wl, &wl->ptable[part]);
+out:
+       return ret;
 }
-EXPORT_SYMBOL_GPL(wlcore_select_partition);
+EXPORT_SYMBOL_GPL(wlcore_set_partition);
 
 void wl1271_io_reset(struct wl1271 *wl)
 {
index 8942954b56a0f435a5cdccfc6e7d96f7ccbf9dc7..fef80adc8bf5ac24f5cd0880c0dcae837e3eae20 100644 (file)
@@ -45,6 +45,7 @@
 struct wl1271;
 
 void wlcore_disable_interrupts(struct wl1271 *wl);
+void wlcore_disable_interrupts_nosync(struct wl1271 *wl);
 void wlcore_enable_interrupts(struct wl1271 *wl);
 
 void wl1271_io_reset(struct wl1271 *wl);
@@ -52,79 +53,113 @@ void wl1271_io_init(struct wl1271 *wl);
 int wlcore_translate_addr(struct wl1271 *wl, int addr);
 
 /* Raw target IO, address is not translated */
-static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
-                                   size_t len, bool fixed)
+static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
+                                               void *buf, size_t len,
+                                               bool fixed)
 {
-       wl->if_ops->write(wl->dev, addr, buf, len, fixed);
+       int ret;
+
+       if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
+               return -EIO;
+
+       ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
+       if (ret)
+               set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
+
+       return ret;
 }
 
-static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
-                                  size_t len, bool fixed)
+static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
+                                              void *buf, size_t len,
+                                              bool fixed)
 {
-       wl->if_ops->read(wl->dev, addr, buf, len, fixed);
+       int ret;
+
+       if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags))
+               return -EIO;
+
+       ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
+       if (ret)
+               set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags);
+
+       return ret;
 }
 
-static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf,
-                                       size_t len, bool fixed)
+static inline int __must_check wlcore_raw_read_data(struct wl1271 *wl, int reg,
+                                                   void *buf, size_t len,
+                                                   bool fixed)
 {
-       wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed);
+       return wlcore_raw_read(wl, wl->rtable[reg], buf, len, fixed);
 }
 
-static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf,
-                                        size_t len, bool fixed)
+static inline int __must_check wlcore_raw_write_data(struct wl1271 *wl, int reg,
+                                                    void *buf, size_t len,
+                                                    bool fixed)
 {
-       wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed);
+       return wlcore_raw_write(wl, wl->rtable[reg], buf, len, fixed);
 }
 
-static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
+static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr,
+                                                u32 *val)
 {
-       wl1271_raw_read(wl, addr, &wl->buffer_32,
-                           sizeof(wl->buffer_32), false);
+       int ret;
+
+       ret = wlcore_raw_read(wl, addr, &wl->buffer_32,
+                             sizeof(wl->buffer_32), false);
+       if (ret < 0)
+               return ret;
+
+       if (val)
+               *val = le32_to_cpu(wl->buffer_32);
 
-       return le32_to_cpu(wl->buffer_32);
+       return 0;
 }
 
-static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
+static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr,
+                                                 u32 val)
 {
        wl->buffer_32 = cpu_to_le32(val);
-       wl1271_raw_write(wl, addr, &wl->buffer_32,
-                            sizeof(wl->buffer_32), false);
+       return wlcore_raw_write(wl, addr, &wl->buffer_32,
+                               sizeof(wl->buffer_32), false);
 }
 
-static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
-                              size_t len, bool fixed)
+static inline int __must_check wlcore_read(struct wl1271 *wl, int addr,
+                                          void *buf, size_t len, bool fixed)
 {
        int physical;
 
        physical = wlcore_translate_addr(wl, addr);
 
-       wl1271_raw_read(wl, physical, buf, len, fixed);
+       return wlcore_raw_read(wl, physical, buf, len, fixed);
 }
 
-static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
-                               size_t len, bool fixed)
+static inline int __must_check wlcore_write(struct wl1271 *wl, int addr,
+                                           void *buf, size_t len, bool fixed)
 {
        int physical;
 
        physical = wlcore_translate_addr(wl, addr);
 
-       wl1271_raw_write(wl, physical, buf, len, fixed);
+       return wlcore_raw_write(wl, physical, buf, len, fixed);
 }
 
-static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf,
-                                    size_t len, bool fixed)
+static inline int __must_check wlcore_write_data(struct wl1271 *wl, int reg,
+                                                void *buf, size_t len,
+                                                bool fixed)
 {
-       wl1271_write(wl, wl->rtable[reg], buf, len, fixed);
+       return wlcore_write(wl, wl->rtable[reg], buf, len, fixed);
 }
 
-static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf,
-                                   size_t len, bool fixed)
+static inline int __must_check wlcore_read_data(struct wl1271 *wl, int reg,
+                                               void *buf, size_t len,
+                                               bool fixed)
 {
-       wl1271_read(wl, wl->rtable[reg], buf, len, fixed);
+       return wlcore_read(wl, wl->rtable[reg], buf, len, fixed);
 }
 
-static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
-                                     void *buf, size_t len, bool fixed)
+static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr,
+                                                 void *buf, size_t len,
+                                                 bool fixed)
 {
        int physical;
        int addr;
@@ -134,34 +169,47 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr,
 
        physical = wlcore_translate_addr(wl, addr);
 
-       wl1271_raw_read(wl, physical, buf, len, fixed);
+       return wlcore_raw_read(wl, physical, buf, len, fixed);
 }
 
-static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+static inline int __must_check wlcore_read32(struct wl1271 *wl, int addr,
+                                            u32 *val)
 {
-       return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr));
+       return wlcore_raw_read32(wl, wlcore_translate_addr(wl, addr), val);
 }
 
-static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+static inline int __must_check wlcore_write32(struct wl1271 *wl, int addr,
+                                             u32 val)
 {
-       wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
+       return wlcore_raw_write32(wl, wlcore_translate_addr(wl, addr), val);
 }
 
-static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg)
+static inline int __must_check wlcore_read_reg(struct wl1271 *wl, int reg,
+                                              u32 *val)
 {
-       return wl1271_raw_read32(wl,
-                                wlcore_translate_addr(wl, wl->rtable[reg]));
+       return wlcore_raw_read32(wl,
+                                wlcore_translate_addr(wl, wl->rtable[reg]),
+                                val);
 }
 
-static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val)
+static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg,
+                                               u32 val)
 {
-       wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val);
+       return wlcore_raw_write32(wl,
+                                 wlcore_translate_addr(wl, wl->rtable[reg]),
+                                 val);
 }
 
 static inline void wl1271_power_off(struct wl1271 *wl)
 {
-       wl->if_ops->power(wl->dev, false);
-       clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+       int ret;
+
+       if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags))
+               return;
+
+       ret = wl->if_ops->power(wl->dev, false);
+       if (!ret)
+               clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 
 static inline int wl1271_power_on(struct wl1271 *wl)
@@ -173,8 +221,8 @@ static inline int wl1271_power_on(struct wl1271 *wl)
        return ret;
 }
 
-void wlcore_set_partition(struct wl1271 *wl,
-                         const struct wlcore_partition_set *p);
+int wlcore_set_partition(struct wl1271 *wl,
+                        const struct wlcore_partition_set *p);
 
 bool wl1271_set_block_size(struct wl1271 *wl);
 
@@ -182,6 +230,4 @@ bool wl1271_set_block_size(struct wl1271 *wl);
 
 int wl1271_tx_dummy_packet(struct wl1271 *wl);
 
-void wlcore_select_partition(struct wl1271 *wl, u8 part);
-
 #endif
index acef93390d3d4f3cf668da5fb0d4912b56688477..2240cca597acf812d87a4291aa855d4e39272f90 100644 (file)
@@ -320,46 +320,6 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
        }
 }
 
-static int wl1271_plt_init(struct wl1271 *wl)
-{
-       int ret;
-
-       ret = wl->ops->hw_init(wl);
-       if (ret < 0)
-               return ret;
-
-       ret = wl1271_acx_init_mem_config(wl);
-       if (ret < 0)
-               return ret;
-
-       ret = wl12xx_acx_mem_cfg(wl);
-       if (ret < 0)
-               goto out_free_memmap;
-
-       /* Enable data path */
-       ret = wl1271_cmd_data_path(wl, 1);
-       if (ret < 0)
-               goto out_free_memmap;
-
-       /* Configure for CAM power saving (ie. always active) */
-       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-       if (ret < 0)
-               goto out_free_memmap;
-
-       /* configure PM */
-       ret = wl1271_acx_pm_config(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;
-}
-
 static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
                                        struct wl12xx_vif *wlvif,
                                        u8 hlid, u8 tx_pkts)
@@ -387,7 +347,7 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
 
 static void wl12xx_irq_update_links_status(struct wl1271 *wl,
                                           struct wl12xx_vif *wlvif,
-                                          struct wl_fw_status *status)
+                                          struct wl_fw_status_2 *status)
 {
        struct wl1271_link *lnk;
        u32 cur_fw_ps_map;
@@ -418,8 +378,9 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl,
        }
 }
 
-static void wl12xx_fw_status(struct wl1271 *wl,
-                            struct wl_fw_status *status)
+static int wlcore_fw_status(struct wl1271 *wl,
+                           struct wl_fw_status_1 *status_1,
+                           struct wl_fw_status_2 *status_2)
 {
        struct wl12xx_vif *wlvif;
        struct timespec ts;
@@ -427,38 +388,42 @@ static void wl12xx_fw_status(struct wl1271 *wl,
        int avail, freed_blocks;
        int i;
        size_t status_len;
+       int ret;
 
-       status_len = sizeof(*status) + wl->fw_status_priv_len;
+       status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+               sizeof(*status_2) + wl->fw_status_priv_len;
 
-       wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status,
-                            status_len, false);
+       ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1,
+                                  status_len, false);
+       if (ret < 0)
+               return ret;
 
        wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
                     "drv_rx_counter = %d, tx_results_counter = %d)",
-                    status->intr,
-                    status->fw_rx_counter,
-                    status->drv_rx_counter,
-                    status->tx_results_counter);
+                    status_1->intr,
+                    status_1->fw_rx_counter,
+                    status_1->drv_rx_counter,
+                    status_1->tx_results_counter);
 
        for (i = 0; i < NUM_TX_QUEUES; i++) {
                /* prevent wrap-around in freed-packets counter */
                wl->tx_allocated_pkts[i] -=
-                               (status->counters.tx_released_pkts[i] -
+                               (status_2->counters.tx_released_pkts[i] -
                                wl->tx_pkts_freed[i]) & 0xff;
 
-               wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i];
+               wl->tx_pkts_freed[i] = status_2->counters.tx_released_pkts[i];
        }
 
        /* prevent wrap-around in total blocks counter */
        if (likely(wl->tx_blocks_freed <=
-                  le32_to_cpu(status->total_released_blks)))
-               freed_blocks = le32_to_cpu(status->total_released_blks) -
+                  le32_to_cpu(status_2->total_released_blks)))
+               freed_blocks = le32_to_cpu(status_2->total_released_blks) -
                               wl->tx_blocks_freed;
        else
                freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
-                              le32_to_cpu(status->total_released_blks);
+                              le32_to_cpu(status_2->total_released_blks);
 
-       wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
+       wl->tx_blocks_freed = le32_to_cpu(status_2->total_released_blks);
 
        wl->tx_allocated_blocks -= freed_blocks;
 
@@ -474,7 +439,7 @@ static void wl12xx_fw_status(struct wl1271 *wl,
                        cancel_delayed_work(&wl->tx_watchdog_work);
        }
 
-       avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
+       avail = le32_to_cpu(status_2->tx_total) - wl->tx_allocated_blocks;
 
        /*
         * The FW might change the total number of TX memblocks before
@@ -493,13 +458,15 @@ static void wl12xx_fw_status(struct wl1271 *wl,
 
        /* for AP update num of allocated TX blocks per link and ps status */
        wl12xx_for_each_wlvif_ap(wl, wlvif) {
-               wl12xx_irq_update_links_status(wl, wlvif, status);
+               wl12xx_irq_update_links_status(wl, wlvif, status_2);
        }
 
        /* update the host-chipset time offset */
        getnstimeofday(&ts);
        wl->time_offset = (timespec_to_ns(&ts) >> 10) -
-               (s64)le32_to_cpu(status->fw_localtime);
+               (s64)le32_to_cpu(status_2->fw_localtime);
+
+       return 0;
 }
 
 static void wl1271_flush_deferred_work(struct wl1271 *wl)
@@ -527,20 +494,15 @@ static void wl1271_netstack_work(struct work_struct *work)
 
 #define WL1271_IRQ_MAX_LOOPS 256
 
-static irqreturn_t wl1271_irq(int irq, void *cookie)
+static int wlcore_irq_locked(struct wl1271 *wl)
 {
-       int ret;
+       int ret = 0;
        u32 intr;
        int loopcount = WL1271_IRQ_MAX_LOOPS;
-       struct wl1271 *wl = (struct wl1271 *)cookie;
        bool done = false;
        unsigned int defer_count;
        unsigned long flags;
 
-       /* TX might be handled here, avoid redundant work */
-       set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
-       cancel_work_sync(&wl->tx_work);
-
        /*
         * In case edge triggered interrupt must be used, we cannot iterate
         * more than once without introducing race conditions with the hardirq.
@@ -548,8 +510,6 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
        if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
                loopcount = 1;
 
-       mutex_lock(&wl->mutex);
-
        wl1271_debug(DEBUG_IRQ, "IRQ work");
 
        if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -568,21 +528,33 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
                clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
                smp_mb__after_clear_bit();
 
-               wl12xx_fw_status(wl, wl->fw_status);
+               ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
+               if (ret < 0)
+                       goto out;
 
                wlcore_hw_tx_immediate_compl(wl);
 
-               intr = le32_to_cpu(wl->fw_status->intr);
-               intr &= WL1271_INTR_MASK;
+               intr = le32_to_cpu(wl->fw_status_1->intr);
+               intr &= WLCORE_ALL_INTR_MASK;
                if (!intr) {
                        done = true;
                        continue;
                }
 
                if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
-                       wl1271_error("watchdog interrupt received! "
+                       wl1271_error("HW watchdog interrupt received! starting recovery.");
+                       wl->watchdog_recovery = true;
+                       ret = -EIO;
+
+                       /* restarting the chip. ignore any other interrupt. */
+                       goto out;
+               }
+
+               if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) {
+                       wl1271_error("SW watchdog interrupt received! "
                                     "starting recovery.");
-                       wl12xx_queue_recovery_work(wl);
+                       wl->watchdog_recovery = true;
+                       ret = -EIO;
 
                        /* restarting the chip. ignore any other interrupt. */
                        goto out;
@@ -591,7 +563,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
                if (likely(intr & WL1271_ACX_INTR_DATA)) {
                        wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
 
-                       wl12xx_rx(wl, wl->fw_status);
+                       ret = wlcore_rx(wl, wl->fw_status_1);
+                       if (ret < 0)
+                               goto out;
 
                        /* Check if any tx blocks were freed */
                        spin_lock_irqsave(&wl->wl_lock, flags);
@@ -602,13 +576,17 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
                                 * In order to avoid starvation of the TX path,
                                 * call the work function directly.
                                 */
-                               wl1271_tx_work_locked(wl);
+                               ret = wlcore_tx_work_locked(wl);
+                               if (ret < 0)
+                                       goto out;
                        } else {
                                spin_unlock_irqrestore(&wl->wl_lock, flags);
                        }
 
                        /* check for tx results */
-                       wlcore_hw_tx_delayed_compl(wl);
+                       ret = wlcore_hw_tx_delayed_compl(wl);
+                       if (ret < 0)
+                               goto out;
 
                        /* Make sure the deferred queues don't get too long */
                        defer_count = skb_queue_len(&wl->deferred_tx_queue) +
@@ -619,12 +597,16 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
 
                if (intr & WL1271_ACX_INTR_EVENT_A) {
                        wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
-                       wl1271_event_handle(wl, 0);
+                       ret = wl1271_event_handle(wl, 0);
+                       if (ret < 0)
+                               goto out;
                }
 
                if (intr & WL1271_ACX_INTR_EVENT_B) {
                        wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
-                       wl1271_event_handle(wl, 1);
+                       ret = wl1271_event_handle(wl, 1);
+                       if (ret < 0)
+                               goto out;
                }
 
                if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@@ -638,6 +620,25 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
        wl1271_ps_elp_sleep(wl);
 
 out:
+       return ret;
+}
+
+static irqreturn_t wlcore_irq(int irq, void *cookie)
+{
+       int ret;
+       unsigned long flags;
+       struct wl1271 *wl = cookie;
+
+       /* TX might be handled here, avoid redundant work */
+       set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
+       cancel_work_sync(&wl->tx_work);
+
+       mutex_lock(&wl->mutex);
+
+       ret = wlcore_irq_locked(wl);
+       if (ret)
+               wl12xx_queue_recovery_work(wl);
+
        spin_lock_irqsave(&wl->wl_lock, flags);
        /* In case TX was not handled here, queue TX work */
        clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
@@ -743,7 +744,7 @@ out:
        return ret;
 }
 
-static int wl1271_fetch_nvs(struct wl1271 *wl)
+static void wl1271_fetch_nvs(struct wl1271 *wl)
 {
        const struct firmware *fw;
        int ret;
@@ -751,16 +752,15 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
        ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
 
        if (ret < 0) {
-               wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
-                            ret);
-               return ret;
+               wl1271_debug(DEBUG_BOOT, "could not get nvs file %s: %d",
+                            WL12XX_NVS_NAME, ret);
+               return;
        }
 
        wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
 
        if (!wl->nvs) {
                wl1271_error("could not allocate memory for the nvs file");
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -768,14 +768,17 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 
 out:
        release_firmware(fw);
-
-       return ret;
 }
 
 void wl12xx_queue_recovery_work(struct wl1271 *wl)
 {
-       if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+       WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
+
+       /* Avoid a recursive recovery */
+       if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+               wlcore_disable_interrupts_nosync(wl);
                ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       }
 }
 
 size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
@@ -801,14 +804,17 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
        return len;
 }
 
+#define WLCORE_FW_LOG_END 0x2000000
+
 static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 {
        u32 addr;
-       u32 first_addr;
+       u32 offset;
+       u32 end_of_log;
        u8 *block;
+       int ret;
 
        if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
-           (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
            (wl->conf.fwlog.mem_blocks == 0))
                return;
 
@@ -820,34 +826,49 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 
        /*
         * Make sure the chip is awake and the logger isn't active.
-        * This might fail if the firmware hanged.
+        * Do not send a stop fwlog command if the fw is hanged.
         */
-       if (!wl1271_ps_elp_wakeup(wl))
+       if (wl1271_ps_elp_wakeup(wl))
+               goto out;
+       if (!wl->watchdog_recovery)
                wl12xx_cmd_stop_fwlog(wl);
 
        /* Read the first memory block address */
-       wl12xx_fw_status(wl, wl->fw_status);
-       first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
-       if (!first_addr)
+       ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2);
+       if (ret < 0)
+               goto out;
+
+       addr = le32_to_cpu(wl->fw_status_2->log_start_addr);
+       if (!addr)
                goto out;
 
+       if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
+               offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
+               end_of_log = WLCORE_FW_LOG_END;
+       } else {
+               offset = sizeof(addr);
+               end_of_log = addr;
+       }
+
        /* Traverse the memory blocks linked list */
-       addr = first_addr;
        do {
                memset(block, 0, WL12XX_HW_BLOCK_SIZE);
-               wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
-                                  false);
+               ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
+                                        false);
+               if (ret < 0)
+                       goto out;
 
                /*
                 * Memory blocks are linked to one another. The first 4 bytes
                 * of each memory block hold the hardware address of the next
-                * one. The last memory block points to the first one.
+                * one. The last memory block points to the first one in
+                * on demand mode and is equal to 0x2000000 in continuous mode.
                 */
                addr = le32_to_cpup((__le32 *)block);
-               if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
-                                      WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
+               if (!wl12xx_copy_fwlog(wl, block + offset,
+                                      WL12XX_HW_BLOCK_SIZE - offset))
                        break;
-       } while (addr && (addr != first_addr));
+       } while (addr && (addr != end_of_log));
 
        wake_up_interruptible(&wl->fwlog_waitq);
 
@@ -855,6 +876,34 @@ out:
        kfree(block);
 }
 
+static void wlcore_print_recovery(struct wl1271 *wl)
+{
+       u32 pc = 0;
+       u32 hint_sts = 0;
+       int ret;
+
+       wl1271_info("Hardware recovery in progress. FW ver: %s",
+                   wl->chip.fw_ver_str);
+
+       /* change partitions momentarily so we can read the FW pc */
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       if (ret < 0)
+               return;
+
+       ret = wlcore_read_reg(wl, REG_PC_ON_RECOVERY, &pc);
+       if (ret < 0)
+               return;
+
+       ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &hint_sts);
+       if (ret < 0)
+               return;
+
+       wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts);
+
+       wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
+}
+
+
 static void wl1271_recovery_work(struct work_struct *work)
 {
        struct wl1271 *wl =
@@ -867,14 +916,9 @@ static void wl1271_recovery_work(struct work_struct *work)
        if (wl->state != WL1271_STATE_ON || wl->plt)
                goto out_unlock;
 
-       /* Avoid a recursive recovery */
-       set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
-
        wl12xx_read_fwlog_panic(wl);
 
-       wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
-                   wl->chip.fw_ver_str,
-                   wlcore_read_reg(wl, REG_PC_ON_RECOVERY));
+       wlcore_print_recovery(wl);
 
        BUG_ON(bug_on_recovery &&
               !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags));
@@ -885,8 +929,6 @@ static void wl1271_recovery_work(struct work_struct *work)
                goto out_unlock;
        }
 
-       BUG_ON(bug_on_recovery);
-
        /*
         * Advance security sequence number to overcome potential progress
         * in the firmware during recovery. This doens't hurt if the network is
@@ -900,7 +942,7 @@ static void wl1271_recovery_work(struct work_struct *work)
        }
 
        /* Prevent spurious TX during FW restart */
-       ieee80211_stop_queues(wl->hw);
+       wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
 
        if (wl->sched_scanning) {
                ieee80211_sched_scan_stopped(wl->hw);
@@ -914,37 +956,43 @@ static void wl1271_recovery_work(struct work_struct *work)
                vif = wl12xx_wlvif_to_vif(wlvif);
                __wl1271_op_remove_interface(wl, vif, false);
        }
+        wl->watchdog_recovery = false;
        mutex_unlock(&wl->mutex);
        wl1271_op_stop(wl->hw);
 
-       clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
-
        ieee80211_restart_hw(wl->hw);
 
        /*
         * Its safe to enable TX now - the queues are stopped after a request
         * to restart the HW.
         */
-       ieee80211_wake_queues(wl->hw);
+       wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
        return;
 out_unlock:
+        wl->watchdog_recovery = false;
        mutex_unlock(&wl->mutex);
 }
 
-static void wl1271_fw_wakeup(struct wl1271 *wl)
+static int wlcore_fw_wakeup(struct wl1271 *wl)
 {
-       wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
+       return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
 }
 
 static int wl1271_setup(struct wl1271 *wl)
 {
-       wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
-       if (!wl->fw_status)
+       wl->fw_status_1 = kmalloc(WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) +
+                                 sizeof(*wl->fw_status_2) +
+                                 wl->fw_status_priv_len, GFP_KERNEL);
+       if (!wl->fw_status_1)
                return -ENOMEM;
 
+       wl->fw_status_2 = (struct wl_fw_status_2 *)
+                               (((u8 *) wl->fw_status_1) +
+                               WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc));
+
        wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
        if (!wl->tx_res_if) {
-               kfree(wl->fw_status);
+               kfree(wl->fw_status_1);
                return -ENOMEM;
        }
 
@@ -963,13 +1011,21 @@ static int wl12xx_set_power_on(struct wl1271 *wl)
        wl1271_io_reset(wl);
        wl1271_io_init(wl);
 
-       wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
+       if (ret < 0)
+               goto fail;
 
        /* ELP module wake up */
-       wl1271_fw_wakeup(wl);
+       ret = wlcore_fw_wakeup(wl);
+       if (ret < 0)
+               goto fail;
 
 out:
        return ret;
+
+fail:
+       wl1271_power_off(wl);
+       return ret;
 }
 
 static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
@@ -987,13 +1043,12 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
         * simplify the code and since the performance impact is
         * negligible, we use the same block size for all different
         * chip types.
+        *
+        * Check if the bus supports blocksize alignment and, if it
+        * doesn't, make sure we don't have the quirk.
         */
-       if (wl1271_set_block_size(wl))
-               wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
-
-       ret = wl->ops->identify_chip(wl);
-       if (ret < 0)
-               goto out;
+       if (!wl1271_set_block_size(wl))
+               wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN;
 
        /* TODO: make sure the lower driver has set things up correctly */
 
@@ -1005,13 +1060,6 @@ static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
        if (ret < 0)
                goto out;
 
-       /* 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;
-       }
-
 out:
        return ret;
 }
@@ -1039,14 +1087,10 @@ int wl1271_plt_start(struct wl1271 *wl)
                if (ret < 0)
                        goto power_off;
 
-               ret = wl->ops->boot(wl);
+               ret = wl->ops->plt_init(wl);
                if (ret < 0)
                        goto power_off;
 
-               ret = wl1271_plt_init(wl);
-               if (ret < 0)
-                       goto irq_disable;
-
                wl->plt = true;
                wl->state = WL1271_STATE_ON;
                wl1271_notice("firmware booted in PLT mode (%s)",
@@ -1059,19 +1103,6 @@ int wl1271_plt_start(struct wl1271 *wl)
 
                goto out;
 
-irq_disable:
-               mutex_unlock(&wl->mutex);
-               /* Unlocking the mutex in the middle of handling is
-                  inherently unsafe. In this case we deem it safe to do,
-                  because we need to let any possibly pending IRQ out of
-                  the system (and while we are WL1271_STATE_OFF the IRQ
-                  work function will not do anything.) Also, any other
-                  possible concurrent operations will fail due to the
-                  current state, hence the wl1271 struct should be safe. */
-               wlcore_disable_interrupts(wl);
-               wl1271_flush_deferred_work(wl);
-               cancel_work_sync(&wl->netstack_work);
-               mutex_lock(&wl->mutex);
 power_off:
                wl1271_power_off(wl);
        }
@@ -1125,6 +1156,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
        mutex_lock(&wl->mutex);
        wl1271_power_off(wl);
        wl->flags = 0;
+       wl->sleep_auth = WL1271_PSM_ILLEGAL;
        wl->state = WL1271_STATE_OFF;
        wl->plt = false;
        wl->rx_counter = 0;
@@ -1154,9 +1186,16 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        spin_lock_irqsave(&wl->wl_lock, flags);
 
-       /* queue the packet */
+       /*
+        * drop the packet if the link is invalid or the queue is stopped
+        * for any reason but watermark. Watermark is a "soft"-stop so we
+        * allow these packets through.
+        */
        if (hlid == WL12XX_INVALID_LINK_ID ||
-           (wlvif && !test_bit(hlid, wlvif->links_map))) {
+           (wlvif && !test_bit(hlid, wlvif->links_map)) ||
+            (wlcore_is_queue_stopped(wl, q) &&
+             !wlcore_is_queue_stopped_by_reason(wl, q,
+                       WLCORE_QUEUE_STOP_REASON_WATERMARK))) {
                wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
                ieee80211_free_txskb(hw, skb);
                goto out;
@@ -1174,8 +1213,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         */
        if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
                wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
-               ieee80211_stop_queue(wl->hw, mapping);
-               set_bit(q, &wl->stopped_queues_map);
+               wlcore_stop_queue_locked(wl, q,
+                                        WLCORE_QUEUE_STOP_REASON_WATERMARK);
        }
 
        /*
@@ -1209,7 +1248,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl)
 
        /* The FW is low on RX memory blocks, so send the dummy packet asap */
        if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
-               wl1271_tx_work_locked(wl);
+               return wlcore_tx_work_locked(wl);
 
        /*
         * If the FW TX is busy, TX work will be scheduled by the threaded
@@ -1476,8 +1515,15 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
        int i, ret;
 
        if (!wow || wow->any || !wow->n_patterns) {
-               wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
-               wl1271_rx_filter_clear_all(wl);
+               ret = wl1271_acx_default_rx_filter_enable(wl, 0,
+                                                         FILTER_SIGNAL);
+               if (ret)
+                       goto out;
+
+               ret = wl1271_rx_filter_clear_all(wl);
+               if (ret)
+                       goto out;
+
                return 0;
        }
 
@@ -1493,8 +1539,13 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
                }
        }
 
-       wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
-       wl1271_rx_filter_clear_all(wl);
+       ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
+       if (ret)
+               goto out;
+
+       ret = wl1271_rx_filter_clear_all(wl);
+       if (ret)
+               goto out;
 
        /* Translate WoWLAN patterns into filters */
        for (i = 0; i < wow->n_patterns; i++) {
@@ -1536,7 +1587,10 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
        if (ret < 0)
                goto out;
 
-       wl1271_configure_wowlan(wl, wow);
+       ret = wl1271_configure_wowlan(wl, wow);
+       if (ret < 0)
+               goto out_sleep;
+
        ret = wl1271_acx_wake_up_conditions(wl, wlvif,
                                    wl->conf.conn.suspend_wake_up_event,
                                    wl->conf.conn.suspend_listen_interval);
@@ -1544,8 +1598,8 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
        if (ret < 0)
                wl1271_error("suspend: set wake up conditions failed: %d", ret);
 
+out_sleep:
        wl1271_ps_elp_sleep(wl);
-
 out:
        return ret;
 
@@ -1624,6 +1678,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
        wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
        WARN_ON(!wow);
 
+       /* we want to perform the recovery before suspending */
+       if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+               wl1271_warning("postponing suspend to perform recovery");
+               return -EBUSY;
+       }
+
        wl1271_tx_flush(wl);
 
        mutex_lock(&wl->mutex);
@@ -1664,7 +1724,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif;
        unsigned long flags;
-       bool run_irq_work = false;
+       bool run_irq_work = false, pending_recovery;
+       int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
                     wl->wow_enabled);
@@ -1680,17 +1741,37 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
                run_irq_work = true;
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
+       mutex_lock(&wl->mutex);
+
+       /* test the recovery flag before calling any SDIO functions */
+       pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
+                                   &wl->flags);
+
        if (run_irq_work) {
                wl1271_debug(DEBUG_MAC80211,
                             "run postponed irq_work directly");
-               wl1271_irq(0, wl);
+
+               /* don't talk to the HW if recovery is pending */
+               if (!pending_recovery) {
+                       ret = wlcore_irq_locked(wl);
+                       if (ret)
+                               wl12xx_queue_recovery_work(wl);
+               }
+
                wlcore_enable_interrupts(wl);
        }
 
-       mutex_lock(&wl->mutex);
+       if (pending_recovery) {
+               wl1271_warning("queuing forgotten recovery on resume");
+               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+               goto out;
+       }
+
        wl12xx_for_each_wlvif(wl, wlvif) {
                wl1271_configure_resume(wl, wlvif);
        }
+
+out:
        wl->wow_enabled = false;
        mutex_unlock(&wl->mutex);
 
@@ -1731,6 +1812,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wlcore_disable_interrupts(wl);
        mutex_lock(&wl->mutex);
        if (wl->state == WL1271_STATE_OFF) {
+               if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
+                                       &wl->flags))
+                       wlcore_enable_interrupts(wl);
+
                mutex_unlock(&wl->mutex);
 
                /*
@@ -1758,15 +1843,23 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        cancel_delayed_work_sync(&wl->connection_loss_work);
 
        /* let's notify MAC80211 about the remaining pending TX frames */
-       wl12xx_tx_reset(wl, true);
+       wl12xx_tx_reset(wl);
        mutex_lock(&wl->mutex);
 
        wl1271_power_off(wl);
+       /*
+        * In case a recovery was scheduled, interrupts were disabled to avoid
+        * an interrupt storm. Now that the power is down, it is safe to
+        * re-enable interrupts to balance the disable depth
+        */
+       if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+               wlcore_enable_interrupts(wl);
 
        wl->band = IEEE80211_BAND_2GHZ;
 
        wl->rx_counter = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+       wl->channel_type = NL80211_CHAN_NO_HT;
        wl->tx_blocks_available = 0;
        wl->tx_allocated_blocks = 0;
        wl->tx_results_count = 0;
@@ -1775,6 +1868,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->ap_fw_ps_map = 0;
        wl->ap_ps_map = 0;
        wl->sched_scanning = false;
+       wl->sleep_auth = WL1271_PSM_ILLEGAL;
        memset(wl->roles_map, 0, sizeof(wl->roles_map));
        memset(wl->links_map, 0, sizeof(wl->links_map));
        memset(wl->roc_map, 0, sizeof(wl->roc_map));
@@ -1799,8 +1893,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
        wl1271_debugfs_reset(wl);
 
-       kfree(wl->fw_status);
-       wl->fw_status = NULL;
+       kfree(wl->fw_status_1);
+       wl->fw_status_1 = NULL;
+       wl->fw_status_2 = NULL;
        kfree(wl->tx_res_if);
        wl->tx_res_if = NULL;
        kfree(wl->target_mem_map);
@@ -1894,6 +1989,9 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
                wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
                wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
                wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
+               wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+               wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
+               wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
        } else {
                /* init ap data */
                wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
@@ -1903,13 +2001,19 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
                for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
                        wl12xx_allocate_rate_policy(wl,
                                                &wlvif->ap.ucast_rate_idx[i]);
+               wlvif->basic_rate_set = CONF_TX_AP_ENABLED_RATES;
+               /*
+                * TODO: check if basic_rate shouldn't be
+                * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+                * instead (the same thing for STA above).
+               */
+               wlvif->basic_rate = CONF_TX_AP_ENABLED_RATES;
+               /* TODO: this seems to be used only for STA, check it */
+               wlvif->rate_set = CONF_TX_AP_ENABLED_RATES;
        }
 
        wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
        wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
-       wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
-       wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
-       wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
        wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
 
        /*
@@ -1919,6 +2023,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
        wlvif->band = wl->band;
        wlvif->channel = wl->channel;
        wlvif->power_level = wl->power_level;
+       wlvif->channel_type = wl->channel_type;
 
        INIT_WORK(&wlvif->rx_streaming_enable_work,
                  wl1271_rx_streaming_enable_work);
@@ -2170,6 +2275,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
 {
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int i, ret;
+       bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
 
@@ -2250,11 +2356,25 @@ deinit:
        wlvif->role_id = WL12XX_INVALID_ROLE_ID;
        wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
 
-       if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+       if (is_ap)
                wl->ap_count--;
        else
                wl->sta_count--;
 
+       /* Last AP, have more stations. Configure according to STA. */
+       if (wl->ap_count == 0 && is_ap && wl->sta_count) {
+               u8 sta_auth = wl->conf.conn.sta_sleep_auth;
+               /* Configure for power according to debugfs */
+               if (sta_auth != WL1271_PSM_ILLEGAL)
+                       wl1271_acx_sleep_auth(wl, sta_auth);
+               /* Configure for power always on */
+               else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
+                       wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+               /* Configure for ELP power saving */
+               else
+                       wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
+       }
+
        mutex_unlock(&wl->mutex);
 
        del_timer_sync(&wlvif->rx_streaming_timer);
@@ -2444,7 +2564,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        } else {
                /* The current firmware only supports sched_scan in idle */
                if (wl->sched_scanning) {
-                       wl1271_scan_sched_scan_stop(wl);
+                       wl1271_scan_sched_scan_stop(wl, wlvif);
                        ieee80211_sched_scan_stopped(wl->hw);
                }
 
@@ -2469,13 +2589,24 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        /* if the channel changes while joined, join again */
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
            ((wlvif->band != conf->channel->band) ||
-            (wlvif->channel != channel))) {
+            (wlvif->channel != channel) ||
+            (wlvif->channel_type != conf->channel_type))) {
                /* send all pending packets */
-               wl1271_tx_work_locked(wl);
+               ret = wlcore_tx_work_locked(wl);
+               if (ret < 0)
+                       return ret;
+
                wlvif->band = conf->channel->band;
                wlvif->channel = channel;
+               wlvif->channel_type = conf->channel_type;
 
-               if (!is_ap) {
+               if (is_ap) {
+                       wl1271_set_band_rate(wl, wlvif);
+                       ret = wl1271_init_ap_rates(wl, wlvif);
+                       if (ret < 0)
+                               wl1271_error("AP rate policy change failed %d",
+                                            ret);
+               } else {
                        /*
                         * FIXME: the mac80211 should really provide a fixed
                         * rate to use here. for now, just use the smallest
@@ -2583,8 +2714,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
         * frames, such as the deauth. To make sure those frames reach the air,
         * wait here until the TX queue is fully flushed.
         */
-       if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
-           (conf->flags & IEEE80211_CONF_IDLE))
+       if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
+           ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
+            (conf->flags & IEEE80211_CONF_IDLE)))
                wl1271_tx_flush(wl);
 
        mutex_lock(&wl->mutex);
@@ -2593,6 +2725,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                wl->band = conf->channel->band;
                wl->channel = channel;
+               wl->channel_type = conf->channel_type;
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER)
@@ -2825,17 +2958,6 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        int ret;
        bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
 
-       /*
-        * A role set to GEM cipher requires different Tx settings (namely
-        * spare blocks). Note when we are in this mode so the HW can adjust.
-        */
-       if (key_type == KEY_GEM) {
-               if (action == KEY_ADD_OR_REPLACE)
-                       wlvif->is_gem = true;
-               else if (action == KEY_REMOVE)
-                       wlvif->is_gem = false;
-       }
-
        if (is_ap) {
                struct wl1271_station *wl_sta;
                u8 hlid;
@@ -2913,12 +3035,21 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        return 0;
 }
 
-static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                             struct ieee80211_vif *vif,
                             struct ieee80211_sta *sta,
                             struct ieee80211_key_conf *key_conf)
 {
        struct wl1271 *wl = hw->priv;
+
+       return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
+}
+
+int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+                  struct ieee80211_vif *vif,
+                  struct ieee80211_sta *sta,
+                  struct ieee80211_key_conf *key_conf)
+{
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
        u32 tx_seq_32 = 0;
@@ -3029,6 +3160,7 @@ out_unlock:
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(wlcore_set_key);
 
 static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
@@ -3167,6 +3299,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
@@ -3180,7 +3313,7 @@ static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       wl1271_scan_sched_scan_stop(wl);
+       wl1271_scan_sched_scan_stop(wl, wlvif);
 
        wl1271_ps_elp_sleep(wl);
 out:
@@ -3316,8 +3449,15 @@ static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
                                      skb->data,
                                      skb->len, 0,
                                      rates);
-
        dev_kfree_skb(skb);
+
+       if (ret < 0)
+               goto out;
+
+       wl1271_debug(DEBUG_AP, "probe response updated");
+       set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
+
+out:
        return ret;
 }
 
@@ -3422,6 +3562,87 @@ out:
        return ret;
 }
 
+static int wlcore_set_beacon_template(struct wl1271 *wl,
+                                     struct ieee80211_vif *vif,
+                                     bool is_ap)
+{
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct ieee80211_hdr *hdr;
+       u32 min_rate;
+       int ret;
+       int ieoffset = offsetof(struct ieee80211_mgmt,
+                               u.beacon.variable);
+       struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
+       u16 tmpl_id;
+
+       if (!beacon) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       wl1271_debug(DEBUG_MASTER, "beacon updated");
+
+       ret = wl1271_ssid_set(vif, beacon, ieoffset);
+       if (ret < 0) {
+               dev_kfree_skb(beacon);
+               goto out;
+       }
+       min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+       tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
+               CMD_TEMPL_BEACON;
+       ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
+                                     beacon->data,
+                                     beacon->len, 0,
+                                     min_rate);
+       if (ret < 0) {
+               dev_kfree_skb(beacon);
+               goto out;
+       }
+
+       /*
+        * In case we already have a probe-resp beacon set explicitly
+        * by usermode, don't use the beacon data.
+        */
+       if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
+               goto end_bcn;
+
+       /* remove TIM ie from probe response */
+       wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
+
+       /*
+        * remove p2p ie from probe response.
+        * the fw reponds to probe requests that don't include
+        * the p2p ie. probe requests with p2p ie will be passed,
+        * and will be responded by the supplicant (the spec
+        * forbids including the p2p ie when responding to probe
+        * requests that didn't include it).
+        */
+       wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
+                               WLAN_OUI_TYPE_WFA_P2P, ieoffset);
+
+       hdr = (struct ieee80211_hdr *) beacon->data;
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                        IEEE80211_STYPE_PROBE_RESP);
+       if (is_ap)
+               ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
+                                                          beacon->data,
+                                                          beacon->len,
+                                                          min_rate);
+       else
+               ret = wl1271_cmd_template_set(wl, wlvif->role_id,
+                                             CMD_TEMPL_PROBE_RESPONSE,
+                                             beacon->data,
+                                             beacon->len, 0,
+                                             min_rate);
+end_bcn:
+       dev_kfree_skb(beacon);
+       if (ret < 0)
+               goto out;
+
+out:
+       return ret;
+}
+
 static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                                          struct ieee80211_vif *vif,
                                          struct ieee80211_bss_conf *bss_conf,
@@ -3440,81 +3661,12 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
 
        if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
                u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-               if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
-                       wl1271_debug(DEBUG_AP, "probe response updated");
-                       set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
-               }
+
+               wl1271_ap_set_probe_resp_tmpl(wl, rate, vif);
        }
 
        if ((changed & BSS_CHANGED_BEACON)) {
-               struct ieee80211_hdr *hdr;
-               u32 min_rate;
-               int ieoffset = offsetof(struct ieee80211_mgmt,
-                                       u.beacon.variable);
-               struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
-               u16 tmpl_id;
-
-               if (!beacon) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               wl1271_debug(DEBUG_MASTER, "beacon updated");
-
-               ret = wl1271_ssid_set(vif, beacon, ieoffset);
-               if (ret < 0) {
-                       dev_kfree_skb(beacon);
-                       goto out;
-               }
-               min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
-               tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
-                                 CMD_TEMPL_BEACON;
-               ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
-                                             beacon->data,
-                                             beacon->len, 0,
-                                             min_rate);
-               if (ret < 0) {
-                       dev_kfree_skb(beacon);
-                       goto out;
-               }
-
-               /*
-                * In case we already have a probe-resp beacon set explicitly
-                * by usermode, don't use the beacon data.
-                */
-               if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
-                       goto end_bcn;
-
-               /* remove TIM ie from probe response */
-               wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
-
-               /*
-                * remove p2p ie from probe response.
-                * the fw reponds to probe requests that don't include
-                * the p2p ie. probe requests with p2p ie will be passed,
-                * and will be responded by the supplicant (the spec
-                * forbids including the p2p ie when responding to probe
-                * requests that didn't include it).
-                */
-               wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
-                                       WLAN_OUI_TYPE_WFA_P2P, ieoffset);
-
-               hdr = (struct ieee80211_hdr *) beacon->data;
-               hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                IEEE80211_STYPE_PROBE_RESP);
-               if (is_ap)
-                       ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
-                                               beacon->data,
-                                               beacon->len,
-                                               min_rate);
-               else
-                       ret = wl1271_cmd_template_set(wl, wlvif->role_id,
-                                               CMD_TEMPL_PROBE_RESPONSE,
-                                               beacon->data,
-                                               beacon->len, 0,
-                                               min_rate);
-end_bcn:
-               dev_kfree_skb(beacon);
+               ret = wlcore_set_beacon_template(wl, vif, is_ap);
                if (ret < 0)
                        goto out;
        }
@@ -3551,6 +3703,14 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
                ret = wl1271_ap_init_templates(wl, vif);
                if (ret < 0)
                        goto out;
+
+               ret = wl1271_ap_set_probe_resp_tmpl(wl, wlvif->basic_rate, vif);
+               if (ret < 0)
+                       goto out;
+
+               ret = wlcore_set_beacon_template(wl, vif, true);
+               if (ret < 0)
+                       goto out;
        }
 
        ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
@@ -3691,7 +3851,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
                if (sta->ht_cap.ht_supported)
                        sta_rate_set |=
-                           (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
+                         (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET) |
+                         (sta->ht_cap.mcs.rx_mask[1] << HW_MIMO_RATES_OFFSET);
                sta_ht_cap = sta->ht_cap;
                sta_exists = true;
 
@@ -3704,13 +3865,11 @@ sta_not_found:
                        u32 rates;
                        int ieoffset;
                        wlvif->aid = bss_conf->aid;
+                       wlvif->channel_type = bss_conf->channel_type;
                        wlvif->beacon_int = bss_conf->beacon_int;
                        do_join = true;
                        set_assoc = true;
 
-                       /* Cancel connection_loss_work */
-                       cancel_delayed_work_sync(&wl->connection_loss_work);
-
                        /*
                         * use basic rates from AP, and determine lowest rate
                         * to use with control frames.
@@ -3960,6 +4119,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
                     (int)changed);
 
+       /*
+        * make sure to cancel pending disconnections if our association
+        * state changed
+        */
+       if (!is_ap && (changed & BSS_CHANGED_ASSOC))
+               cancel_delayed_work_sync(&wl->connection_loss_work);
+
+       if (is_ap && (changed & BSS_CHANGED_BEACON_ENABLED) &&
+           !bss_conf->enable_beacon)
+               wl1271_tx_flush(wl);
+
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -4068,16 +4238,13 @@ out:
 static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
                                struct survey_info *survey)
 {
-       struct wl1271 *wl = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
 
        if (idx != 0)
                return -ENOENT;
 
        survey->channel = conf->channel;
-       survey->filled = SURVEY_INFO_NOISE_DBM;
-       survey->noise = wl->noise;
-
+       survey->filled = 0;
        return 0;
 }
 
@@ -4343,9 +4510,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
 
        case IEEE80211_AMPDU_RX_STOP:
                if (!(*ba_bitmap & BIT(tid))) {
-                       ret = -EINVAL;
-                       wl1271_error("no active RX BA session on tid: %d",
+                       /*
+                        * this happens on reconfig - so only output a debug
+                        * message for now, and don't fail the function.
+                        */
+                       wl1271_debug(DEBUG_MAC80211,
+                                    "no active RX BA session on tid: %d",
                                     tid);
+                       ret = 0;
                        break;
                }
 
@@ -4636,7 +4808,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .prepare_multicast = wl1271_op_prepare_multicast,
        .configure_filter = wl1271_op_configure_filter,
        .tx = wl1271_op_tx,
-       .set_key = wl1271_op_set_key,
+       .set_key = wlcore_op_set_key,
        .hw_scan = wl1271_op_hw_scan,
        .cancel_hw_scan = wl1271_op_cancel_hw_scan,
        .sched_scan_start = wl1271_op_sched_scan_start,
@@ -4882,18 +5054,22 @@ static int wl12xx_get_hw_info(struct wl1271 *wl)
        if (ret < 0)
                goto out;
 
-       wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B);
+       ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id);
+       if (ret < 0)
+               goto out;
 
        wl->fuse_oui_addr = 0;
        wl->fuse_nic_addr = 0;
 
-       wl->hw_pg_ver = wl->ops->get_pg_ver(wl);
+       ret = wl->ops->get_pg_ver(wl, &wl->hw_pg_ver);
+       if (ret < 0)
+               goto out;
 
        if (wl->ops->get_mac)
-               wl->ops->get_mac(wl);
+               ret = wl->ops->get_mac(wl);
 
-       wl1271_power_off(wl);
 out:
+       wl1271_power_off(wl);
        return ret;
 }
 
@@ -4905,14 +5081,8 @@ static int wl1271_register_hw(struct wl1271 *wl)
        if (wl->mac80211_registered)
                return 0;
 
-       ret = wl12xx_get_hw_info(wl);
-       if (ret < 0) {
-               wl1271_error("couldn't get hw info");
-               goto out;
-       }
-
-       ret = wl1271_fetch_nvs(wl);
-       if (ret == 0) {
+       wl1271_fetch_nvs(wl);
+       if (wl->nvs != NULL) {
                /* NOTE: The wl->nvs->nvs element must be first, in
                 * order to simplify the casting, we assume it is at
                 * the beginning of the wl->nvs structure.
@@ -4960,6 +5130,29 @@ static void wl1271_unregister_hw(struct wl1271 *wl)
 
 }
 
+static const struct ieee80211_iface_limit wlcore_iface_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP) |
+                        BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+wlcore_iface_combinations[] = {
+       {
+         .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = wlcore_iface_limits,
+         .n_limits = ARRAY_SIZE(wlcore_iface_limits),
+       },
+};
+
 static int wl1271_init_ieee80211(struct wl1271 *wl)
 {
        static const u32 cipher_suites[] = {
@@ -4970,9 +5163,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                WL1271_CIPHER_SUITE_GEM,
        };
 
-       /* The tx descriptor buffer and the TKIP space. */
-       wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
-               sizeof(struct wl1271_tx_hw_descr);
+       /* The tx descriptor buffer */
+       wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr);
+
+       if (wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE)
+               wl->hw->extra_tx_headroom += WL1271_EXTRA_SPACE_TKIP;
 
        /* unit us */
        /* FIXME: find a proper value */
@@ -5025,12 +5220,14 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
         */
        memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
               sizeof(wl1271_band_2ghz));
-       memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap,
-              sizeof(wl->ht_cap));
+       memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap,
+              &wl->ht_cap[IEEE80211_BAND_2GHZ],
+              sizeof(*wl->ht_cap));
        memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
               sizeof(wl1271_band_5ghz));
-       memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap,
-              sizeof(wl->ht_cap));
+       memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap,
+              &wl->ht_cap[IEEE80211_BAND_5GHZ],
+              sizeof(*wl->ht_cap));
 
        wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
                &wl->bands[IEEE80211_BAND_2GHZ];
@@ -5049,6 +5246,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
+       /* allowed interface combinations */
+       wl->hw->wiphy->iface_combinations = wlcore_iface_combinations;
+       wl->hw->wiphy->n_iface_combinations =
+               ARRAY_SIZE(wlcore_iface_combinations);
+
        SET_IEEE80211_DEV(wl->hw, wl->dev);
 
        wl->hw->sta_data_size = sizeof(struct wl1271_station);
@@ -5117,8 +5319,10 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
        wl->rx_counter = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->band = IEEE80211_BAND_2GHZ;
+       wl->channel_type = NL80211_CHAN_NO_HT;
        wl->flags = 0;
        wl->sg_enabled = true;
+       wl->sleep_auth = WL1271_PSM_ILLEGAL;
        wl->hw_pg_ver = -1;
        wl->ap_ps_map = 0;
        wl->ap_fw_ps_map = 0;
@@ -5142,6 +5346,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
        wl->state = WL1271_STATE_OFF;
        wl->fw_type = WL12XX_FW_TYPE_NONE;
        mutex_init(&wl->mutex);
+       mutex_init(&wl->flush_mutex);
 
        order = get_order(WL1271_AGGR_BUFFER_SIZE);
        wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
@@ -5222,7 +5427,7 @@ int wlcore_free_hw(struct wl1271 *wl)
        kfree(wl->nvs);
        wl->nvs = NULL;
 
-       kfree(wl->fw_status);
+       kfree(wl->fw_status_1);
        kfree(wl->tx_res_if);
        destroy_workqueue(wl->freezable_wq);
 
@@ -5279,8 +5484,6 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
        wlcore_adjust_conf(wl);
 
        wl->irq = platform_get_irq(pdev, 0);
-       wl->ref_clock = pdata->board_ref_clock;
-       wl->tcxo_clock = pdata->board_tcxo_clock;
        wl->platform_quirks = pdata->platform_quirks;
        wl->set_power = pdata->set_power;
        wl->dev = &pdev->dev;
@@ -5293,7 +5496,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
        else
                irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
 
-       ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
+       ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq,
                                   irqflags,
                                   pdev->name, wl);
        if (ret < 0) {
@@ -5316,6 +5519,16 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
        }
        disable_irq(wl->irq);
 
+       ret = wl12xx_get_hw_info(wl);
+       if (ret < 0) {
+               wl1271_error("couldn't get hw info");
+               goto out_irq;
+       }
+
+       ret = wl->ops->identify_chip(wl);
+       if (ret < 0)
+               goto out_irq;
+
        ret = wl1271_init_ieee80211(wl);
        if (ret)
                goto out_irq;
@@ -5328,7 +5541,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
        ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
        if (ret < 0) {
                wl1271_error("failed to create sysfs file bt_coex_state");
-               goto out_irq;
+               goto out_unreg;
        }
 
        /* Create sysfs file to get HW PG version */
@@ -5353,6 +5566,9 @@ out_hw_pg_ver:
 out_bt_coex_state:
        device_remove_file(wl->dev, &dev_attr_bt_coex_state);
 
+out_unreg:
+       wl1271_unregister_hw(wl);
+
 out_irq:
        free_irq(wl->irq, wl);
 
index 756eee2257b4bc51d857f3068c46b06cc5844907..46d36fd30eba54e306cbf4cdeade28b61e337ea7 100644 (file)
 
 #define WL1271_WAKEUP_TIMEOUT 500
 
+#define ELP_ENTRY_DELAY  5
+
 void wl1271_elp_work(struct work_struct *work)
 {
        struct delayed_work *dwork;
        struct wl1271 *wl;
        struct wl12xx_vif *wlvif;
+       int ret;
 
        dwork = container_of(work, struct delayed_work, work);
        wl = container_of(dwork, struct wl1271, elp_work);
@@ -61,7 +64,12 @@ void wl1271_elp_work(struct work_struct *work)
        }
 
        wl1271_debug(DEBUG_PSM, "chip to elp");
-       wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
+       ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP);
+       if (ret < 0) {
+               wl12xx_queue_recovery_work(wl);
+               goto out;
+       }
+
        set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
 
 out:
@@ -72,8 +80,9 @@ out:
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
        struct wl12xx_vif *wlvif;
+       u32 timeout;
 
-       if (wl->quirks & WLCORE_QUIRK_NO_ELP)
+       if (wl->sleep_auth != WL1271_PSM_ELP)
                return;
 
        /* we shouldn't get consecutive sleep requests */
@@ -89,8 +98,13 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
                        return;
        }
 
+       if (wl->conf.conn.forced_ps)
+               timeout = ELP_ENTRY_DELAY;
+       else
+               timeout = wl->conf.conn.dynamic_ps_timeout;
+
        ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
-               msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
+                                    msecs_to_jiffies(timeout));
 }
 
 int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -127,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
                wl->elp_compl = &compl;
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
-       wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
+       ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP);
+       if (ret < 0) {
+               wl12xx_queue_recovery_work(wl);
+               goto err;
+       }
 
        if (!pending) {
                ret = wait_for_completion_timeout(
@@ -185,8 +203,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
                set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
 
-               /* enable beacon early termination. Not relevant for 5GHz */
-               if (wlvif->band == IEEE80211_BAND_2GHZ) {
+               /*
+                * enable beacon early termination.
+                * Not relevant for 5GHz and for high rates.
+                */
+               if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
+                   (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
                        ret = wl1271_acx_bet_enable(wl, wlvif, true);
                        if (ret < 0)
                                return ret;
@@ -196,7 +218,8 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                wl1271_debug(DEBUG_PSM, "leaving psm");
 
                /* disable beacon early termination */
-               if (wlvif->band == IEEE80211_BAND_2GHZ) {
+               if ((wlvif->band == IEEE80211_BAND_2GHZ) &&
+                   (wlvif->basic_rate < CONF_HW_BIT_RATE_9MBPS)) {
                        ret = wl1271_acx_bet_enable(wl, wlvif, false);
                        if (ret < 0)
                                return ret;
index d6a3c6b07827738bbc3e0f3ea0ea977e1a6e9dad..f55e2f9e7ac56c4212c01cdf0e96b32cf3a7e465 100644 (file)
@@ -127,7 +127,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
        }
 
        if (rx_align == WLCORE_RX_BUF_UNALIGNED)
-               reserved = NET_IP_ALIGN;
+               reserved = RX_BUF_ALIGN;
 
        /* the data read starts with the descriptor */
        desc = (struct wl1271_rx_descriptor *) data;
@@ -175,7 +175,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
         */
        memcpy(buf, data + sizeof(*desc), pkt_data_len);
        if (rx_align == WLCORE_RX_BUF_PADDED)
-               skb_pull(skb, NET_IP_ALIGN);
+               skb_pull(skb, RX_BUF_ALIGN);
 
        *hlid = desc->hlid;
 
@@ -186,6 +186,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
                is_data = 1;
 
        wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
+       wlcore_hw_set_rx_csum(wl, desc, skb);
 
        seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
        wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
@@ -199,17 +200,18 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
        return is_data;
 }
 
-void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
+int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status)
 {
        unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
        u32 buf_size;
-       u32 fw_rx_counter  = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
-       u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
+       u32 fw_rx_counter = status->fw_rx_counter % wl->num_rx_desc;
+       u32 drv_rx_counter = wl->rx_counter % wl->num_rx_desc;
        u32 rx_counter;
        u32 pkt_len, align_pkt_len;
        u32 pkt_offset, des;
        u8 hlid;
        enum wl_rx_buf_align rx_align;
+       int ret = 0;
 
        while (drv_rx_counter != fw_rx_counter) {
                buf_size = 0;
@@ -223,7 +225,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
                                break;
                        buf_size += align_pkt_len;
                        rx_counter++;
-                       rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+                       rx_counter %= wl->num_rx_desc;
                }
 
                if (buf_size == 0) {
@@ -233,9 +235,14 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
 
                /* Read all available packets at once */
                des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
-               wlcore_hw_prepare_read(wl, des, buf_size);
-               wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
-                                buf_size, true);
+               ret = wlcore_hw_prepare_read(wl, des, buf_size);
+               if (ret < 0)
+                       goto out;
+
+               ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
+                                      buf_size, true);
+               if (ret < 0)
+                       goto out;
 
                /* Split data into separate packets */
                pkt_offset = 0;
@@ -263,7 +270,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
 
                        wl->rx_counter++;
                        drv_rx_counter++;
-                       drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
+                       drv_rx_counter %= wl->num_rx_desc;
                        pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
                }
        }
@@ -272,11 +279,17 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
         * Write the driver's packet counter to the FW. This is only required
         * for older hardware revisions
         */
-       if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
-               wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
-                              wl->rx_counter);
+       if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
+               ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
+                                    wl->rx_counter);
+               if (ret < 0)
+                       goto out;
+       }
 
        wl12xx_rearm_rx_streaming(wl, active_hlids);
+
+out:
+       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -305,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl,
        return 0;
 }
 
-void wl1271_rx_filter_clear_all(struct wl1271 *wl)
+int wl1271_rx_filter_clear_all(struct wl1271 *wl)
 {
-       int i;
+       int i, ret = 0;
 
        for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
                if (!wl->rx_filter_enabled[i])
                        continue;
-               wl1271_rx_filter_enable(wl, i, 0, NULL);
+               ret = wl1271_rx_filter_enable(wl, i, 0, NULL);
+               if (ret)
+                       goto out;
        }
+
+out:
+       return ret;
 }
 #endif /* CONFIG_PM */
index e9a162a864ca14f4a1897a6f1e4269c2ad6619d9..71eba18999152f6462600f703ca345a91f37e56d 100644 (file)
@@ -38,8 +38,6 @@
 #define RX_DESC_PACKETID_SHIFT 11
 #define RX_MAX_PACKET_ID 3
 
-#define NUM_RX_PKT_DESC_MOD_MASK   7
-
 #define RX_DESC_VALID_FCS         0x0001
 #define RX_DESC_MATCH_RXADDR1     0x0002
 #define RX_DESC_MCAST             0x0004
 /* If set, the start of IP payload is not 4 bytes aligned */
 #define RX_BUF_UNALIGNED_PAYLOAD     BIT(20)
 
+/* If set, the buffer was padded by the FW to be 4 bytes aligned */
+#define RX_BUF_PADDED_PAYLOAD        BIT(30)
+
+/*
+ * Account for the padding inserted by the FW in case of RX_ALIGNMENT
+ * or for fixing alignment in case the packet wasn't aligned.
+ */
+#define RX_BUF_ALIGN                 2
+
 /* Describes the alignment state of a Rx buffer */
 enum wl_rx_buf_align {
        WLCORE_RX_BUF_ALIGNED,
@@ -136,11 +143,11 @@ struct wl1271_rx_descriptor {
        u8  reserved;
 } __packed;
 
-void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
+int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
 int wl1271_rx_filter_enable(struct wl1271 *wl,
                            int index, bool enable,
                            struct wl12xx_rx_filter *filter);
-void wl1271_rx_filter_clear_all(struct wl1271 *wl);
+int wl1271_rx_filter_clear_all(struct wl1271 *wl);
 
 #endif
index ade21a011c458dcee0e67fccd8c54756f3e30332..d9daed53ceb72c7d6712fdfdf6cc5b732963ae1e 100644 (file)
@@ -411,7 +411,8 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                                    struct cfg80211_sched_scan_request *req,
                                    struct conn_scan_ch_params *channels,
                                    u32 band, bool radar, bool passive,
-                                   int start, int max_channels)
+                                   int start, int max_channels,
+                                   u8 *n_pactive_ch)
 {
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
        int i, j;
@@ -479,6 +480,23 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                        channels[j].tx_power_att = req->channels[i]->max_power;
                        channels[j].channel = req->channels[i]->hw_value;
 
+                       if ((band == IEEE80211_BAND_2GHZ) &&
+                           (channels[j].channel >= 12) &&
+                           (channels[j].channel <= 14) &&
+                           (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+                           !force_passive) {
+                               /* pactive channels treated as DFS */
+                               channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
+
+                               /*
+                                * n_pactive_ch is counted down from the end of
+                                * the passive channel list
+                                */
+                               (*n_pactive_ch)++;
+                               wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d",
+                                            *n_pactive_ch);
+                       }
+
                        j++;
                }
        }
@@ -491,38 +509,47 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                                struct cfg80211_sched_scan_request *req,
                                struct wl1271_cmd_sched_scan_config *cfg)
 {
+       u8 n_pactive_ch = 0;
+
        cfg->passive[0] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
                                                    IEEE80211_BAND_2GHZ,
                                                    false, true, 0,
-                                                   MAX_CHANNELS_2GHZ);
+                                                   MAX_CHANNELS_2GHZ,
+                                                   &n_pactive_ch);
        cfg->active[0] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2,
                                                    IEEE80211_BAND_2GHZ,
                                                    false, false,
                                                    cfg->passive[0],
-                                                   MAX_CHANNELS_2GHZ);
+                                                   MAX_CHANNELS_2GHZ,
+                                                   &n_pactive_ch);
        cfg->passive[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
                                                    IEEE80211_BAND_5GHZ,
                                                    false, true, 0,
-                                                   MAX_CHANNELS_5GHZ);
+                                                   MAX_CHANNELS_5GHZ,
+                                                   &n_pactive_ch);
        cfg->dfs =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
                                                    IEEE80211_BAND_5GHZ,
                                                    true, true,
                                                    cfg->passive[1],
-                                                   MAX_CHANNELS_5GHZ);
+                                                   MAX_CHANNELS_5GHZ,
+                                                   &n_pactive_ch);
        cfg->active[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5,
                                                    IEEE80211_BAND_5GHZ,
                                                    false, false,
                                                    cfg->passive[1] + cfg->dfs,
-                                                   MAX_CHANNELS_5GHZ);
+                                                   MAX_CHANNELS_5GHZ,
+                                                   &n_pactive_ch);
        /* 802.11j channels are not supported yet */
        cfg->passive[2] = 0;
        cfg->active[2] = 0;
 
+       cfg->n_pactive_ch = n_pactive_ch;
+
        wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
                     cfg->active[0], cfg->passive[0]);
        wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
@@ -537,6 +564,7 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 /* Returns the scan type to be used or a negative value on error */
 static int
 wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
+                                struct wl12xx_vif *wlvif,
                                 struct cfg80211_sched_scan_request *req)
 {
        struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
@@ -565,6 +593,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                goto out;
        }
 
+       cmd->role_id = wlvif->dev_role_id;
        if (!n_match_ssids) {
                /* No filter, with ssids */
                type = SCAN_SSID_FILTER_DISABLED;
@@ -603,7 +632,9 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                                        continue;
 
                                for (j = 0; j < cmd->n_ssids; j++)
-                                       if (!memcmp(req->ssids[i].ssid,
+                                       if ((req->ssids[i].ssid_len ==
+                                            req->ssids[j].ssid_len) &&
+                                           !memcmp(req->ssids[i].ssid,
                                                   cmd->ssids[j].ssid,
                                                   req->ssids[i].ssid_len)) {
                                                cmd->ssids[j].type =
@@ -652,6 +683,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        if (!cfg)
                return -ENOMEM;
 
+       cfg->role_id = wlvif->dev_role_id;
        cfg->rssi_threshold = c->rssi_threshold;
        cfg->snr_threshold  = c->snr_threshold;
        cfg->n_probe_reqs = c->num_probe_reqs;
@@ -669,7 +701,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                cfg->intervals[i] = cpu_to_le32(req->interval);
 
        cfg->ssid_len = 0;
-       ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
+       ret = wl12xx_scan_sched_scan_ssid_list(wl, wlvif, req);
        if (ret < 0)
                goto out;
 
@@ -741,6 +773,7 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        if (!start)
                return -ENOMEM;
 
+       start->role_id = wlvif->dev_role_id;
        start->tag = WL1271_SCAN_DEFAULT_TAG;
 
        ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
@@ -762,7 +795,7 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl)
        ieee80211_sched_scan_results(wl->hw);
 }
 
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif)
 {
        struct wl1271_cmd_sched_scan_stop *stop;
        int ret = 0;
@@ -776,6 +809,7 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
                return;
        }
 
+       stop->role_id = wlvif->dev_role_id;
        stop->tag = WL1271_SCAN_DEFAULT_TAG;
 
        ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
index 81ee36ac20785f23d364e2a3b3ef45674ba537f8..29f3c8d6b0468265dc55528a493eee7de9a8625b 100644 (file)
@@ -40,7 +40,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                                     struct cfg80211_sched_scan_request *req,
                                     struct ieee80211_sched_scan_ies *ies);
 int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl,  struct wl12xx_vif *wlvif);
 void wl1271_scan_sched_scan_results(struct wl1271 *wl);
 
 #define WL1271_SCAN_MAX_CHANNELS       24
@@ -142,7 +142,8 @@ enum {
        SCAN_BSS_TYPE_ANY,
 };
 
-#define SCAN_CHANNEL_FLAGS_DFS         BIT(0)
+#define SCAN_CHANNEL_FLAGS_DFS         BIT(0) /* channel is passive until an
+                                                 activity is detected on it */
 #define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1)
 
 struct conn_scan_ch_params {
@@ -185,7 +186,10 @@ struct wl1271_cmd_sched_scan_config {
 
        u8 dfs;
 
-       u8 padding[3];
+       u8 n_pactive_ch; /* number of pactive (passive until fw detects energy)
+                           channels in BG band */
+       u8 role_id;
+       u8 padding[1];
 
        struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
        struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
@@ -212,21 +216,24 @@ struct wl1271_cmd_sched_scan_ssid_list {
 
        u8 n_ssids;
        struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
-       u8 padding[3];
+       u8 role_id;
+       u8 padding[2];
 } __packed;
 
 struct wl1271_cmd_sched_scan_start {
        struct wl1271_cmd_header header;
 
        u8 tag;
-       u8 padding[3];
+       u8 role_id;
+       u8 padding[2];
 } __packed;
 
 struct wl1271_cmd_sched_scan_stop {
        struct wl1271_cmd_header header;
 
        u8 tag;
-       u8 padding[3];
+       u8 role_id;
+       u8 padding[2];
 } __packed;
 
 
index 0a72347cfc4c79e3184e04607803105d202f9452..204e69fa93274bf0b6d984a2a36d7c48be82578d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/platform_device.h>
+#include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
@@ -32,6 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/wl12xx.h>
 #include <linux/pm_runtime.h>
+#include <linux/printk.h>
 
 #include "wlcore.h"
 #include "wl12xx_80211.h"
@@ -45,6 +47,8 @@
 #define SDIO_DEVICE_ID_TI_WL1271       0x4076
 #endif
 
+static bool dump = false;
+
 struct wl12xx_sdio_glue {
        struct device *dev;
        struct platform_device *core;
@@ -67,8 +71,8 @@ static void wl1271_sdio_set_block_size(struct device *child,
        sdio_release_host(func);
 }
 
-static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
-                                size_t len, bool fixed)
+static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr,
+                                            void *buf, size_t len, bool fixed)
 {
        int ret;
        struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
@@ -76,6 +80,13 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
 
        sdio_claim_host(func);
 
+       if (unlikely(dump)) {
+               printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr);
+               print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ",
+                               DUMP_PREFIX_OFFSET, 16, 1,
+                               buf, len, false);
+       }
+
        if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
                ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
                dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
@@ -92,12 +103,14 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf,
 
        sdio_release_host(func);
 
-       if (ret)
+       if (WARN_ON(ret))
                dev_err(child->parent, "sdio read failed (%d)\n", ret);
+
+       return ret;
 }
 
-static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
-                                 size_t len, bool fixed)
+static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr,
+                                             void *buf, size_t len, bool fixed)
 {
        int ret;
        struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
@@ -105,6 +118,13 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
 
        sdio_claim_host(func);
 
+       if (unlikely(dump)) {
+               printk(KERN_DEBUG "wlcore_sdio: WRITE to 0x%04x\n", addr);
+               print_hex_dump(KERN_DEBUG, "wlcore_sdio: WRITE ",
+                               DUMP_PREFIX_OFFSET, 16, 1,
+                               buf, len, false);
+       }
+
        if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
                sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
                dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
@@ -121,25 +141,30 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf,
 
        sdio_release_host(func);
 
-       if (ret)
+       if (WARN_ON(ret))
                dev_err(child->parent, "sdio write failed (%d)\n", ret);
+
+       return ret;
 }
 
 static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
 {
        int ret;
        struct sdio_func *func = dev_to_sdio_func(glue->dev);
+       struct mmc_card *card = func->card;
 
-       /* If enabled, tell runtime PM not to power off the card */
-       if (pm_runtime_enabled(&func->dev)) {
-               ret = pm_runtime_get_sync(&func->dev);
-               if (ret < 0)
-                       goto out;
-       } else {
-               /* Runtime PM is disabled: power up the card manually */
-               ret = mmc_power_restore_host(func->card->host);
-               if (ret < 0)
+       ret = pm_runtime_get_sync(&card->dev);
+       if (ret) {
+               /*
+                * Runtime PM might be temporarily disabled, or the device
+                * might have a positive reference counter. Make sure it is
+                * really powered on.
+                */
+               ret = mmc_power_restore_host(card->host);
+               if (ret < 0) {
+                       pm_runtime_put_sync(&card->dev);
                        goto out;
+               }
        }
 
        sdio_claim_host(func);
@@ -154,20 +179,21 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
 {
        int ret;
        struct sdio_func *func = dev_to_sdio_func(glue->dev);
+       struct mmc_card *card = func->card;
 
        sdio_claim_host(func);
        sdio_disable_func(func);
        sdio_release_host(func);
 
-       /* Power off the card manually, even if runtime PM is enabled. */
-       ret = mmc_power_save_host(func->card->host);
+       /* Power off the card manually in case it wasn't powered off above */
+       ret = mmc_power_save_host(card->host);
        if (ret < 0)
-               return ret;
+               goto out;
 
-       /* If enabled, let runtime PM know the card is powered off */
-       if (pm_runtime_enabled(&func->dev))
-               ret = pm_runtime_put_sync(&func->dev);
+       /* Let runtime PM know the card is powered off */
+       pm_runtime_put_sync(&card->dev);
 
+out:
        return ret;
 }
 
@@ -196,6 +222,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
        struct resource res[1];
        mmc_pm_flag_t mmcflags;
        int ret = -ENOMEM;
+       const char *chip_family;
 
        /* We are only able to handle the wlan function */
        if (func->num != 0x02)
@@ -236,7 +263,18 @@ static int __devinit wl1271_probe(struct sdio_func *func,
        /* Tell PM core that we don't need the card to be powered now */
        pm_runtime_put_noidle(&func->dev);
 
-       glue->core = platform_device_alloc("wl12xx", -1);
+       /*
+        * Due to a hardware bug, we can't differentiate wl18xx from
+        * wl12xx, because both report the same device ID.  The only
+        * way to differentiate is by checking the SDIO revision,
+        * which is 3.00 on the wl18xx chips.
+        */
+       if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00)
+               chip_family = "wl18xx";
+       else
+               chip_family = "wl12xx";
+
+       glue->core = platform_device_alloc(chip_family, -1);
        if (!glue->core) {
                dev_err(glue->dev, "can't allocate platform_device");
                ret = -ENOMEM;
@@ -367,6 +405,9 @@ static void __exit wl1271_exit(void)
 module_init(wl1271_init);
 module_exit(wl1271_exit);
 
+module_param(dump, bool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
index 553cd3cbb98c0a7f054db94383b422d9c65f5870..6420abae40ee79e8e1c1ad2da4bf8b75f336f9fd 100644 (file)
@@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child)
        return -ETIMEDOUT;
 }
 
-static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
-                               size_t len, bool fixed)
+static int __must_check wl12xx_spi_raw_read(struct device *child, int addr,
+                                           void *buf, size_t len, bool fixed)
 {
        struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
        struct wl1271 *wl = dev_get_drvdata(child);
@@ -238,7 +238,7 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
                if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
                    wl12xx_spi_read_busy(child)) {
                        memset(buf, 0, chunk_len);
-                       return;
+                       return 0;
                }
 
                spi_message_init(&m);
@@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf,
                buf += chunk_len;
                len -= chunk_len;
        }
+
+       return 0;
 }
 
-static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
-                                size_t len, bool fixed)
+static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
+                                            void *buf, size_t len, bool fixed)
 {
        struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
        struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS];
@@ -304,6 +306,8 @@ static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf,
        }
 
        spi_sync(to_spi_device(glue->dev), &m);
+
+       return 0;
 }
 
 static struct wl1271_if_operations spi_ops = {
index 0e59ea2cdd39ea59376347ec03103167f4bf7349..eeb339d61d1e8ccd92cf49e79ce37cfd2c65f466 100644 (file)
@@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
        }
 
        if (answer) {
+               /* If we got bip calibration answer print radio status */
+               struct wl1271_cmd_cal_p2g *params =
+                       (struct wl1271_cmd_cal_p2g *) buf;
+
+               s16 radio_status = (s16) le16_to_cpu(params->radio_status);
+
+               if (params->test.id == TEST_CMD_P2G_CAL &&
+                   radio_status < 0)
+                       wl1271_warning("testmode cmd: radio status=%d",
+                                       radio_status);
+               else
+                       wl1271_info("testmode cmd: radio status=%d",
+                                       radio_status);
+
                len = nla_total_size(buf_len);
                skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len);
                if (!skb) {
index 6893bc2079941e93c8d1d07e265508a30199e9ee..6a28aeecf004db4c9fb553ca33197f0951ae4cd8 100644 (file)
@@ -72,7 +72,7 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
        return id;
 }
 
-static void wl1271_free_tx_id(struct wl1271 *wl, int id)
+void wl1271_free_tx_id(struct wl1271 *wl, int id)
 {
        if (__test_and_clear_bit(id, wl->tx_frames_map)) {
                if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
@@ -82,6 +82,7 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
                wl->tx_frames_cnt--;
        }
 }
+EXPORT_SYMBOL(wl1271_free_tx_id);
 
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
                                                 struct sk_buff *skb)
@@ -127,6 +128,7 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
 {
        return wl->dummy_packet == skb;
 }
+EXPORT_SYMBOL(wl12xx_is_dummy_packet);
 
 u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                         struct sk_buff *skb)
@@ -146,10 +148,10 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                        return wl->system_hlid;
 
                hdr = (struct ieee80211_hdr *)skb->data;
-               if (ieee80211_is_mgmt(hdr->frame_control))
-                       return wlvif->ap.global_hlid;
-               else
+               if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
                        return wlvif->ap.bcast_hlid;
+               else
+                       return wlvif->ap.global_hlid;
        }
 }
 
@@ -176,37 +178,34 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
                                          unsigned int packet_length)
 {
-       if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
-               return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
-       else
+       if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) ||
+           !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN))
                return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
+       else
+               return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
 }
 EXPORT_SYMBOL(wlcore_calc_packet_alignment);
 
 static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                              struct sk_buff *skb, u32 extra, u32 buf_offset,
-                             u8 hlid)
+                             u8 hlid, bool is_gem)
 {
        struct wl1271_tx_hw_descr *desc;
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
        u32 total_blocks;
        int id, ret = -EBUSY, ac;
-       u32 spare_blocks = wl->normal_tx_spare;
-       bool is_dummy = false;
+       u32 spare_blocks;
 
        if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
                return -EAGAIN;
 
+       spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem);
+
        /* allocate free identifier for the packet */
        id = wl1271_alloc_tx_id(wl, skb);
        if (id < 0)
                return id;
 
-       if (unlikely(wl12xx_is_dummy_packet(wl, skb)))
-               is_dummy = true;
-       else if (wlvif->is_gem)
-               spare_blocks = wl->gem_tx_spare;
-
        total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
 
        if (total_blocks <= wl->tx_blocks_available) {
@@ -228,7 +227,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                wl->tx_allocated_pkts[ac]++;
 
-               if (!is_dummy && wlvif &&
+               if (!wl12xx_is_dummy_packet(wl, skb) && wlvif &&
                    wlvif->bss_type == BSS_TYPE_AP_BSS &&
                    test_bit(hlid, wlvif->ap.sta_hlid_map))
                        wl->links[hlid].allocated_pkts++;
@@ -268,6 +267,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (extra) {
                int hdrlen = ieee80211_hdrlen(frame_control);
                memmove(frame_start, hdr, hdrlen);
+               skb_set_network_header(skb, skb_network_offset(skb) + extra);
        }
 
        /* configure packet life time */
@@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (is_dummy || !wlvif)
                rate_idx = 0;
        else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
-               /* if the packets are destined for AP (have a STA entry)
-                  send them with AP rate policies, otherwise use default
-                  basic rates */
+               /*
+                * if the packets are destined for AP (have a STA entry)
+                * send them with AP rate policies (EAPOLs are an exception),
+                * otherwise use default basic rates
+                */
                if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
                        rate_idx = wlvif->sta.p2p_rate_idx;
+               else if (skb->protocol == cpu_to_be16(ETH_P_PAE))
+                       rate_idx = wlvif->sta.basic_rate_idx;
                else if (control->control.sta)
                        rate_idx = wlvif->sta.ap_rate_idx;
                else
@@ -330,9 +334,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
            ieee80211_has_protected(frame_control))
                tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
 
-       desc->reserved = 0;
        desc->tx_attr = cpu_to_le16(tx_attr);
 
+       wlcore_hw_set_tx_desc_csum(wl, desc, skb);
        wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
 }
 
@@ -346,16 +350,20 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        u32 total_len;
        u8 hlid;
        bool is_dummy;
+       bool is_gem = false;
 
-       if (!skb)
+       if (!skb) {
+               wl1271_error("discarding null skb");
                return -EINVAL;
+       }
 
        info = IEEE80211_SKB_CB(skb);
 
        /* TODO: handle dummy packets on multi-vifs */
        is_dummy = wl12xx_is_dummy_packet(wl, skb);
 
-       if (info->control.hw_key &&
+       if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+           info->control.hw_key &&
            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
                extra = WL1271_EXTRA_SPACE_TKIP;
 
@@ -373,6 +381,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                                return ret;
                        wlvif->default_key = idx;
                }
+
+               is_gem = (cipher == WL1271_CIPHER_SUITE_GEM);
        }
        hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
        if (hlid == WL12XX_INVALID_LINK_ID) {
@@ -380,7 +390,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                return -EINVAL;
        }
 
-       ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid);
+       ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid,
+                                is_gem);
        if (ret < 0)
                return ret;
 
@@ -425,10 +436,10 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
                rate_set >>= 1;
        }
 
-       /* MCS rates indication are on bits 16 - 23 */
+       /* MCS rates indication are on bits 16 - 31 */
        rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
 
-       for (bit = 0; bit < 8; bit++) {
+       for (bit = 0; bit < 16; bit++) {
                if (rate_set & 0x1)
                        enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
                rate_set >>= 1;
@@ -439,18 +450,15 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
 
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
 {
-       unsigned long flags;
        int i;
 
        for (i = 0; i < NUM_TX_QUEUES; i++) {
-               if (test_bit(i, &wl->stopped_queues_map) &&
+               if (wlcore_is_queue_stopped_by_reason(wl, i,
+                       WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
                    wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
                        /* firmware buffer has space, restart queues */
-                       spin_lock_irqsave(&wl->wl_lock, flags);
-                       ieee80211_wake_queue(wl->hw,
-                                            wl1271_tx_get_mac80211_queue(i));
-                       clear_bit(i, &wl->stopped_queues_map);
-                       spin_unlock_irqrestore(&wl->wl_lock, flags);
+                       wlcore_wake_queue(wl, i,
+                                         WLCORE_QUEUE_STOP_REASON_WATERMARK);
                }
        }
 }
@@ -656,18 +664,29 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
        }
 }
 
-void wl1271_tx_work_locked(struct wl1271 *wl)
+/*
+ * Returns failure values only in case of failed bus ops within this function.
+ * wl1271_prepare_tx_frame retvals won't be returned in order to avoid
+ * triggering recovery by higher layers when not necessary.
+ * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery
+ * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame
+ * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING
+ * within prepare_tx_frame code but there's nothing we should do about those
+ * as well.
+ */
+int wlcore_tx_work_locked(struct wl1271 *wl)
 {
        struct wl12xx_vif *wlvif;
        struct sk_buff *skb;
        struct wl1271_tx_hw_descr *desc;
-       u32 buf_offset = 0;
+       u32 buf_offset = 0, last_len = 0;
        bool sent_packets = false;
        unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
-       int ret;
+       int ret = 0;
+       int bus_ret = 0;
 
        if (unlikely(wl->state == WL1271_STATE_OFF))
-               return;
+               return 0;
 
        while ((skb = wl1271_skb_dequeue(wl))) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -685,8 +704,14 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
                         * Flush buffer and try again.
                         */
                        wl1271_skb_queue_head(wl, wlvif, skb);
-                       wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
-                                         buf_offset, true);
+
+                       buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
+                                                           last_len);
+                       bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
+                                            wl->aggr_buf, buf_offset, true);
+                       if (bus_ret < 0)
+                               goto out;
+
                        sent_packets = true;
                        buf_offset = 0;
                        continue;
@@ -710,7 +735,8 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
                                ieee80211_free_txskb(wl->hw, skb);
                        goto out_ack;
                }
-               buf_offset += ret;
+               last_len = ret;
+               buf_offset += last_len;
                wl->tx_packets_count++;
                if (has_data) {
                        desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -720,8 +746,12 @@ void wl1271_tx_work_locked(struct wl1271 *wl)
 
 out_ack:
        if (buf_offset) {
-               wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
-                                 buf_offset, true);
+               buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
+               bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
+                                            buf_offset, true);
+               if (bus_ret < 0)
+                       goto out;
+
                sent_packets = true;
        }
        if (sent_packets) {
@@ -729,13 +759,19 @@ out_ack:
                 * Interrupt the firmware with the new packets. This is only
                 * required for older hardware revisions
                 */
-               if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
-                       wl1271_write32(wl, WL12XX_HOST_WR_ACCESS,
-                                      wl->tx_packets_count);
+               if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
+                       bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
+                                            wl->tx_packets_count);
+                       if (bus_ret < 0)
+                               goto out;
+               }
 
                wl1271_handle_tx_low_watermark(wl);
        }
        wl12xx_rearm_rx_streaming(wl, active_hlids);
+
+out:
+       return bus_ret;
 }
 
 void wl1271_tx_work(struct work_struct *work)
@@ -748,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work)
        if (ret < 0)
                goto out;
 
-       wl1271_tx_work_locked(wl);
+       ret = wlcore_tx_work_locked(wl);
+       if (ret < 0) {
+               wl12xx_queue_recovery_work(wl);
+               goto out;
+       }
 
        wl1271_ps_elp_sleep(wl);
 out:
@@ -849,7 +889,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
 
        /* remove TKIP header space if present */
-       if (info->control.hw_key &&
+       if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+           info->control.hw_key &&
            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
                memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
@@ -869,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 }
 
 /* Called upon reception of a TX complete interrupt */
-void wl1271_tx_complete(struct wl1271 *wl)
+int wlcore_tx_complete(struct wl1271 *wl)
 {
        struct wl1271_acx_mem_map *memmap =
                (struct wl1271_acx_mem_map *)wl->target_mem_map;
        u32 count, fw_counter;
        u32 i;
+       int ret;
 
        /* read the tx results from the chipset */
-       wl1271_read(wl, le32_to_cpu(memmap->tx_result),
-                   wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+       ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
+                         wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+       if (ret < 0)
+               goto out;
+
        fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
 
        /* write host counter to chipset (to ack) */
-       wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
-                      offsetof(struct wl1271_tx_hw_res_if,
-                               tx_result_host_counter), fw_counter);
+       ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) +
+                            offsetof(struct wl1271_tx_hw_res_if,
+                                     tx_result_host_counter), fw_counter);
+       if (ret < 0)
+               goto out;
 
        count = fw_counter - wl->tx_results_count;
        wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
@@ -904,8 +951,11 @@ void wl1271_tx_complete(struct wl1271 *wl)
 
                wl->tx_results_count++;
        }
+
+out:
+       return ret;
 }
-EXPORT_SYMBOL(wl1271_tx_complete);
+EXPORT_SYMBOL(wlcore_tx_complete);
 
 void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
 {
@@ -958,7 +1008,7 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 
 }
 /* caller must hold wl->mutex and TX must be stopped */
-void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
+void wl12xx_tx_reset(struct wl1271 *wl)
 {
        int i;
        struct sk_buff *skb;
@@ -973,15 +1023,12 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
                        wl->tx_queue_count[i] = 0;
        }
 
-       wl->stopped_queues_map = 0;
-
        /*
         * Make sure the driver is at a consistent state, in case this
         * function is called from a context other than interface removal.
         * This call will always wake the TX queues.
         */
-       if (reset_tx_queues)
-               wl1271_handle_tx_low_watermark(wl);
+       wl1271_handle_tx_low_watermark(wl);
 
        for (i = 0; i < wl->num_tx_desc; i++) {
                if (wl->tx_frames[i] == NULL)
@@ -998,7 +1045,8 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
                         */
                        info = IEEE80211_SKB_CB(skb);
                        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
-                       if (info->control.hw_key &&
+                       if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
+                           info->control.hw_key &&
                            info->control.hw_key->cipher ==
                            WLAN_CIPHER_SUITE_TKIP) {
                                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -1024,6 +1072,11 @@ void wl1271_tx_flush(struct wl1271 *wl)
        int i;
        timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
 
+       /* only one flush should be in progress, for consistent queue state */
+       mutex_lock(&wl->flush_mutex);
+
+       wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
+
        while (!time_after(jiffies, timeout)) {
                mutex_lock(&wl->mutex);
                wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
@@ -1032,7 +1085,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
                if ((wl->tx_frames_cnt == 0) &&
                    (wl1271_tx_total_queue_count(wl) == 0)) {
                        mutex_unlock(&wl->mutex);
-                       return;
+                       goto out;
                }
                mutex_unlock(&wl->mutex);
                msleep(1);
@@ -1045,7 +1098,12 @@ void wl1271_tx_flush(struct wl1271 *wl)
        for (i = 0; i < WL12XX_MAX_LINKS; i++)
                wl1271_tx_reset_link_queues(wl, i);
        mutex_unlock(&wl->mutex);
+
+out:
+       wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
+       mutex_unlock(&wl->flush_mutex);
 }
+EXPORT_SYMBOL_GPL(wl1271_tx_flush);
 
 u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 {
@@ -1054,3 +1112,96 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 
        return BIT(__ffs(rate_set));
 }
+
+void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
+                             enum wlcore_queue_stop_reason reason)
+{
+       bool stopped = !!wl->queue_stop_reasons[queue];
+
+       /* queue should not be stopped for this reason */
+       WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue]));
+
+       if (stopped)
+               return;
+
+       ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+}
+
+void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+                      enum wlcore_queue_stop_reason reason)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       wlcore_stop_queue_locked(wl, queue, reason);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+                      enum wlcore_queue_stop_reason reason)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->wl_lock, flags);
+
+       /* queue should not be clear for this reason */
+       WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue]));
+
+       if (wl->queue_stop_reasons[queue])
+               goto out;
+
+       ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue));
+
+out:
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+void wlcore_stop_queues(struct wl1271 *wl,
+                       enum wlcore_queue_stop_reason reason)
+{
+       int i;
+
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               wlcore_stop_queue(wl, i, reason);
+}
+EXPORT_SYMBOL_GPL(wlcore_stop_queues);
+
+void wlcore_wake_queues(struct wl1271 *wl,
+                       enum wlcore_queue_stop_reason reason)
+{
+       int i;
+
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               wlcore_wake_queue(wl, i, reason);
+}
+EXPORT_SYMBOL_GPL(wlcore_wake_queues);
+
+void wlcore_reset_stopped_queues(struct wl1271 *wl)
+{
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wl->wl_lock, flags);
+
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
+               if (!wl->queue_stop_reasons[i])
+                       continue;
+
+               wl->queue_stop_reasons[i] = 0;
+               ieee80211_wake_queue(wl->hw,
+                                    wl1271_tx_get_mac80211_queue(i));
+       }
+
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+}
+
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+                            enum wlcore_queue_stop_reason reason)
+{
+       return test_bit(reason, &wl->queue_stop_reasons[queue]);
+}
+
+bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue)
+{
+       return !!wl->queue_stop_reasons[queue];
+}
index 2fd6e5dc6f7567324d5e75c9dabd9975eb238c56..1e939b016155c57a45a5a5582b0823f1cbbbea9b 100644 (file)
@@ -85,6 +85,19 @@ struct wl128x_tx_mem {
        u8 extra_bytes;
 } __packed;
 
+struct wl18xx_tx_mem {
+       /*
+        * Total number of memory blocks allocated by the host for
+        * this packet.
+        */
+       u8 total_mem_blocks;
+
+       /*
+        * control bits
+        */
+       u8 ctrl;
+} __packed;
+
 /*
  * On wl128x based devices, when TX packets are aggregated, each packet
  * size must be aligned to the SDIO block size. The maximum block size
@@ -100,6 +113,7 @@ struct wl1271_tx_hw_descr {
        union {
                struct wl127x_tx_mem wl127x_mem;
                struct wl128x_tx_mem wl128x_mem;
+               struct wl18xx_tx_mem wl18xx_mem;
        } __packed;
        /* Device time (in us) when the packet arrived to the driver */
        __le32 start_time;
@@ -116,7 +130,16 @@ struct wl1271_tx_hw_descr {
        u8 tid;
        /* host link ID (HLID) */
        u8 hlid;
-       u8 reserved;
+
+       union {
+               u8 wl12xx_reserved;
+
+               /*
+                * bit 0   -> 0 = udp, 1 = tcp
+                * bit 1:7 -> IP header offset
+                */
+               u8 wl18xx_checksum_data;
+       } __packed;
 } __packed;
 
 enum wl1271_tx_hw_res_status {
@@ -161,6 +184,13 @@ struct wl1271_tx_hw_res_if {
        struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
 } __packed;
 
+enum wlcore_queue_stop_reason {
+       WLCORE_QUEUE_STOP_REASON_WATERMARK,
+       WLCORE_QUEUE_STOP_REASON_FW_RESTART,
+       WLCORE_QUEUE_STOP_REASON_FLUSH,
+       WLCORE_QUEUE_STOP_REASON_SPARE_BLK, /* 18xx specific */
+};
+
 static inline int wl1271_tx_get_queue(int queue)
 {
        switch (queue) {
@@ -204,10 +234,10 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
 }
 
 void wl1271_tx_work(struct work_struct *work);
-void wl1271_tx_work_locked(struct wl1271 *wl);
-void wl1271_tx_complete(struct wl1271 *wl);
+int wlcore_tx_work_locked(struct wl1271 *wl);
+int wlcore_tx_complete(struct wl1271 *wl);
 void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
+void wl12xx_tx_reset(struct wl1271 *wl);
 void wl1271_tx_flush(struct wl1271 *wl);
 u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band);
 u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
@@ -223,6 +253,21 @@ bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
 void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids);
 unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
                                          unsigned int packet_length);
+void wl1271_free_tx_id(struct wl1271 *wl, int id);
+void wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue,
+                             enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queue(struct wl1271 *wl, u8 queue,
+                      enum wlcore_queue_stop_reason reason);
+void wlcore_wake_queue(struct wl1271 *wl, u8 queue,
+                      enum wlcore_queue_stop_reason reason);
+void wlcore_stop_queues(struct wl1271 *wl,
+                       enum wlcore_queue_stop_reason reason);
+void wlcore_wake_queues(struct wl1271 *wl,
+                       enum wlcore_queue_stop_reason reason);
+void wlcore_reset_stopped_queues(struct wl1271 *wl);
+bool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue,
+                                      enum wlcore_queue_stop_reason reason);
+bool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue);
 
 /* from main.c */
 void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid);
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx.h b/drivers/net/wireless/ti/wlcore/wl12xx.h
deleted file mode 100644 (file)
index f12bdf7..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * This file is part of wl1271
- *
- * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
- * Copyright (C) 2008-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 __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#include "conf.h"
-#include "ini.h"
-
-#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
-#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
-
-#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
-#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
-
-#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
-#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
-
-/*
- * wl127x and wl128x are using the same NVS file name. However, the
- * ini parameters between them are different.  The driver validates
- * the correct NVS size in wl1271_boot_upload_nvs().
- */
-#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
-
-#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
-#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
-#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
-
-#define WL1271_CIPHER_SUITE_GEM 0x00147201
-
-#define WL1271_BUSY_WORD_CNT 1
-#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 WL12XX_MAX_ROLES           4
-#define WL12XX_MAX_LINKS           12
-#define WL12XX_INVALID_ROLE_ID     0xff
-#define WL12XX_INVALID_LINK_ID     0xff
-
-#define WL12XX_MAX_RATE_POLICIES 16
-
-/* Defined by FW as 0. Will not be freed or allocated. */
-#define WL12XX_SYSTEM_HLID         0
-
-/*
- * When in AP-mode, we allow (at least) this number of packets
- * to be transmitted to FW for a STA in PS-mode. Only when packets are
- * present in the FW buffers it will wake the sleeping STA. We want to put
- * enough packets for the driver to transmit all of its buffered data before
- * the STA goes to sleep again. But we don't want to take too much memory
- * as it might hurt the throughput of active STAs.
- */
-#define WL1271_PS_STA_MAX_PACKETS  2
-
-#define WL1271_AP_BSS_INDEX        0
-#define WL1271_AP_DEF_BEACON_EXP   20
-
-#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
-
-enum wl1271_state {
-       WL1271_STATE_OFF,
-       WL1271_STATE_ON,
-};
-
-enum wl12xx_fw_type {
-       WL12XX_FW_TYPE_NONE,
-       WL12XX_FW_TYPE_NORMAL,
-       WL12XX_FW_TYPE_MULTI,
-       WL12XX_FW_TYPE_PLT,
-};
-
-struct wl1271;
-
-enum {
-       FW_VER_CHIP,
-       FW_VER_IF_TYPE,
-       FW_VER_MAJOR,
-       FW_VER_SUBTYPE,
-       FW_VER_MINOR,
-
-       NUM_FW_VER
-};
-
-#define FW_VER_CHIP_WL127X 6
-#define FW_VER_CHIP_WL128X 7
-
-#define FW_VER_IF_TYPE_STA 1
-#define FW_VER_IF_TYPE_AP  2
-
-#define FW_VER_MINOR_1_SPARE_STA_MIN 58
-#define FW_VER_MINOR_1_SPARE_AP_MIN  47
-
-#define FW_VER_MINOR_FWLOG_STA_MIN 70
-
-struct wl1271_chip {
-       u32 id;
-       char fw_ver_str[ETHTOOL_BUSINFO_LEN];
-       unsigned int fw_ver[NUM_FW_VER];
-};
-
-struct wl1271_stats {
-       struct acx_statistics *fw_stats;
-       unsigned long fw_stats_update;
-
-       unsigned int retry_count;
-       unsigned int excessive_retries;
-};
-
-#define NUM_TX_QUEUES              4
-#define NUM_RX_PKT_DESC            8
-
-#define AP_MAX_STATIONS            8
-
-struct wl_fw_packet_counters {
-       /* Cumulative counter of released packets per AC */
-       u8 tx_released_pkts[NUM_TX_QUEUES];
-
-       /* Cumulative counter of freed packets per HLID */
-       u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
-
-       /* Cumulative counter of released Voice memory blocks */
-       u8 tx_voice_released_blks;
-
-       u8 padding[3];
-} __packed;
-
-/* FW status registers */
-struct wl_fw_status {
-       __le32 intr;
-       u8  fw_rx_counter;
-       u8  drv_rx_counter;
-       u8  reserved;
-       u8  tx_results_counter;
-       __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
-       __le32 fw_localtime;
-
-       /*
-        * A bitmap (where each bit represents a single HLID)
-        * to indicate if the station is in PS mode.
-        */
-       __le32 link_ps_bitmap;
-
-       /*
-        * A bitmap (where each bit represents a single HLID) to indicate
-        * if the station is in Fast mode
-        */
-       __le32 link_fast_bitmap;
-
-       /* Cumulative counter of total released mem blocks since FW-reset */
-       __le32 total_released_blks;
-
-       /* Size (in Memory Blocks) of TX pool */
-       __le32 tx_total;
-
-       struct wl_fw_packet_counters counters;
-
-       __le32 log_start_addr;
-
-       /* Private status to be used by the lower drivers */
-       u8 priv[0];
-} __packed;
-
-struct wl1271_rx_mem_pool_addr {
-       u32 addr;
-       u32 addr_extra;
-};
-
-#define WL1271_MAX_CHANNELS 64
-struct wl1271_scan {
-       struct cfg80211_scan_request *req;
-       unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
-       bool failed;
-       u8 state;
-       u8 ssid[IEEE80211_MAX_SSID_LEN+1];
-       size_t ssid_len;
-};
-
-struct wl1271_if_operations {
-       void (*read)(struct device *child, int addr, void *buf, size_t len,
-                    bool fixed);
-       void (*write)(struct device *child, int addr, void *buf, size_t len,
-                    bool fixed);
-       void (*reset)(struct device *child);
-       void (*init)(struct device *child);
-       int (*power)(struct device *child, bool enable);
-       void (*set_block_size) (struct device *child, unsigned int blksz);
-};
-
-#define MAX_NUM_KEYS 14
-#define MAX_KEY_SIZE 32
-
-struct wl1271_ap_key {
-       u8 id;
-       u8 key_type;
-       u8 key_size;
-       u8 key[MAX_KEY_SIZE];
-       u8 hlid;
-       u32 tx_seq_32;
-       u16 tx_seq_16;
-};
-
-enum wl12xx_flags {
-       WL1271_FLAG_GPIO_POWER,
-       WL1271_FLAG_TX_QUEUE_STOPPED,
-       WL1271_FLAG_TX_PENDING,
-       WL1271_FLAG_IN_ELP,
-       WL1271_FLAG_ELP_REQUESTED,
-       WL1271_FLAG_IRQ_RUNNING,
-       WL1271_FLAG_FW_TX_BUSY,
-       WL1271_FLAG_DUMMY_PACKET_PENDING,
-       WL1271_FLAG_SUSPENDED,
-       WL1271_FLAG_PENDING_WORK,
-       WL1271_FLAG_SOFT_GEMINI,
-       WL1271_FLAG_RECOVERY_IN_PROGRESS,
-       WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
-       WL1271_FLAG_INTENDED_FW_RECOVERY,
-};
-
-enum wl12xx_vif_flags {
-       WLVIF_FLAG_INITIALIZED,
-       WLVIF_FLAG_STA_ASSOCIATED,
-       WLVIF_FLAG_STA_AUTHORIZED,
-       WLVIF_FLAG_IBSS_JOINED,
-       WLVIF_FLAG_AP_STARTED,
-       WLVIF_FLAG_IN_PS,
-       WLVIF_FLAG_STA_STATE_SENT,
-       WLVIF_FLAG_RX_STREAMING_STARTED,
-       WLVIF_FLAG_PSPOLL_FAILURE,
-       WLVIF_FLAG_CS_PROGRESS,
-       WLVIF_FLAG_AP_PROBE_RESP_SET,
-       WLVIF_FLAG_IN_USE,
-};
-
-struct wl1271_link {
-       /* AP-mode - TX queue per AC in link */
-       struct sk_buff_head tx_queue[NUM_TX_QUEUES];
-
-       /* accounting for allocated / freed packets in FW */
-       u8 allocated_pkts;
-       u8 prev_freed_pkts;
-
-       u8 addr[ETH_ALEN];
-
-       /* bitmap of TIDs where RX BA sessions are active for this link */
-       u8 ba_bitmap;
-};
-
-#define WL1271_MAX_RX_FILTERS 5
-#define WL1271_RX_FILTER_MAX_FIELDS 8
-
-#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
-#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
-#define RX_FILTER_FIELD_OVERHEAD                               \
-       (sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
-#define WL1271_RX_FILTER_MAX_PATTERN_SIZE                      \
-       (WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
-
-#define WL1271_RX_FILTER_FLAG_MASK                BIT(0)
-#define WL1271_RX_FILTER_FLAG_IP_HEADER           0
-#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER     BIT(1)
-
-enum rx_filter_action {
-       FILTER_DROP = 0,
-       FILTER_SIGNAL = 1,
-       FILTER_FW_HANDLE = 2
-};
-
-struct wl12xx_rx_filter_field {
-       __le16 offset;
-       u8 len;
-       u8 flags;
-       u8 *pattern;
-} __packed;
-
-struct wl12xx_rx_filter {
-       u8 action;
-       int num_fields;
-       struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
-};
-
-struct wl1271_station {
-       u8 hlid;
-};
-
-struct wl12xx_vif {
-       struct wl1271 *wl;
-       struct list_head list;
-       unsigned long flags;
-       u8 bss_type;
-       u8 p2p; /* we are using p2p role */
-       u8 role_id;
-
-       /* sta/ibss specific */
-       u8 dev_role_id;
-       u8 dev_hlid;
-
-       union {
-               struct {
-                       u8 hlid;
-                       u8 ba_rx_bitmap;
-
-                       u8 basic_rate_idx;
-                       u8 ap_rate_idx;
-                       u8 p2p_rate_idx;
-
-                       bool qos;
-               } sta;
-               struct {
-                       u8 global_hlid;
-                       u8 bcast_hlid;
-
-                       /* HLIDs bitmap of associated stations */
-                       unsigned long sta_hlid_map[BITS_TO_LONGS(
-                                                       WL12XX_MAX_LINKS)];
-
-                       /* recoreded keys - set here before AP startup */
-                       struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
-
-                       u8 mgmt_rate_idx;
-                       u8 bcast_rate_idx;
-                       u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
-               } ap;
-       };
-
-       /* the hlid of the last transmitted skb */
-       int last_tx_hlid;
-
-       unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
-
-       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
-       u8 ssid_len;
-
-       /* The current band */
-       enum ieee80211_band band;
-       int channel;
-
-       u32 bitrate_masks[IEEE80211_NUM_BANDS];
-       u32 basic_rate_set;
-
-       /*
-        * currently configured rate set:
-        *      bits  0-15 - 802.11abg rates
-        *      bits 16-23 - 802.11n   MCS index mask
-        * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
-        */
-       u32 basic_rate;
-       u32 rate_set;
-
-       /* probe-req template for the current AP */
-       struct sk_buff *probereq;
-
-       /* Beaconing interval (needed for ad-hoc) */
-       u32 beacon_int;
-
-       /* Default key (for WEP) */
-       u32 default_key;
-
-       /* Our association ID */
-       u16 aid;
-
-       /* Session counter for the chipset */
-       int session_counter;
-
-       /* retry counter for PSM entries */
-       u8 psm_entry_retry;
-
-       /* in dBm */
-       int power_level;
-
-       int rssi_thold;
-       int last_rssi_event;
-
-       /* save the current encryption type for auto-arp config */
-       u8 encryption_type;
-       __be32 ip_addr;
-
-       /* RX BA constraint value */
-       bool ba_support;
-       bool ba_allowed;
-
-       /* Rx Streaming */
-       struct work_struct rx_streaming_enable_work;
-       struct work_struct rx_streaming_disable_work;
-       struct timer_list rx_streaming_timer;
-
-       /* does the current role use GEM for encryption (AP or STA) */
-       bool is_gem;
-
-       /*
-        * This struct must be last!
-        * data that has to be saved acrossed reconfigs (e.g. recovery)
-        * should be declared in this struct.
-        */
-       struct {
-               u8 persistent[0];
-               /*
-                * Security sequence number
-                *     bits 0-15: lower 16 bits part of sequence number
-                *     bits 16-47: higher 32 bits part of sequence number
-                *     bits 48-63: not in use
-                */
-               u64 tx_security_seq;
-
-               /* 8 bits of the last sequence number in use */
-               u8 tx_security_last_seq_lsb;
-       };
-};
-
-static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
-{
-       return (struct wl12xx_vif *)vif->drv_priv;
-}
-
-static inline
-struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
-{
-       return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
-}
-
-#define wl12xx_for_each_wlvif(wl, wlvif) \
-               list_for_each_entry(wlvif, &wl->wlvif_list, list)
-
-#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
-               list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
-
-#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type)   \
-               wl12xx_for_each_wlvif(wl, wlvif)                \
-                       if (wlvif->bss_type == _bss_type)
-
-#define wl12xx_for_each_wlvif_sta(wl, wlvif)   \
-               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
-
-#define wl12xx_for_each_wlvif_ap(wl, wlvif)    \
-               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
-
-int wl1271_plt_start(struct wl1271 *wl);
-int wl1271_plt_stop(struct wl1271 *wl);
-int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
-void wl12xx_queue_recovery_work(struct wl1271 *wl);
-size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
-int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
-                                       u16 offset, u8 flags,
-                                       u8 *pattern, u8 len);
-void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
-struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
-int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
-void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
-                                    u8 *buf);
-
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
-#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
-
-#define WL1271_DEFAULT_POWER_LEVEL 0
-
-#define WL1271_TX_QUEUE_LOW_WATERMARK  32
-#define WL1271_TX_QUEUE_HIGH_WATERMARK 256
-
-#define WL1271_DEFERRED_QUEUE_LIMIT    64
-
-/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
-   on in case is has been shut down shortly before */
-#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */
-#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */
-
-/* Macros to handle wl1271.sta_rate_set */
-#define HW_BG_RATES_MASK       0xffff
-#define HW_HT_RATES_OFFSET     16
-
-#define WL12XX_HW_BLOCK_SIZE   256
-
-#endif
index 0b3f0b586f4bb534802b80ebf6dcb1f97e15c8a6..e796974df59bc16729e81309d45cb99d4c00d260 100644 (file)
@@ -24,8 +24,9 @@
 
 #include <linux/platform_device.h>
 
-#include "wl12xx.h"
+#include "wlcore_i.h"
 #include "event.h"
+#include "boot.h"
 
 /* The maximum number of Tx descriptors in all chip families */
 #define WLCORE_MAX_TX_DESCRIPTORS 32
 /* forward declaration */
 struct wl1271_tx_hw_descr;
 enum wl_rx_buf_align;
+struct wl1271_rx_descriptor;
 
 struct wlcore_ops {
        int (*identify_chip)(struct wl1271 *wl);
        int (*identify_fw)(struct wl1271 *wl);
        int (*boot)(struct wl1271 *wl);
-       void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
-                           void *buf, size_t len);
-       void (*ack_event)(struct wl1271 *wl);
+       int (*plt_init)(struct wl1271 *wl);
+       int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr,
+                          void *buf, size_t len);
+       int (*ack_event)(struct wl1271 *wl);
        u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks);
        void (*set_tx_desc_blocks)(struct wl1271 *wl,
                                   struct wl1271_tx_hw_descr *desc,
@@ -50,17 +53,34 @@ struct wlcore_ops {
                                     struct sk_buff *skb);
        enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl,
                                                 u32 rx_desc);
-       void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
+       int (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len);
        u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data,
                                 u32 data_len);
-       void (*tx_delayed_compl)(struct wl1271 *wl);
+       int (*tx_delayed_compl)(struct wl1271 *wl);
        void (*tx_immediate_compl)(struct wl1271 *wl);
        int (*hw_init)(struct wl1271 *wl);
        int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
        u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl,
                                    struct wl12xx_vif *wlvif);
-       s8 (*get_pg_ver)(struct wl1271 *wl);
-       void (*get_mac)(struct wl1271 *wl);
+       int (*get_pg_ver)(struct wl1271 *wl, s8 *ver);
+       int (*get_mac)(struct wl1271 *wl);
+       void (*set_tx_desc_csum)(struct wl1271 *wl,
+                                struct wl1271_tx_hw_descr *desc,
+                                struct sk_buff *skb);
+       void (*set_rx_csum)(struct wl1271 *wl,
+                           struct wl1271_rx_descriptor *desc,
+                           struct sk_buff *skb);
+       u32 (*ap_get_mimo_wide_rate_mask)(struct wl1271 *wl,
+                                         struct wl12xx_vif *wlvif);
+       int (*debugfs_init)(struct wl1271 *wl, struct dentry *rootdir);
+       int (*handle_static_data)(struct wl1271 *wl,
+                                 struct wl1271_static_data *static_data);
+       int (*get_spare_blocks)(struct wl1271 *wl, bool is_gem);
+       int (*set_key)(struct wl1271 *wl, enum set_key_cmd cmd,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta,
+                      struct ieee80211_key_conf *key_conf);
+       u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
 };
 
 enum wlcore_partitions {
@@ -109,6 +129,15 @@ enum wlcore_registers {
        REG_TABLE_LEN,
 };
 
+struct wl1271_stats {
+       void *fw_stats;
+       unsigned long fw_stats_update;
+       size_t fw_stats_len;
+
+       unsigned int retry_count;
+       unsigned int excessive_retries;
+};
+
 struct wl1271 {
        struct ieee80211_hw *hw;
        bool mac80211_registered;
@@ -121,7 +150,6 @@ struct wl1271 {
 
        void (*set_power)(bool enable);
        int irq;
-       int ref_clock;
 
        spinlock_t wl_lock;
 
@@ -186,7 +214,7 @@ struct wl1271 {
 
        /* Frames scheduled for transmission, not handled yet */
        int tx_queue_count[NUM_TX_QUEUES];
-       long stopped_queues_map;
+       unsigned long queue_stop_reasons[NUM_TX_QUEUES];
 
        /* Frames received, not handled yet by mac80211 */
        struct sk_buff_head deferred_rx_queue;
@@ -205,9 +233,6 @@ struct wl1271 {
        /* FW Rx counter */
        u32 rx_counter;
 
-       /* Rx memory pool address */
-       struct wl1271_rx_mem_pool_addr rx_mem_pool_addr;
-
        /* Intermediate buffer, used for packet aggregation */
        u8 *aggr_buf;
 
@@ -228,6 +253,7 @@ struct wl1271 {
 
        /* Hardware recovery work */
        struct work_struct recovery_work;
+       bool watchdog_recovery;
 
        /* Pointer that holds DMA-friendly block for the mailbox */
        struct event_mailbox *mbox;
@@ -263,7 +289,8 @@ struct wl1271 {
        u32 buffer_cmd;
        u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
 
-       struct wl_fw_status *fw_status;
+       struct wl_fw_status_1 *fw_status_1;
+       struct wl_fw_status_2 *fw_status_2;
        struct wl1271_tx_hw_res_if *tx_res_if;
 
        /* Current chipset configuration */
@@ -279,8 +306,6 @@ struct wl1271 {
        /* bands supported by this instance of wl12xx */
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
-       int tcxo_clock;
-
        /*
         * wowlan trigger was configured during suspend.
         * (currently, only "ANY" trigger is supported)
@@ -333,10 +358,8 @@ struct wl1271 {
 
        /* number of TX descriptors the HW supports. */
        u32 num_tx_desc;
-
-       /* spare Tx blocks for normal/GEM operating modes */
-       u32 normal_tx_spare;
-       u32 gem_tx_spare;
+       /* number of RX descriptors the HW supports. */
+       u32 num_rx_desc;
 
        /* translate HW Tx rates to standard rate-indices */
        const u8 **band_rate_to_idx;
@@ -348,19 +371,42 @@ struct wl1271 {
        u8 hw_min_ht_rate;
 
        /* HW HT (11n) capabilities */
-       struct ieee80211_sta_ht_cap ht_cap;
+       struct ieee80211_sta_ht_cap ht_cap[IEEE80211_NUM_BANDS];
 
        /* size of the private FW status data */
        size_t fw_status_priv_len;
 
        /* RX Data filter rule state - enabled/disabled */
        bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
+
+       /* size of the private static data */
+       size_t static_data_priv_len;
+
+       /* the current channel type */
+       enum nl80211_channel_type channel_type;
+
+       /* mutex for protecting the tx_flush function */
+       struct mutex flush_mutex;
+
+       /* sleep auth value currently configured to FW */
+       int sleep_auth;
 };
 
 int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
 int __devexit wlcore_remove(struct platform_device *pdev);
 struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size);
 int wlcore_free_hw(struct wl1271 *wl);
+int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
+                  struct ieee80211_vif *vif,
+                  struct ieee80211_sta *sta,
+                  struct ieee80211_key_conf *key_conf);
+
+static inline void
+wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
+                 struct ieee80211_sta_ht_cap *ht_cap)
+{
+       memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap));
+}
 
 /* Firmware image load chunk size */
 #define CHUNK_SIZE     16384
@@ -385,6 +431,12 @@ int wlcore_free_hw(struct wl1271 *wl);
 /* Some firmwares may not support ELP */
 #define WLCORE_QUIRK_NO_ELP                    BIT(6)
 
+/* pad only the last frame in the aggregate buffer */
+#define WLCORE_QUIRK_TX_PAD_LAST_FRAME         BIT(7)
+
+/* extra header space is required for TKIP */
+#define WLCORE_QUIRK_TKIP_HEADER_SPACE         BIT(8)
+
 /* TODO: move to the lower drivers when all usages are abstracted */
 #define CHIP_ID_1271_PG10              (0x4030101)
 #define CHIP_ID_1271_PG20              (0x4030111)
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
new file mode 100644 (file)
index 0000000..4273a21
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
+ * Copyright (C) 2008-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 __WLCORE_I_H__
+#define __WLCORE_I_H__
+
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <net/mac80211.h>
+
+#include "conf.h"
+#include "ini.h"
+
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
+
+/*
+ * wl127x and wl128x are using the same NVS file name. However, the
+ * ini parameters between them are different.  The driver validates
+ * the correct NVS size in wl1271_boot_upload_nvs().
+ */
+#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
+
+#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
+#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
+
+#define WL1271_CIPHER_SUITE_GEM 0x00147201
+
+#define WL1271_BUSY_WORD_CNT 1
+#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 WL12XX_MAX_ROLES           4
+#define WL12XX_MAX_LINKS           12
+#define WL12XX_INVALID_ROLE_ID     0xff
+#define WL12XX_INVALID_LINK_ID     0xff
+
+#define WL12XX_MAX_RATE_POLICIES 16
+
+/* Defined by FW as 0. Will not be freed or allocated. */
+#define WL12XX_SYSTEM_HLID         0
+
+/*
+ * When in AP-mode, we allow (at least) this number of packets
+ * to be transmitted to FW for a STA in PS-mode. Only when packets are
+ * present in the FW buffers it will wake the sleeping STA. We want to put
+ * enough packets for the driver to transmit all of its buffered data before
+ * the STA goes to sleep again. But we don't want to take too much memory
+ * as it might hurt the throughput of active STAs.
+ */
+#define WL1271_PS_STA_MAX_PACKETS  2
+
+#define WL1271_AP_BSS_INDEX        0
+#define WL1271_AP_DEF_BEACON_EXP   20
+
+#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE)
+
+enum wl1271_state {
+       WL1271_STATE_OFF,
+       WL1271_STATE_ON,
+};
+
+enum wl12xx_fw_type {
+       WL12XX_FW_TYPE_NONE,
+       WL12XX_FW_TYPE_NORMAL,
+       WL12XX_FW_TYPE_MULTI,
+       WL12XX_FW_TYPE_PLT,
+};
+
+struct wl1271;
+
+enum {
+       FW_VER_CHIP,
+       FW_VER_IF_TYPE,
+       FW_VER_MAJOR,
+       FW_VER_SUBTYPE,
+       FW_VER_MINOR,
+
+       NUM_FW_VER
+};
+
+#define FW_VER_CHIP_WL127X 6
+#define FW_VER_CHIP_WL128X 7
+
+#define FW_VER_IF_TYPE_STA 1
+#define FW_VER_IF_TYPE_AP  2
+
+#define FW_VER_MINOR_1_SPARE_STA_MIN 58
+#define FW_VER_MINOR_1_SPARE_AP_MIN  47
+
+#define FW_VER_MINOR_FWLOG_STA_MIN 70
+
+struct wl1271_chip {
+       u32 id;
+       char fw_ver_str[ETHTOOL_BUSINFO_LEN];
+       unsigned int fw_ver[NUM_FW_VER];
+};
+
+#define NUM_TX_QUEUES              4
+
+#define AP_MAX_STATIONS            8
+
+struct wl_fw_packet_counters {
+       /* Cumulative counter of released packets per AC */
+       u8 tx_released_pkts[NUM_TX_QUEUES];
+
+       /* Cumulative counter of freed packets per HLID */
+       u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS];
+
+       /* Cumulative counter of released Voice memory blocks */
+       u8 tx_voice_released_blks;
+
+       u8 padding[3];
+} __packed;
+
+/* FW status registers */
+struct wl_fw_status_1 {
+       __le32 intr;
+       u8  fw_rx_counter;
+       u8  drv_rx_counter;
+       u8  reserved;
+       u8  tx_results_counter;
+       __le32 rx_pkt_descs[0];
+} __packed;
+
+/*
+ * Each HW arch has a different number of Rx descriptors.
+ * The length of the status depends on it, since it holds an array
+ * of descriptors.
+ */
+#define WLCORE_FW_STATUS_1_LEN(num_rx_desc) \
+               (sizeof(struct wl_fw_status_1) + \
+               (sizeof(((struct wl_fw_status_1 *)0)->rx_pkt_descs[0])) * \
+               num_rx_desc)
+
+struct wl_fw_status_2 {
+       __le32 fw_localtime;
+
+       /*
+        * A bitmap (where each bit represents a single HLID)
+        * to indicate if the station is in PS mode.
+        */
+       __le32 link_ps_bitmap;
+
+       /*
+        * A bitmap (where each bit represents a single HLID) to indicate
+        * if the station is in Fast mode
+        */
+       __le32 link_fast_bitmap;
+
+       /* Cumulative counter of total released mem blocks since FW-reset */
+       __le32 total_released_blks;
+
+       /* Size (in Memory Blocks) of TX pool */
+       __le32 tx_total;
+
+       struct wl_fw_packet_counters counters;
+
+       __le32 log_start_addr;
+
+       /* Private status to be used by the lower drivers */
+       u8 priv[0];
+} __packed;
+
+#define WL1271_MAX_CHANNELS 64
+struct wl1271_scan {
+       struct cfg80211_scan_request *req;
+       unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
+       bool failed;
+       u8 state;
+       u8 ssid[IEEE80211_MAX_SSID_LEN+1];
+       size_t ssid_len;
+};
+
+struct wl1271_if_operations {
+       int __must_check (*read)(struct device *child, int addr, void *buf,
+                                size_t len, bool fixed);
+       int __must_check (*write)(struct device *child, int addr, void *buf,
+                                 size_t len, bool fixed);
+       void (*reset)(struct device *child);
+       void (*init)(struct device *child);
+       int (*power)(struct device *child, bool enable);
+       void (*set_block_size) (struct device *child, unsigned int blksz);
+};
+
+#define MAX_NUM_KEYS 14
+#define MAX_KEY_SIZE 32
+
+struct wl1271_ap_key {
+       u8 id;
+       u8 key_type;
+       u8 key_size;
+       u8 key[MAX_KEY_SIZE];
+       u8 hlid;
+       u32 tx_seq_32;
+       u16 tx_seq_16;
+};
+
+enum wl12xx_flags {
+       WL1271_FLAG_GPIO_POWER,
+       WL1271_FLAG_TX_QUEUE_STOPPED,
+       WL1271_FLAG_TX_PENDING,
+       WL1271_FLAG_IN_ELP,
+       WL1271_FLAG_ELP_REQUESTED,
+       WL1271_FLAG_IRQ_RUNNING,
+       WL1271_FLAG_FW_TX_BUSY,
+       WL1271_FLAG_DUMMY_PACKET_PENDING,
+       WL1271_FLAG_SUSPENDED,
+       WL1271_FLAG_PENDING_WORK,
+       WL1271_FLAG_SOFT_GEMINI,
+       WL1271_FLAG_RECOVERY_IN_PROGRESS,
+       WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
+       WL1271_FLAG_INTENDED_FW_RECOVERY,
+       WL1271_FLAG_SDIO_FAILED,
+};
+
+enum wl12xx_vif_flags {
+       WLVIF_FLAG_INITIALIZED,
+       WLVIF_FLAG_STA_ASSOCIATED,
+       WLVIF_FLAG_STA_AUTHORIZED,
+       WLVIF_FLAG_IBSS_JOINED,
+       WLVIF_FLAG_AP_STARTED,
+       WLVIF_FLAG_IN_PS,
+       WLVIF_FLAG_STA_STATE_SENT,
+       WLVIF_FLAG_RX_STREAMING_STARTED,
+       WLVIF_FLAG_PSPOLL_FAILURE,
+       WLVIF_FLAG_CS_PROGRESS,
+       WLVIF_FLAG_AP_PROBE_RESP_SET,
+       WLVIF_FLAG_IN_USE,
+};
+
+struct wl1271_link {
+       /* AP-mode - TX queue per AC in link */
+       struct sk_buff_head tx_queue[NUM_TX_QUEUES];
+
+       /* accounting for allocated / freed packets in FW */
+       u8 allocated_pkts;
+       u8 prev_freed_pkts;
+
+       u8 addr[ETH_ALEN];
+
+       /* bitmap of TIDs where RX BA sessions are active for this link */
+       u8 ba_bitmap;
+};
+
+#define WL1271_MAX_RX_FILTERS 5
+#define WL1271_RX_FILTER_MAX_FIELDS 8
+
+#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
+#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
+#define RX_FILTER_FIELD_OVERHEAD                               \
+       (sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
+#define WL1271_RX_FILTER_MAX_PATTERN_SIZE                      \
+       (WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
+
+#define WL1271_RX_FILTER_FLAG_MASK                BIT(0)
+#define WL1271_RX_FILTER_FLAG_IP_HEADER           0
+#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER     BIT(1)
+
+enum rx_filter_action {
+       FILTER_DROP = 0,
+       FILTER_SIGNAL = 1,
+       FILTER_FW_HANDLE = 2
+};
+
+struct wl12xx_rx_filter_field {
+       __le16 offset;
+       u8 len;
+       u8 flags;
+       u8 *pattern;
+} __packed;
+
+struct wl12xx_rx_filter {
+       u8 action;
+       int num_fields;
+       struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
+};
+
+struct wl1271_station {
+       u8 hlid;
+};
+
+struct wl12xx_vif {
+       struct wl1271 *wl;
+       struct list_head list;
+       unsigned long flags;
+       u8 bss_type;
+       u8 p2p; /* we are using p2p role */
+       u8 role_id;
+
+       /* sta/ibss specific */
+       u8 dev_role_id;
+       u8 dev_hlid;
+
+       union {
+               struct {
+                       u8 hlid;
+                       u8 ba_rx_bitmap;
+
+                       u8 basic_rate_idx;
+                       u8 ap_rate_idx;
+                       u8 p2p_rate_idx;
+
+                       bool qos;
+               } sta;
+               struct {
+                       u8 global_hlid;
+                       u8 bcast_hlid;
+
+                       /* HLIDs bitmap of associated stations */
+                       unsigned long sta_hlid_map[BITS_TO_LONGS(
+                                                       WL12XX_MAX_LINKS)];
+
+                       /* recoreded keys - set here before AP startup */
+                       struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS];
+
+                       u8 mgmt_rate_idx;
+                       u8 bcast_rate_idx;
+                       u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT];
+               } ap;
+       };
+
+       /* the hlid of the last transmitted skb */
+       int last_tx_hlid;
+
+       unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)];
+
+       u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+       u8 ssid_len;
+
+       /* The current band */
+       enum ieee80211_band band;
+       int channel;
+       enum nl80211_channel_type channel_type;
+
+       u32 bitrate_masks[IEEE80211_NUM_BANDS];
+       u32 basic_rate_set;
+
+       /*
+        * currently configured rate set:
+        *      bits  0-15 - 802.11abg rates
+        *      bits 16-23 - 802.11n   MCS index mask
+        * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
+        */
+       u32 basic_rate;
+       u32 rate_set;
+
+       /* probe-req template for the current AP */
+       struct sk_buff *probereq;
+
+       /* Beaconing interval (needed for ad-hoc) */
+       u32 beacon_int;
+
+       /* Default key (for WEP) */
+       u32 default_key;
+
+       /* Our association ID */
+       u16 aid;
+
+       /* Session counter for the chipset */
+       int session_counter;
+
+       /* retry counter for PSM entries */
+       u8 psm_entry_retry;
+
+       /* in dBm */
+       int power_level;
+
+       int rssi_thold;
+       int last_rssi_event;
+
+       /* save the current encryption type for auto-arp config */
+       u8 encryption_type;
+       __be32 ip_addr;
+
+       /* RX BA constraint value */
+       bool ba_support;
+       bool ba_allowed;
+
+       /* Rx Streaming */
+       struct work_struct rx_streaming_enable_work;
+       struct work_struct rx_streaming_disable_work;
+       struct timer_list rx_streaming_timer;
+
+       /*
+        * This struct must be last!
+        * data that has to be saved acrossed reconfigs (e.g. recovery)
+        * should be declared in this struct.
+        */
+       struct {
+               u8 persistent[0];
+               /*
+                * Security sequence number
+                *     bits 0-15: lower 16 bits part of sequence number
+                *     bits 16-47: higher 32 bits part of sequence number
+                *     bits 48-63: not in use
+                */
+               u64 tx_security_seq;
+
+               /* 8 bits of the last sequence number in use */
+               u8 tx_security_last_seq_lsb;
+       };
+};
+
+static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif)
+{
+       return (struct wl12xx_vif *)vif->drv_priv;
+}
+
+static inline
+struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
+{
+       return container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
+}
+
+#define wl12xx_for_each_wlvif(wl, wlvif) \
+               list_for_each_entry(wlvif, &wl->wlvif_list, list)
+
+#define wl12xx_for_each_wlvif_continue(wl, wlvif) \
+               list_for_each_entry_continue(wlvif, &wl->wlvif_list, list)
+
+#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type)   \
+               wl12xx_for_each_wlvif(wl, wlvif)                \
+                       if (wlvif->bss_type == _bss_type)
+
+#define wl12xx_for_each_wlvif_sta(wl, wlvif)   \
+               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
+
+#define wl12xx_for_each_wlvif_ap(wl, wlvif)    \
+               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
+
+int wl1271_plt_start(struct wl1271 *wl);
+int wl1271_plt_stop(struct wl1271 *wl);
+int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
+void wl12xx_queue_recovery_work(struct wl1271 *wl);
+size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
+int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
+                                       u16 offset, u8 flags,
+                                       u8 *pattern, u8 len);
+void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
+struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
+int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
+void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
+                                    u8 *buf);
+
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
+
+#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */
+#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */
+
+#define WL1271_DEFAULT_POWER_LEVEL 0
+
+#define WL1271_TX_QUEUE_LOW_WATERMARK  32
+#define WL1271_TX_QUEUE_HIGH_WATERMARK 256
+
+#define WL1271_DEFERRED_QUEUE_LIMIT    64
+
+/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
+   on in case is has been shut down shortly before */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */
+#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */
+
+/* Macros to handle wl1271.sta_rate_set */
+#define HW_BG_RATES_MASK       0xffff
+#define HW_HT_RATES_OFFSET     16
+#define HW_MIMO_RATES_OFFSET   24
+
+#define WL12XX_HW_BLOCK_SIZE   256
+
+#endif /* __WLCORE_I_H__ */
index 19110f0eb15f2d0b15bafbdd8109f155004db7f5..9ac829e22e732036f1c13ed5ec4668102a2c261e 100644 (file)
@@ -45,6 +45,9 @@ static const struct usb_device_id pn533_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, pn533_table);
 
+/* How much time we spend listening for initiators */
+#define PN533_LISTEN_TIME 2
+
 /* frame definitions */
 #define PN533_FRAME_TAIL_SIZE 2
 #define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
@@ -74,6 +77,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_IN_RELEASE 0x52
 #define PN533_CMD_IN_JUMP_FOR_DEP 0x56
 
+#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
+#define PN533_CMD_TG_GET_DATA 0x86
+#define PN533_CMD_TG_SET_DATA 0x8e
+
 #define PN533_CMD_RESPONSE(cmd) (cmd + 1)
 
 /* PN533 Return codes */
@@ -81,6 +88,9 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 #define PN533_CMD_MI_MASK 0x40
 #define PN533_CMD_RET_SUCCESS 0x00
 
+/* PN533 status codes */
+#define PN533_STATUS_TARGET_RELEASED 0x29
+
 struct pn533;
 
 typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
@@ -97,8 +107,14 @@ struct pn533_fw_version {
 };
 
 /* PN533_CMD_RF_CONFIGURATION */
+#define PN533_CFGITEM_TIMING 0x02
 #define PN533_CFGITEM_MAX_RETRIES 0x05
 
+#define PN533_CONFIG_TIMING_102 0xb
+#define PN533_CONFIG_TIMING_204 0xc
+#define PN533_CONFIG_TIMING_409 0xd
+#define PN533_CONFIG_TIMING_819 0xe
+
 #define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
 #define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
 
@@ -108,6 +124,12 @@ struct pn533_config_max_retries {
        u8 mx_rty_passive_act;
 } __packed;
 
+struct pn533_config_timing {
+       u8 rfu;
+       u8 atr_res_timeout;
+       u8 dep_timeout;
+} __packed;
+
 /* PN533_CMD_IN_LIST_PASSIVE_TARGET */
 
 /* felica commands opcode */
@@ -144,6 +166,7 @@ enum {
        PN533_POLL_MOD_424KBPS_FELICA,
        PN533_POLL_MOD_106KBPS_JEWEL,
        PN533_POLL_MOD_847KBPS_B,
+       PN533_LISTEN_MOD,
 
        __PN533_POLL_MOD_AFTER_LAST,
 };
@@ -211,6 +234,9 @@ const struct pn533_poll_modulations poll_mod[] = {
                },
                .len = 3,
        },
+       [PN533_LISTEN_MOD] = {
+               .len = 0,
+       },
 };
 
 /* PN533_CMD_IN_ATR */
@@ -237,7 +263,7 @@ struct pn533_cmd_jump_dep {
        u8 active;
        u8 baud;
        u8 next;
-       u8 gt[];
+       u8 data[];
 } __packed;
 
 struct pn533_cmd_jump_dep_response {
@@ -253,6 +279,29 @@ struct pn533_cmd_jump_dep_response {
        u8 gt[];
 } __packed;
 
+
+/* PN533_TG_INIT_AS_TARGET */
+#define PN533_INIT_TARGET_PASSIVE 0x1
+#define PN533_INIT_TARGET_DEP 0x2
+
+#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3
+#define PN533_INIT_TARGET_RESP_ACTIVE     0x1
+#define PN533_INIT_TARGET_RESP_DEP        0x4
+
+struct pn533_cmd_init_target {
+       u8 mode;
+       u8 mifare[6];
+       u8 felica[18];
+       u8 nfcid3[10];
+       u8 gb_len;
+       u8 gb[];
+} __packed;
+
+struct pn533_cmd_init_target_response {
+       u8 mode;
+       u8 cmd[];
+} __packed;
+
 struct pn533 {
        struct usb_device *udev;
        struct usb_interface *interface;
@@ -270,22 +319,31 @@ struct pn533 {
 
        struct workqueue_struct *wq;
        struct work_struct cmd_work;
+       struct work_struct poll_work;
        struct work_struct mi_work;
+       struct work_struct tg_work;
+       struct timer_list listen_timer;
        struct pn533_frame *wq_in_frame;
        int wq_in_error;
+       int cancel_listen;
 
        pn533_cmd_complete_t cmd_complete;
        void *cmd_complete_arg;
-       struct semaphore cmd_lock;
+       struct mutex cmd_lock;
        u8 cmd;
 
        struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
        u8 poll_mod_count;
        u8 poll_mod_curr;
        u32 poll_protocols;
+       u32 listen_protocols;
+
+       u8 *gb;
+       size_t gb_len;
 
        u8 tgt_available_prots;
        u8 tgt_active_prot;
+       u8 tgt_mode;
 };
 
 struct pn533_frame {
@@ -405,7 +463,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
                                        PN533_FRAME_CMD_PARAMS_LEN(in_frame));
 
        if (rc != -EINPROGRESS)
-               up(&dev->cmd_lock);
+               mutex_unlock(&dev->cmd_lock);
 }
 
 static void pn533_recv_response(struct urb *urb)
@@ -583,7 +641,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (down_trylock(&dev->cmd_lock))
+       if (!mutex_trylock(&dev->cmd_lock))
                return -EBUSY;
 
        rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
@@ -593,7 +651,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
 
        return 0;
 error:
-       up(&dev->cmd_lock);
+       mutex_unlock(&dev->cmd_lock);
        return rc;
 }
 
@@ -963,6 +1021,11 @@ static int pn533_target_found(struct pn533 *dev,
        return 0;
 }
 
+static inline void pn533_poll_next_mod(struct pn533 *dev)
+{
+       dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+}
+
 static void pn533_poll_reset_mod_list(struct pn533 *dev)
 {
        dev->poll_mod_count = 0;
@@ -975,102 +1038,283 @@ static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
        dev->poll_mod_count++;
 }
 
-static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
+static void pn533_poll_create_mod_list(struct pn533 *dev,
+                                      u32 im_protocols, u32 tm_protocols)
 {
        pn533_poll_reset_mod_list(dev);
 
-       if (protocols & NFC_PROTO_MIFARE_MASK
-                                       || protocols & NFC_PROTO_ISO14443_MASK
-                                       || protocols & NFC_PROTO_NFC_DEP_MASK)
+       if (im_protocols & NFC_PROTO_MIFARE_MASK
+           || im_protocols & NFC_PROTO_ISO14443_MASK
+           || im_protocols & NFC_PROTO_NFC_DEP_MASK)
                pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
 
-       if (protocols & NFC_PROTO_FELICA_MASK
-                                       || protocols & NFC_PROTO_NFC_DEP_MASK) {
+       if (im_protocols & NFC_PROTO_FELICA_MASK
+           || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
                pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
                pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
        }
 
-       if (protocols & NFC_PROTO_JEWEL_MASK)
+       if (im_protocols & NFC_PROTO_JEWEL_MASK)
                pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
 
-       if (protocols & NFC_PROTO_ISO14443_MASK)
+       if (im_protocols & NFC_PROTO_ISO14443_MASK)
                pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
+
+       if (tm_protocols)
+               pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
+}
+
+static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
+                                    u8 *params, int params_len)
+{
+       struct pn533_poll_response *resp;
+       int rc;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       resp = (struct pn533_poll_response *) params;
+       if (resp->nbtg) {
+               rc = pn533_target_found(dev, resp, params_len);
+
+               /* We must stop the poll after a valid target found */
+               if (rc == 0) {
+                       pn533_poll_reset_mod_list(dev);
+                       return 0;
+               }
+       }
+
+       return -EAGAIN;
 }
 
-static void pn533_start_poll_frame(struct pn533_frame *frame,
-                                       struct pn533_poll_modulations *mod)
+static int pn533_init_target_frame(struct pn533_frame *frame,
+                                  u8 *gb, size_t gb_len)
 {
+       struct pn533_cmd_init_target *cmd;
+       size_t cmd_len;
+       u8 felica_params[18] = {0x1, 0xfe, /* DEP */
+                               0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
+                               0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+                               0xff, 0xff}; /* System code */
+       u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
+                              0x0, 0x0, 0x0,
+                              0x40}; /* SEL_RES for DEP */
+
+       cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
+       cmd = kzalloc(cmd_len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+
+       /* DEP support only */
+       cmd->mode |= PN533_INIT_TARGET_DEP;
+
+       /* Felica params */
+       memcpy(cmd->felica, felica_params, 18);
+       get_random_bytes(cmd->felica + 2, 6);
+
+       /* NFCID3 */
+       memset(cmd->nfcid3, 0, 10);
+       memcpy(cmd->nfcid3, cmd->felica, 8);
 
-       pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+       /* MIFARE params */
+       memcpy(cmd->mifare, mifare_params, 6);
 
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
-       frame->datalen += mod->len;
+       /* General bytes */
+       cmd->gb_len = gb_len;
+       memcpy(cmd->gb, gb, gb_len);
+
+       /* Len Tk */
+       cmd->gb[gb_len] = 0;
+
+       memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+
+       frame->datalen += cmd_len;
 
        pn533_tx_frame_finish(frame);
+
+       kfree(cmd);
+
+       return 0;
 }
 
-static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
-                                               u8 *params, int params_len)
+#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
+                                     u8 *params, int params_len)
 {
-       struct pn533_poll_response *resp;
-       struct pn533_poll_modulations *next_mod;
-       int rc;
+       struct sk_buff *skb_resp = arg;
+       struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
-       if (params_len == -ENOENT) {
-               nfc_dev_dbg(&dev->interface->dev, "Polling operation has been"
-                                                               " stopped");
-               goto stop_poll;
+       if (params_len < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when starting as a target",
+                           params_len);
+
+               return params_len;
        }
 
+       if (params_len > 0 && params[0] != 0) {
+               nfc_tm_deactivated(dev->nfc_dev);
+
+               dev->tgt_mode = 0;
+
+               kfree_skb(skb_resp);
+               return 0;
+       }
+
+       skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
+       skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
+       skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
+
+       return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+}
+
+static void pn533_wq_tg_get_data(struct work_struct *work)
+{
+       struct pn533 *dev = container_of(work, struct pn533, tg_work);
+       struct pn533_frame *in_frame;
+       struct sk_buff *skb_resp;
+       size_t skb_resp_len;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
+               PN533_CMD_DATAEXCH_DATA_MAXLEN +
+               PN533_FRAME_TAIL_SIZE;
+
+       skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
+       if (!skb_resp)
+               return;
+
+       in_frame = (struct pn533_frame *)skb_resp->data;
+
+       pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
+       pn533_tx_frame_finish(dev->out_frame);
+
+       pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
+                                  skb_resp_len,
+                                  pn533_tm_get_data_complete,
+                                  skb_resp, GFP_KERNEL);
+
+       return;
+}
+
+#define ATR_REQ_GB_OFFSET 17
+static int pn533_init_target_complete(struct pn533 *dev, void *arg,
+                                     u8 *params, int params_len)
+{
+       struct pn533_cmd_init_target_response *resp;
+       u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+       size_t gb_len;
+       int rc;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
        if (params_len < 0) {
-               nfc_dev_err(&dev->interface->dev, "Error %d when running poll",
-                                                               params_len);
-               goto stop_poll;
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when starting as a target",
+                           params_len);
+
+               return params_len;
        }
 
-       resp = (struct pn533_poll_response *) params;
-       if (resp->nbtg) {
-               rc = pn533_target_found(dev, resp, params_len);
+       if (params_len < ATR_REQ_GB_OFFSET + 1)
+               return -EINVAL;
 
-               /* We must stop the poll after a valid target found */
-               if (rc == 0)
-                       goto stop_poll;
+       resp = (struct pn533_cmd_init_target_response *) params;
+
+       nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
+                   resp->mode, params_len);
+
+       frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
+       if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+               comm_mode = NFC_COMM_ACTIVE;
 
-               if (rc != -EAGAIN)
-                       nfc_dev_err(&dev->interface->dev, "The target found is"
-                                       " not valid - continuing to poll");
+       /* Again, only DEP */
+       if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+               return -EOPNOTSUPP;
+
+       gb = resp->cmd + ATR_REQ_GB_OFFSET;
+       gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+
+       rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+                             comm_mode, gb, gb_len);
+       if (rc < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error when signaling target activation");
+               return rc;
        }
 
-       dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+       dev->tgt_mode = 1;
 
-       next_mod = dev->poll_mod_active[dev->poll_mod_curr];
+       queue_work(dev->wq, &dev->tg_work);
 
-       nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)",
-                                                       dev->poll_mod_curr);
+       return 0;
+}
+
+static void pn533_listen_mode_timer(unsigned long data)
+{
+       struct pn533 *dev = (struct pn533 *) data;
+
+       nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
+
+       /* An ack will cancel the last issued command (poll) */
+       pn533_send_ack(dev, GFP_ATOMIC);
+
+       dev->cancel_listen = 1;
+
+       mutex_unlock(&dev->cmd_lock);
+
+       pn533_poll_next_mod(dev);
+
+       queue_work(dev->wq, &dev->poll_work);
+}
 
-       pn533_start_poll_frame(dev->out_frame, next_mod);
+static int pn533_poll_complete(struct pn533 *dev, void *arg,
+                              u8 *params, int params_len)
+{
+       struct pn533_poll_modulations *cur_mod;
+       int rc;
 
-       /* Don't need to down the semaphore again */
-       rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-                               dev->in_maxlen, pn533_start_poll_complete,
-                               NULL, GFP_ATOMIC);
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       if (params_len == -ENOENT) {
+               if (dev->poll_mod_count != 0)
+                       return 0;
+
+               nfc_dev_err(&dev->interface->dev,
+                           "Polling operation has been stopped");
 
-       if (rc == -EPERM) {
-               nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation"
-                                       " because poll has been stopped");
                goto stop_poll;
        }
 
-       if (rc) {
-               nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll"
-                                                       " next modulation", rc);
+       if (params_len < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when running poll", params_len);
+
                goto stop_poll;
        }
 
-       /* Inform caller function to do not up the semaphore */
-       return -EINPROGRESS;
+       cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+       if (cur_mod->len == 0) {
+               del_timer(&dev->listen_timer);
+
+               return pn533_init_target_complete(dev, arg, params, params_len);
+       } else {
+               rc = pn533_start_poll_complete(dev, arg, params, params_len);
+               if (!rc)
+                       return rc;
+       }
+
+       pn533_poll_next_mod(dev);
+
+       queue_work(dev->wq, &dev->poll_work);
+
+       return 0;
 
 stop_poll:
        pn533_poll_reset_mod_list(dev);
@@ -1078,61 +1322,104 @@ stop_poll:
        return 0;
 }
 
-static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static void pn533_build_poll_frame(struct pn533 *dev,
+                                  struct pn533_frame *frame,
+                                  struct pn533_poll_modulations *mod)
 {
-       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
-       struct pn533_poll_modulations *start_mod;
-       int rc;
+       nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
 
-       nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
-                                                               protocols);
+       if (mod->len == 0) {
+               /* Listen mode */
+               pn533_init_target_frame(frame, dev->gb, dev->gb_len);
+       } else {
+               /* Polling mode */
+               pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
 
-       if (dev->poll_mod_count) {
-               nfc_dev_err(&dev->interface->dev, "Polling operation already"
-                                                               " active");
-               return -EBUSY;
-       }
+               memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
+               frame->datalen += mod->len;
 
-       if (dev->tgt_active_prot) {
-               nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
-                                                       " already activated");
-               return -EBUSY;
+               pn533_tx_frame_finish(frame);
        }
+}
 
-       pn533_poll_create_mod_list(dev, protocols);
+static int pn533_send_poll_frame(struct pn533 *dev)
+{
+       struct pn533_poll_modulations *cur_mod;
+       int rc;
 
-       if (!dev->poll_mod_count) {
-               nfc_dev_err(&dev->interface->dev, "No valid protocols"
-                                                               " specified");
-               rc = -EINVAL;
-               goto error;
+       cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+       pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
+
+       rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+                               dev->in_maxlen, pn533_poll_complete,
+                               NULL, GFP_KERNEL);
+       if (rc)
+               nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
+
+       return rc;
+}
+
+static void pn533_wq_poll(struct work_struct *work)
+{
+       struct pn533 *dev = container_of(work, struct pn533, poll_work);
+       struct pn533_poll_modulations *cur_mod;
+       int rc;
+
+       cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+       nfc_dev_dbg(&dev->interface->dev,
+                   "%s cancel_listen %d modulation len %d",
+                   __func__, dev->cancel_listen, cur_mod->len);
+
+       if (dev->cancel_listen == 1) {
+               dev->cancel_listen = 0;
+               usb_kill_urb(dev->in_urb);
        }
 
-       nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types",
-                                                       dev->poll_mod_count);
+       rc = pn533_send_poll_frame(dev);
+       if (rc)
+               return;
 
-       dev->poll_mod_curr = 0;
-       start_mod = dev->poll_mod_active[dev->poll_mod_curr];
+       if (cur_mod->len == 0 && dev->poll_mod_count > 1)
+               mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ);
 
-       pn533_start_poll_frame(dev->out_frame, start_mod);
+       return;
+}
 
-       rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
-                               dev->in_maxlen, pn533_start_poll_complete,
-                               NULL, GFP_KERNEL);
+static int pn533_start_poll(struct nfc_dev *nfc_dev,
+                           u32 im_protocols, u32 tm_protocols)
+{
+       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
 
-       if (rc) {
-               nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
-                                                       " start poll", rc);
-               goto error;
+       nfc_dev_dbg(&dev->interface->dev,
+                   "%s: im protocols 0x%x tm protocols 0x%x",
+                   __func__, im_protocols, tm_protocols);
+
+       if (dev->tgt_active_prot) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Cannot poll with a target already activated");
+               return -EBUSY;
        }
 
-       dev->poll_protocols = protocols;
+       if (dev->tgt_mode) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Cannot poll while already being activated");
+               return -EBUSY;
+       }
 
-       return 0;
+       if (tm_protocols) {
+               dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
+               if (dev->gb == NULL)
+                       tm_protocols = 0;
+       }
 
-error:
-       pn533_poll_reset_mod_list(dev);
-       return rc;
+       dev->poll_mod_curr = 0;
+       pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
+       dev->poll_protocols = im_protocols;
+       dev->listen_protocols = tm_protocols;
+
+       return pn533_send_poll_frame(dev);
 }
 
 static void pn533_stop_poll(struct nfc_dev *nfc_dev)
@@ -1141,6 +1428,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
+       del_timer(&dev->listen_timer);
+
        if (!dev->poll_mod_count) {
                nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
                                                                " running");
@@ -1152,6 +1441,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 
        /* prevent pn533_start_poll_complete to issue a new poll meanwhile */
        usb_kill_urb(dev->in_urb);
+
+       pn533_poll_reset_mod_list(dev);
 }
 
 static int pn533_activate_target_nfcdep(struct pn533 *dev)
@@ -1349,13 +1640,29 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
        return 0;
 }
 
+static int pn533_mod_to_baud(struct pn533 *dev)
+{
+       switch (dev->poll_mod_curr) {
+       case PN533_POLL_MOD_106KBPS_A:
+               return 0;
+       case PN533_POLL_MOD_212KBPS_FELICA:
+               return 1;
+       case PN533_POLL_MOD_424KBPS_FELICA:
+               return 2;
+       default:
+               return -EINVAL;
+       }
+}
+
+#define PASSIVE_DATA_LEN 5
 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
                             u8 comm_mode, u8* gb, size_t gb_len)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        struct pn533_cmd_jump_dep *cmd;
-       u8 cmd_len;
-       int rc;
+       u8 cmd_len, *data_ptr;
+       u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
+       int rc, baud;
 
        nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
 
@@ -1371,7 +1678,17 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
                return -EBUSY;
        }
 
+       baud = pn533_mod_to_baud(dev);
+       if (baud < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Invalid curr modulation %d", dev->poll_mod_curr);
+               return baud;
+       }
+
        cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+       if (comm_mode == NFC_COMM_PASSIVE)
+               cmd_len += PASSIVE_DATA_LEN;
+
        cmd = kzalloc(cmd_len, GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
@@ -1379,10 +1696,18 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
        pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
 
        cmd->active = !comm_mode;
-       cmd->baud = 0;
+       cmd->next = 0;
+       cmd->baud = baud;
+       data_ptr = cmd->data;
+       if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
+               memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
+               cmd->next |= 1;
+               data_ptr += PASSIVE_DATA_LEN;
+       }
+
        if (gb != NULL && gb_len > 0) {
-               cmd->next = 4; /* We have some Gi */
-               memcpy(cmd->gt, gb, gb_len);
+               cmd->next |= 4; /* We have some Gi */
+               memcpy(data_ptr, gb, gb_len);
        } else {
                cmd->next = 0;
        }
@@ -1407,15 +1732,25 @@ out:
 
 static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
 {
-       pn533_deactivate_target(nfc_dev, 0);
+       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+       pn533_poll_reset_mod_list(dev);
+
+       if (dev->tgt_mode || dev->tgt_active_prot) {
+               pn533_send_ack(dev, GFP_KERNEL);
+               usb_kill_urb(dev->in_urb);
+       }
+
+       dev->tgt_active_prot = 0;
+       dev->tgt_mode = 0;
+
+       skb_queue_purge(&dev->resp_q);
 
        return 0;
 }
 
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
-#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
-
-static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
+static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
+                               bool target)
 {
        int payload_len = skb->len;
        struct pn533_frame *out_frame;
@@ -1432,14 +1767,20 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
                return -ENOSYS;
        }
 
-       skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
-       out_frame = (struct pn533_frame *) skb->data;
+       if (target == true) {
+               skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
+               out_frame = (struct pn533_frame *) skb->data;
 
-       pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+               pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+               tg = 1;
+               memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
+               out_frame->datalen += sizeof(u8);
+       } else {
+               skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
+               out_frame = (struct pn533_frame *) skb->data;
+               pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
+       }
 
-       tg = 1;
-       memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
-       out_frame->datalen += sizeof(u8);
 
        /* The data is already in the out_frame, just update the datalen */
        out_frame->datalen += payload_len;
@@ -1550,9 +1891,9 @@ error:
        return 0;
 }
 
-static int pn533_data_exchange(struct nfc_dev *nfc_dev,
-                              struct nfc_target *target, struct sk_buff *skb,
-                              data_exchange_cb_t cb, void *cb_context)
+static int pn533_transceive(struct nfc_dev *nfc_dev,
+                           struct nfc_target *target, struct sk_buff *skb,
+                           data_exchange_cb_t cb, void *cb_context)
 {
        struct pn533 *dev = nfc_get_drvdata(nfc_dev);
        struct pn533_frame *out_frame, *in_frame;
@@ -1570,7 +1911,7 @@ static int pn533_data_exchange(struct nfc_dev *nfc_dev,
                goto error;
        }
 
-       rc = pn533_data_exchange_tx_frame(dev, skb);
+       rc = pn533_build_tx_frame(dev, skb, true);
        if (rc)
                goto error;
 
@@ -1618,6 +1959,63 @@ error:
        return rc;
 }
 
+static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
+                                 u8 *params, int params_len)
+{
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       if (params_len < 0) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when sending data",
+                           params_len);
+
+               return params_len;
+       }
+
+       if (params_len > 0 && params[0] != 0) {
+               nfc_tm_deactivated(dev->nfc_dev);
+
+               dev->tgt_mode = 0;
+
+               return 0;
+       }
+
+       queue_work(dev->wq, &dev->tg_work);
+
+       return 0;
+}
+
+static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+       struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+       struct pn533_frame *out_frame;
+       int rc;
+
+       nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+       rc = pn533_build_tx_frame(dev, skb, false);
+       if (rc)
+               goto error;
+
+       out_frame = (struct pn533_frame *) skb->data;
+
+       rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
+                                       dev->in_maxlen, pn533_tm_send_complete,
+                                       NULL, GFP_KERNEL);
+       if (rc) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error %d when trying to send data", rc);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       kfree_skb(skb);
+
+       return rc;
+}
+
 static void pn533_wq_mi_recv(struct work_struct *work)
 {
        struct pn533 *dev = container_of(work, struct pn533, mi_work);
@@ -1638,7 +2036,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
 
        skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
 
-       rc = pn533_data_exchange_tx_frame(dev, skb_cmd);
+       rc = pn533_build_tx_frame(dev, skb_cmd, true);
        if (rc)
                goto error_frame;
 
@@ -1677,7 +2075,7 @@ error_cmd:
 
        kfree(arg);
 
-       up(&dev->cmd_lock);
+       mutex_unlock(&dev->cmd_lock);
 }
 
 static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
@@ -1712,7 +2110,8 @@ struct nfc_ops pn533_nfc_ops = {
        .stop_poll = pn533_stop_poll,
        .activate_target = pn533_activate_target,
        .deactivate_target = pn533_deactivate_target,
-       .data_exchange = pn533_data_exchange,
+       .im_transceive = pn533_transceive,
+       .tm_send = pn533_tm_send,
 };
 
 static int pn533_probe(struct usb_interface *interface,
@@ -1723,6 +2122,7 @@ static int pn533_probe(struct usb_interface *interface,
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
        struct pn533_config_max_retries max_retries;
+       struct pn533_config_timing timing;
        int in_endpoint = 0;
        int out_endpoint = 0;
        int rc = -ENOMEM;
@@ -1735,7 +2135,7 @@ static int pn533_probe(struct usb_interface *interface,
 
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
        dev->interface = interface;
-       sema_init(&dev->cmd_lock, 1);
+       mutex_init(&dev->cmd_lock);
 
        iface_desc = interface->cur_altsetting;
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
@@ -1779,12 +2179,18 @@ static int pn533_probe(struct usb_interface *interface,
 
        INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
        INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
+       INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
+       INIT_WORK(&dev->poll_work, pn533_wq_poll);
        dev->wq = alloc_workqueue("pn533",
                                  WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
                                  1);
        if (dev->wq == NULL)
                goto error;
 
+       init_timer(&dev->listen_timer);
+       dev->listen_timer.data = (unsigned long) dev;
+       dev->listen_timer.function = pn533_listen_mode_timer;
+
        skb_queue_head_init(&dev->resp_q);
 
        usb_set_intfdata(interface, dev);
@@ -1830,13 +2236,29 @@ static int pn533_probe(struct usb_interface *interface,
        if (rc) {
                nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
                                                                " config");
-               goto free_nfc_dev;
+               goto unregister_nfc_dev;
+       }
+
+       timing.rfu = PN533_CONFIG_TIMING_102;
+       timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
+       timing.dep_timeout = PN533_CONFIG_TIMING_409;
+
+       rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING,
+                               (u8 *) &timing, sizeof(timing));
+       if (rc) {
+               nfc_dev_err(&dev->interface->dev,
+                           "Error on setting RF timings");
+               goto unregister_nfc_dev;
        }
 
        return 0;
 
+unregister_nfc_dev:
+       nfc_unregister_device(dev->nfc_dev);
+
 free_nfc_dev:
        nfc_free_device(dev->nfc_dev);
+
 destroy_wq:
        destroy_workqueue(dev->wq);
 error:
@@ -1865,6 +2287,8 @@ static void pn533_disconnect(struct usb_interface *interface)
 
        skb_queue_purge(&dev->resp_q);
 
+       del_timer(&dev->listen_timer);
+
        kfree(dev->in_frame);
        usb_free_urb(dev->in_urb);
        kfree(dev->out_frame);
index 281f18c2fb8282670c4dd6dab4593ab4ef3cc4b8..457eac35dc7486dd8fcfe48195585316081d72ce 100644 (file)
@@ -576,7 +576,8 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
        return pn544_hci_i2c_write(client, skb->data, skb->len);
 }
 
-static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
+static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
+                               u32 im_protocols, u32 tm_protocols)
 {
        struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
        u8 phases = 0;
@@ -584,7 +585,8 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
        u8 duration[2];
        u8 activated;
 
-       pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols);
+       pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
+               __func__, im_protocols, tm_protocols);
 
        r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
                               NFC_HCI_EVT_END_OPERATION, NULL, 0);
@@ -604,10 +606,10 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
        if (r < 0)
                return r;
 
-       if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
+       if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
                         NFC_PROTO_JEWEL_MASK))
                phases |= 1;            /* Type A */
-       if (protocols & NFC_PROTO_FELICA_MASK) {
+       if (im_protocols & NFC_PROTO_FELICA_MASK) {
                phases |= (1 << 2);     /* Type F 212 */
                phases |= (1 << 3);     /* Type F 424 */
        }
index f551e53761473c858dcb6694287c320305723f37..266aa1648a020e0ce36df5d63795fd4706869ef4 100644 (file)
@@ -36,6 +36,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
index 266c7c5c86dcba7dcb6c70965534bea331f1b153..ab4627cf11148c96a969ebd966c4657265e49471 100644 (file)
@@ -90,6 +90,8 @@ const char *ssb_core_name(u16 coreid)
                return "ARM 1176";
        case SSB_DEV_ARM_7TDMI:
                return "ARM 7TDMI";
+       case SSB_DEV_ARM_CM3:
+               return "ARM Cortex M3";
        }
        return "UNKNOWN";
 }
index 8deaf6d050c35fcd135bb1e7e34a531e7813939e..12334f9190cb426552f94eb882f9f959afcbe80f 100644 (file)
@@ -70,6 +70,13 @@ struct bcma_host_ops {
 
 /* Core-ID values. */
 #define BCMA_CORE_OOB_ROUTER           0x367   /* Out of band */
+#define BCMA_CORE_4706_CHIPCOMMON      0x500
+#define BCMA_CORE_4706_SOC_RAM         0x50E
+#define BCMA_CORE_4706_MAC_GBIT                0x52D
+#define BCMA_CORE_AMEMC                        0x52E   /* DDR1/2 memory controller core */
+#define BCMA_CORE_ALTA                 0x534   /* I2S core */
+#define BCMA_CORE_4706_MAC_GBIT_COMMON 0x5DC
+#define BCMA_CORE_DDR23_PHY            0x5DD
 #define BCMA_CORE_INVALID              0x700
 #define BCMA_CORE_CHIPCOMMON           0x800
 #define BCMA_CORE_ILINE20              0x801
index ce9af89185148228c76f260bfd68a848f43e3977..318fc1f705b1f1cebe481af87660f63071aa25ab 100644 (file)
@@ -567,6 +567,26 @@ struct ieee80211s_hdr {
 #define MESH_FLAGS_AE          0x3
 #define MESH_FLAGS_PS_DEEP     0x4
 
+/**
+ * enum ieee80211_preq_flags - mesh PREQ element flags
+ *
+ * @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield
+ */
+enum ieee80211_preq_flags {
+       IEEE80211_PREQ_PROACTIVE_PREP_FLAG      = 1<<2,
+};
+
+/**
+ * enum ieee80211_preq_target_flags - mesh PREQ element per target flags
+ *
+ * @IEEE80211_PREQ_TO_FLAG: target only subfield
+ * @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield
+ */
+enum ieee80211_preq_target_flags {
+       IEEE80211_PREQ_TO_FLAG  = 1<<0,
+       IEEE80211_PREQ_USN_FLAG = 1<<2,
+};
+
 /**
  * struct ieee80211_quiet_ie
  *
@@ -1443,7 +1463,7 @@ enum ieee80211_tdls_actioncode {
  *
  * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method
  * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method
- * that will be specified in a vendor specific information element
+ *     that will be specified in a vendor specific information element
  */
 enum {
        IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1,
@@ -1455,7 +1475,7 @@ enum {
  *
  * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol
  * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will
- * be specified in a vendor specific information element
+ *     be specified in a vendor specific information element
  */
 enum {
        IEEE80211_PATH_PROTOCOL_HWMP = 1,
@@ -1467,13 +1487,35 @@ enum {
  *
  * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric
  * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be
- * specified in a vendor specific information element
+ *     specified in a vendor specific information element
  */
 enum {
        IEEE80211_PATH_METRIC_AIRTIME = 1,
        IEEE80211_PATH_METRIC_VENDOR = 255,
 };
 
+/**
+ * enum ieee80211_root_mode_identifier - root mesh STA mode identifier
+ *
+ * These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode
+ *
+ * @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default)
+ * @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than
+ *     this value
+ * @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports
+ *     the proactive PREQ with proactive PREP subfield set to 0
+ * @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA
+ *     supports the proactive PREQ with proactive PREP subfield set to 1
+ * @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports
+ *     the proactive RANN
+ */
+enum ieee80211_root_mode_identifier {
+       IEEE80211_ROOTMODE_NO_ROOT = 0,
+       IEEE80211_ROOTMODE_ROOT = 1,
+       IEEE80211_PROACTIVE_PREQ_NO_PREP = 2,
+       IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3,
+       IEEE80211_PROACTIVE_RANN = 4,
+};
 
 /*
  * IEEE 802.11-2007 7.3.2.9 Country information element
@@ -1589,6 +1631,10 @@ enum ieee80211_sa_query_action {
 
 #define WLAN_OUI_WFA                   0x506f9a
 #define WLAN_OUI_TYPE_WFA_P2P          9
+#define WLAN_OUI_MICROSOFT             0x0050f2
+#define WLAN_OUI_TYPE_MICROSOFT_WPA    1
+#define WLAN_OUI_TYPE_MICROSOFT_WMM    2
+#define WLAN_OUI_TYPE_MICROSOFT_WPS    4
 
 /*
  * WMM/802.11e Tspec Element
index 0ae9b5857c83b0786a9f7ea92ffe51991c34a1b8..f4e6dd915b1c63c8c9d3bbf62ab545909d13ccd8 100644 (file)
  *     %NFC_ATTR_PROTOCOLS)
  * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
  *     (it sends %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_TM_ACTIVATED: event emitted when the adapter is activated in
+ *      target mode.
+ * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
+ *      from target mode.
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -71,6 +75,8 @@ enum nfc_commands {
        NFC_EVENT_DEVICE_ADDED,
        NFC_EVENT_DEVICE_REMOVED,
        NFC_EVENT_TARGET_LOST,
+       NFC_EVENT_TM_ACTIVATED,
+       NFC_EVENT_TM_DEACTIVATED,
 /* private: internal use only */
        __NFC_CMD_AFTER_LAST
 };
@@ -94,6 +100,8 @@ enum nfc_commands {
  * @NFC_ATTR_TARGET_SENSF_RES: NFC-F targets extra information, max 18 bytes
  * @NFC_ATTR_COMM_MODE: Passive or active mode
  * @NFC_ATTR_RF_MODE: Initiator or target
+ * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
+ * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for
  */
 enum nfc_attrs {
        NFC_ATTR_UNSPEC,
@@ -109,6 +117,8 @@ enum nfc_attrs {
        NFC_ATTR_COMM_MODE,
        NFC_ATTR_RF_MODE,
        NFC_ATTR_DEVICE_POWERED,
+       NFC_ATTR_IM_PROTOCOLS,
+       NFC_ATTR_TM_PROTOCOLS,
 /* private: internal use only */
        __NFC_ATTR_AFTER_LAST
 };
@@ -118,6 +128,7 @@ enum nfc_attrs {
 #define NFC_NFCID1_MAXSIZE 10
 #define NFC_SENSB_RES_MAXSIZE 12
 #define NFC_SENSF_RES_MAXSIZE 18
+#define NFC_GB_MAXSIZE        48
 
 /* NFC protocols */
 #define NFC_PROTO_JEWEL                1
@@ -135,6 +146,7 @@ enum nfc_attrs {
 /* NFC RF modes */
 #define NFC_RF_INITIATOR 0
 #define NFC_RF_TARGET    1
+#define NFC_RF_NONE      2
 
 /* NFC protocols masks used in bitsets */
 #define NFC_PROTO_JEWEL_MASK   (1 << NFC_PROTO_JEWEL)
index a6959f72745e1583525dc8c70565757123389915..c0fc5d2773388fd2083f1d2b977b1088f67b2018 100644 (file)
  *     %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
  *     %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
  *     %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ *     The channel to use can be set on the interface or be given using the
+ *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
  * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
  * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
  * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
  *     NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
  *
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *     (for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
+ *
  * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
  *     has been changed and provides details of the request information
  *     that caused the change such as who initiated the regulatory request
  *     the frame.
  * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
  *     backward compatibility.
+ *
+ * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
+ * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
+ *
  * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
  *     is used to configure connection quality monitoring notification trigger
  *     levels.
@@ -769,6 +781,13 @@ enum nl80211_commands {
  *     section 7.3.2.25.1, e.g. 0x000FAC04)
  * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
  *     CCMP keys, each six bytes in little endian
+ * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key
+ * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the
+ *     default management key
+ * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or
+ *     other commands, indicates which pairwise cipher suites are used
+ * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or
+ *     other commands, indicates which group cipher suite is used
  *
  * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
  * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
@@ -1004,6 +1023,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *     acknowledged by the recipient.
  *
+ * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
+ *
  * @NL80211_ATTR_CQM: connection quality monitor configuration in a
  *     nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
  *
@@ -1061,7 +1082,7 @@ enum nl80211_commands {
  *     flag isn't set, the frame will be rejected. This is also used as an
  *     nl80211 capability flag.
  *
- * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16)
  *
  * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
  *     attributes, specifying what a key should be set as default as.
@@ -1085,10 +1106,10 @@ enum nl80211_commands {
  *     indicate which WoW triggers should be enabled. This is also
  *     used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
  *     triggers.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
  *     cycles, in msecs.
-
+ *
  * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
  *     sets of attributes to match during scheduled scans.  Only BSSs
  *     that match any of the sets will be reported.  These are
@@ -1115,7 +1136,7 @@ enum nl80211_commands {
  *     are managed in software: interfaces of these types aren't subject to
  *     any restrictions in their number or combinations.
  *
- * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information
  *     necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
  *
  * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
@@ -1182,7 +1203,6 @@ enum nl80211_commands {
  * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
  *     &enum nl80211_feature_flags and is advertised in wiphy information.
  * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
- *
  *     requests while operating in AP-mode.
  *     This attribute holds a bitmap of the supported protocols for
  *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
@@ -1520,6 +1540,11 @@ enum nl80211_attrs {
 #define NL80211_MAX_NR_CIPHER_SUITES           5
 #define NL80211_MAX_NR_AKM_SUITES              2
 
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME     10
+
+/* default RSSI threshold for scan results if none specified. */
+#define NL80211_SCAN_RSSI_THOLD_OFF            -300
+
 /**
  * enum nl80211_iftype - (virtual) interface types
  *
@@ -1952,6 +1977,8 @@ enum nl80211_reg_rule_attr {
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
  * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+ *     BSS in scan results. Filtering is turned off if not specified.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *     attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -1959,7 +1986,8 @@ enum nl80211_reg_rule_attr {
 enum nl80211_sched_scan_match_attr {
        __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
 
-       NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+       NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
 
        /* keep last */
        __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -1967,6 +1995,9 @@ enum nl80211_sched_scan_match_attr {
                __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
 };
 
+/* only for backward compatibility */
+#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID
+
 /**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
@@ -2086,78 +2117,91 @@ enum nl80211_mntr_flags {
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
+ *     millisecond units, used by the Peer Link Open message
  *
  * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
- * millisecond units, used by the peer link management to close a peer link
+ *     millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
+ *     millisecond units
  *
  * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
+ *     on this mesh interface
  *
  * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
- * open retries that can be sent to establish a new peer link instance in a
- * mesh
+ *     open retries that can be sent to establish a new peer link instance in a
+ *     mesh
  *
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
- * point.
+ *     point.
  *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ *     open peer links when we detect compatible mesh peers.
  *
  * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
- * containing a PREQ that an MP can send to a particular destination (path
- * target)
+ *     containing a PREQ that an MP can send to a particular destination (path
+ *     target)
  *
  * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
- * (in milliseconds)
+ *     (in milliseconds)
  *
  * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
+ *     until giving up on a path discovery (in milliseconds)
  *
  * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
- * points receiving a PREQ shall consider the forwarding information from the
- * root to be valid. (TU = time unit)
+ *     points receiving a PREQ shall consider the forwarding information from
+ *     the root to be valid. (TU = time unit)
  *
  * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which an MP can send only one action frame containing a PREQ
- * reference element
+ *     TUs) during which an MP can send only one action frame containing a PREQ
+ *     reference element
  *
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
- * that it takes for an HWMP information element to propagate across the mesh
+ *     that it takes for an HWMP information element to propagate across the
+ *     mesh
  *
  * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
  *
  * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
+ *     source mesh point for path selection elements.
  *
  * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
- * root announcements are transmitted.
+ *     root announcements are transmitted.
  *
  * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
- * access to a broader network beyond the MBSS.  This is done via Root
- * Announcement frames.
+ *     access to a broader network beyond the MBSS.  This is done via Root
+ *     Announcement frames.
  *
  * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which a mesh STA can send only one Action frame containing a
- * PERR element.
+ *     TUs) during which a mesh STA can send only one Action frame containing a
+ *     PERR element.
  *
  * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
- * or forwarding entity (default is TRUE - forwarding entity)
+ *     or forwarding entity (default is TRUE - forwarding entity)
  *
  * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
- * threshold for average signal strength of candidate station to establish
- * a peer link.
- *
- * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *     threshold for average signal strength of candidate station to establish
+ *     a peer link.
  *
  * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
- * to synchronize to for 11s default synchronization method (see 11C.12.2.2)
+ *     to synchronize to for 11s default synchronization method
+ *     (see 11C.12.2.2)
  *
  * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
  *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for
+ *     which mesh STAs receiving a proactive PREQ shall consider the forwarding
+ *     information to the root mesh STA to be valid.
+ *
+ * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between
+ *     proactive PREQs are transmitted.
+ *
+ * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time
+ *     (in TUs) during which a mesh STA can send only one Action frame
+ *     containing a PREQ element for root path confirmation.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2184,6 +2228,9 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_RSSI_THRESHOLD,
        NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
        NL80211_MESHCONF_HT_OPMODE,
+       NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+       NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+       NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2199,34 +2246,36 @@ enum nl80211_meshconf_params {
  * @__NL80211_MESH_SETUP_INVALID: Internal use
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
- * vendor specific path selection algorithm or disable it to use the default
- * HWMP.
+ *     vendor specific path selection algorithm or disable it to use the
+ *     default HWMP.
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
- * vendor specific path metric or disable it to use the default Airtime
- * metric.
+ *     vendor specific path metric or disable it to use the default Airtime
+ *     metric.
  *
  * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
- * robust security network ie, or a vendor specific information element that
- * vendors will use to identify the path selection methods and metrics in use.
+ *     robust security network ie, or a vendor specific information element
+ *     that vendors will use to identify the path selection methods and
+ *     metrics in use.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
- * daemon will be authenticating mesh candidates.
+ *     daemon will be authenticating mesh candidates.
  *
  * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
- * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
- * Peering Management (MPM) and is implemented with the assistance of a
- * userspace daemon.  When this flag is set, the kernel will send peer
- * management frames to a userspace daemon that will implement AMPE
- * functionality (security capabilities selection, key confirmation, and key
- * management).  When the flag is unset (default), the kernel can autonomously
- * complete (unsecured) mesh peering without the need of a userspace daemon.
- *
- * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *     daemon will be securing peer link frames.  AMPE is a secured version of
+ *     Mesh Peering Management (MPM) and is implemented with the assistance of
+ *     a userspace daemon.  When this flag is set, the kernel will send peer
+ *     management frames to a userspace daemon that will implement AMPE
+ *     functionality (security capabilities selection, key confirmation, and
+ *     key management).  When the flag is unset (default), the kernel can
+ *     autonomously complete (unsecured) mesh peering without the need of a
+ *     userspace daemon.
  *
  * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a
- * vendor specific synchronization method or disable it to use the default
- * neighbor offset synchronization
+ *     vendor specific synchronization method or disable it to use the default
+ *     neighbor offset synchronization
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
  *
  * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
  */
@@ -2496,6 +2545,11 @@ enum nl80211_band {
        NL80211_BAND_5GHZ,
 };
 
+/**
+ * enum nl80211_ps_state - powersave state
+ * @NL80211_PS_DISABLED: powersave is disabled
+ * @NL80211_PS_ENABLED: powersave is enabled
+ */
 enum nl80211_ps_state {
        NL80211_PS_DISABLED,
        NL80211_PS_ENABLED,
@@ -2534,10 +2588,14 @@ enum nl80211_attr_cqm {
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ *     (Note that deauth/disassoc will still follow if the AP is not
+ *     available. This event might get used as roaming event, etc.)
  */
 enum nl80211_cqm_rssi_threshold_event {
        NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
        NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+       NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
 };
 
 
index bc14bd738ade2f456af80dfc94bdc259b4ceb5aa..bb674c02f3060c3917763dfe2bae1f8bd3559a4d 100644 (file)
@@ -243,6 +243,7 @@ struct ssb_bus_ops {
 #define SSB_DEV_MINI_MACPHY    0x823
 #define SSB_DEV_ARM_1176       0x824
 #define SSB_DEV_ARM_7TDMI      0x825
+#define SSB_DEV_ARM_CM3                0x82A
 
 /* Vendor-ID values */
 #define SSB_VENDOR_BROADCOM    0x4243
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644 (file)
index 0000000..6a76e0a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only 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.
+*/
+
+#ifndef __A2MP_H
+#define __A2MP_H
+
+#include <net/bluetooth/l2cap.h>
+
+#define A2MP_FEAT_EXT  0x8000
+
+struct amp_mgr {
+       struct l2cap_conn       *l2cap_conn;
+       struct l2cap_chan       *a2mp_chan;
+       struct kref             kref;
+       __u8                    ident;
+       __u8                    handle;
+       unsigned long           flags;
+};
+
+struct a2mp_cmd {
+       __u8    code;
+       __u8    ident;
+       __le16  len;
+       __u8    data[0];
+} __packed;
+
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+       __le16  reason;
+       __u8    data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+       __le16  mtu;
+       __le16  ext_feat;
+} __packed;
+
+struct a2mp_cl {
+       __u8    id;
+       __u8    type;
+       __u8    status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+       __le16     mtu;
+       __le16     ext_feat;
+       struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+       __u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+       __u8    id;
+       __u8    status;
+       __le32  total_bw;
+       __le32  max_bw;
+       __le32  min_latency;
+       __le16  pal_cap;
+       __le16  assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+       __u8    id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+       __u8    id;
+       __u8    status;
+       __u8    amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+       __u8    local_id;
+       __u8    remote_id;
+       __u8    amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+       __u8    local_id;
+       __u8    remote_id;
+       __u8    status;
+} __packed;
+
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS                    0x00
+#define A2MP_STATUS_INVALID_CTRL_ID            0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS    0x02
+#define A2MP_STATUS_COLLISION_OCCURED          0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD          0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS           0x05
+#define A2MP_STATUS_SECURITY_VIOLATION         0x06
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+                                      struct sk_buff *skb);
+
+#endif /* __A2MP_H */
index 961669b648fddd259cc65b9f0771d5158b6f5917..565d4bee1e493bbaa145f5e3621bc27e4295727f 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL 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 
+   CLAIM, OR ANY SPECIAL 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.
 
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 #ifndef __BLUETOOTH_H
 #define __BLUETOOTH_H
 
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#include <linux/list.h>
 #include <linux/poll.h>
 #include <net/sock.h>
 
@@ -168,8 +165,8 @@ typedef struct {
 #define BDADDR_LE_PUBLIC       0x01
 #define BDADDR_LE_RANDOM       0x02
 
-#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
 
 /* Copy, swap, convert BD Address */
 static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
@@ -215,7 +212,7 @@ int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                                struct msghdr *msg, size_t len, int flags);
 int  bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *msg, size_t len, int flags);
-uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
 int  bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 int  bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
 
@@ -225,12 +222,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
 struct l2cap_ctrl {
-       unsigned int    sframe  : 1,
-                       poll    : 1,
-                       final   : 1,
-                       fcs     : 1,
-                       sar     : 2,
-                       super   : 2;
+       unsigned int    sframe:1,
+                       poll:1,
+                       final:1,
+                       fcs:1,
+                       sar:2,
+                       super:2;
        __u16           reqseq;
        __u16           txseq;
        __u8            retries;
@@ -249,7 +246,8 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
 {
        struct sk_buff *skb;
 
-       if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
+       skb = alloc_skb(len + BT_SKB_RESERVE, how);
+       if (skb) {
                skb_reserve(skb, BT_SKB_RESERVE);
                bt_cb(skb)->incoming  = 0;
        }
@@ -261,7 +259,8 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
 {
        struct sk_buff *skb;
 
-       if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
+       skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
+       if (skb) {
                skb_reserve(skb, BT_SKB_RESERVE);
                bt_cb(skb)->incoming  = 0;
        }
index 3def64ba77fa0100bd62f0072cc6989e0f403f3f..2a6b0b8b71201dac383ee058a9df6f7f595a150e 100644 (file)
@@ -30,6 +30,9 @@
 #define HCI_MAX_EVENT_SIZE     260
 #define HCI_MAX_FRAME_SIZE     (HCI_MAX_ACL_SIZE + 4)
 
+#define HCI_LINK_KEY_SIZE      16
+#define HCI_AMP_LINK_KEY_SIZE  (2 * HCI_LINK_KEY_SIZE)
+
 /* HCI dev events */
 #define HCI_DEV_REG                    1
 #define HCI_DEV_UNREG                  2
 #define HCI_BREDR      0x00
 #define HCI_AMP                0x01
 
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID   0
+
 /* HCI device quirks */
 enum {
-       HCI_QUIRK_NO_RESET,
+       HCI_QUIRK_RESET_ON_CLOSE,
        HCI_QUIRK_RAW_DEVICE,
        HCI_QUIRK_FIXUP_BUFFER_SIZE
 };
@@ -133,10 +139,8 @@ enum {
 #define HCIINQUIRY     _IOR('H', 240, int)
 
 /* HCI timeouts */
-#define HCI_CONNECT_TIMEOUT    (40000) /* 40 seconds */
 #define HCI_DISCONN_TIMEOUT    (2000)  /* 2 seconds */
 #define HCI_PAIRING_TIMEOUT    (60000) /* 60 seconds */
-#define HCI_IDLE_TIMEOUT       (6000)  /* 6 seconds */
 #define HCI_INIT_TIMEOUT       (10000) /* 10 seconds */
 #define HCI_CMD_TIMEOUT                (1000)  /* 1 seconds */
 #define HCI_ACL_TX_TIMEOUT     (45000) /* 45 seconds */
@@ -371,7 +375,7 @@ struct hci_cp_reject_conn_req {
 #define HCI_OP_LINK_KEY_REPLY          0x040b
 struct hci_cp_link_key_reply {
        bdaddr_t bdaddr;
-       __u8     link_key[16];
+       __u8     link_key[HCI_LINK_KEY_SIZE];
 } __packed;
 
 #define HCI_OP_LINK_KEY_NEG_REPLY      0x040c
@@ -523,6 +527,28 @@ struct hci_cp_io_capability_neg_reply {
        __u8     reason;
 } __packed;
 
+#define HCI_OP_CREATE_PHY_LINK         0x0435
+struct hci_cp_create_phy_link {
+       __u8     phy_handle;
+       __u8     key_len;
+       __u8     key_type;
+       __u8     key[HCI_AMP_LINK_KEY_SIZE];
+} __packed;
+
+#define HCI_OP_ACCEPT_PHY_LINK         0x0436
+struct hci_cp_accept_phy_link {
+       __u8     phy_handle;
+       __u8     key_len;
+       __u8     key_type;
+       __u8     key[HCI_AMP_LINK_KEY_SIZE];
+} __packed;
+
+#define HCI_OP_DISCONN_PHY_LINK        0x0437
+struct hci_cp_disconn_phy_link {
+       __u8     phy_handle;
+       __u8     reason;
+} __packed;
+
 #define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
@@ -818,6 +844,31 @@ struct hci_rp_read_local_amp_info {
        __le32   be_flush_to;
 } __packed;
 
+#define HCI_OP_READ_LOCAL_AMP_ASSOC    0x140a
+struct hci_cp_read_local_amp_assoc {
+       __u8     phy_handle;
+       __le16   len_so_far;
+       __le16   max_len;
+} __packed;
+struct hci_rp_read_local_amp_assoc {
+       __u8     status;
+       __u8     phy_handle;
+       __le16   rem_len;
+       __u8     frag[0];
+} __packed;
+
+#define HCI_OP_WRITE_REMOTE_AMP_ASSOC  0x140b
+struct hci_cp_write_remote_amp_assoc {
+       __u8     phy_handle;
+       __le16   len_so_far;
+       __le16   rem_len;
+       __u8     frag[0];
+} __packed;
+struct hci_rp_write_remote_amp_assoc {
+       __u8     status;
+       __u8     phy_handle;
+} __packed;
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
@@ -1048,7 +1099,7 @@ struct hci_ev_link_key_req {
 #define HCI_EV_LINK_KEY_NOTIFY         0x18
 struct hci_ev_link_key_notify {
        bdaddr_t bdaddr;
-       __u8     link_key[16];
+       __u8     link_key[HCI_LINK_KEY_SIZE];
        __u8     key_type;
 } __packed;
 
@@ -1196,6 +1247,39 @@ struct hci_ev_le_meta {
        __u8     subevent;
 } __packed;
 
+#define HCI_EV_PHY_LINK_COMPLETE       0x40
+struct hci_ev_phy_link_complete {
+       __u8     status;
+       __u8     phy_handle;
+} __packed;
+
+#define HCI_EV_CHANNEL_SELECTED                0x41
+struct hci_ev_channel_selected {
+       __u8     phy_handle;
+} __packed;
+
+#define HCI_EV_DISCONN_PHY_LINK_COMPLETE       0x42
+struct hci_ev_disconn_phy_link_complete {
+       __u8     status;
+       __u8     phy_handle;
+       __u8     reason;
+} __packed;
+
+#define HCI_EV_LOGICAL_LINK_COMPLETE           0x45
+struct hci_ev_logical_link_complete {
+       __u8     status;
+       __le16   handle;
+       __u8     phy_handle;
+       __u8     flow_spec_id;
+} __packed;
+
+#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE   0x46
+struct hci_ev_disconn_logical_link_complete {
+       __u8     status;
+       __le16   handle;
+       __u8     reason;
+} __packed;
+
 #define HCI_EV_NUM_COMP_BLOCKS         0x48
 struct hci_comp_blocks_info {
        __le16   handle;
@@ -1296,7 +1380,6 @@ struct hci_sco_hdr {
        __u8    dlen;
 } __packed;
 
-#include <linux/skbuff.h>
 static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
 {
        return (struct hci_event_hdr *) skb->data;
@@ -1313,12 +1396,12 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 }
 
 /* Command opcode pack/unpack */
-#define hci_opcode_pack(ogf, ocf)      (__u16) ((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_pack(ogf, ocf)      ((__u16) ((ocf & 0x03ff)|(ogf << 10)))
 #define hci_opcode_ogf(op)             (op >> 10)
 #define hci_opcode_ocf(op)             (op & 0x03ff)
 
 /* ACL handle and flags pack/unpack */
-#define hci_handle_pack(h, f)  (__u16) ((h & 0x0fff)|(f << 12))
+#define hci_handle_pack(h, f)  ((__u16) ((h & 0x0fff)|(f << 12)))
 #define hci_handle(h)          (h & 0x0fff)
 #define hci_flags(h)           (h >> 12)
 
index 9fc7728f94e4af3adaaed5944b5c665823363fc4..20fd57367ddcd90f4b3d7027d45af275a860cb41 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
-#include <linux/interrupt.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI priority */
@@ -65,7 +64,7 @@ struct discovery_state {
                DISCOVERY_RESOLVING,
                DISCOVERY_STOPPING,
        } state;
-       struct list_head        all;            /* All devices found during inquiry */
+       struct list_head        all;    /* All devices found during inquiry */
        struct list_head        unknown;        /* Name state not known */
        struct list_head        resolve;        /* Name needs to be resolved */
        __u32                   timestamp;
@@ -105,7 +104,7 @@ struct link_key {
        struct list_head list;
        bdaddr_t bdaddr;
        u8 type;
-       u8 val[16];
+       u8 val[HCI_LINK_KEY_SIZE];
        u8 pin_len;
 };
 
@@ -333,6 +332,7 @@ struct hci_conn {
        void            *l2cap_data;
        void            *sco_data;
        void            *smp_conn;
+       struct amp_mgr  *amp_mgr;
 
        struct hci_conn *link;
 
@@ -360,7 +360,8 @@ extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
 extern int l2cap_disconn_ind(struct hci_conn *hcon);
 extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
 extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
-extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
+extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
+                             u16 flags);
 
 extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
 extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
@@ -429,8 +430,8 @@ enum {
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
-       return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
-                               test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
+       return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+              test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
 }
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -640,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
        dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+       uint8_t count = 0;
+       struct list_head *p;
+
+       list_for_each(p, &hci_dev_list) {
+               count++;
+       }
+
+       return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
@@ -661,7 +675,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
 int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
 int hci_inquiry(void __user *arg);
 
-struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
+                                        bdaddr_t *bdaddr);
 int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
index 1c7d1cd5e679fa1c6e4d94d29300d56807214f82..d80e3f0691b4982c38043dfd84d345ba2121a8cb 100644 (file)
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
-#define L2CAP_LE_DEFAULT_MTU           23
 #define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
 #define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 #define L2CAP_BREDR_MAX_PAYLOAD                1019    /* 3-DH5 packet */
+#define L2CAP_LE_MIN_MTU               23
 
 #define L2CAP_DISC_TIMEOUT             msecs_to_jiffies(100)
 #define L2CAP_DISC_REJ_TIMEOUT         msecs_to_jiffies(5000)
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT             msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT             msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU         670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
        sa_family_t     l2_family;
@@ -229,9 +231,14 @@ struct l2cap_conn_rsp {
        __le16     status;
 } __packed;
 
+/* protocol/service multiplexer (PSM) */
+#define L2CAP_PSM_SDP          0x0001
+#define L2CAP_PSM_RFCOMM       0x0003
+
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING    0x0001
 #define L2CAP_CID_CONN_LESS    0x0002
+#define L2CAP_CID_A2MP         0x0003
 #define L2CAP_CID_LE_DATA      0x0004
 #define L2CAP_CID_LE_SIGNALING 0x0005
 #define L2CAP_CID_SMP          0x0006
@@ -271,6 +278,9 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_PENDING     0x0004
 #define L2CAP_CONF_EFS_REJECT  0x0005
 
+/* configuration req/rsp continuation flag */
+#define L2CAP_CONF_FLAG_CONTINUATION   0x0001
+
 struct l2cap_conf_opt {
        __u8       type;
        __u8       len;
@@ -419,11 +429,6 @@ struct l2cap_seq_list {
 #define L2CAP_SEQ_LIST_CLEAR   0xFFFF
 #define L2CAP_SEQ_LIST_TAIL    0x8000
 
-struct srej_list {
-       __u16   tx_seq;
-       struct list_head list;
-};
-
 struct l2cap_chan {
        struct sock *sk;
 
@@ -475,14 +480,12 @@ struct l2cap_chan {
        __u16           expected_ack_seq;
        __u16           expected_tx_seq;
        __u16           buffer_seq;
-       __u16           buffer_seq_srej;
        __u16           srej_save_reqseq;
        __u16           last_acked_seq;
        __u16           frames_sent;
        __u16           unacked_frames;
        __u8            retry_count;
        __u16           srej_queue_next;
-       __u8            num_acked;
        __u16           sdu_len;
        struct sk_buff  *sdu;
        struct sk_buff  *sdu_last_frag;
@@ -515,7 +518,6 @@ struct l2cap_chan {
        struct sk_buff_head     srej_q;
        struct l2cap_seq_list   srej_list;
        struct l2cap_seq_list   retrans_list;
-       struct list_head        srej_l;
 
        struct list_head        list;
        struct list_head        global_l;
@@ -528,10 +530,14 @@ struct l2cap_chan {
 struct l2cap_ops {
        char                    *name;
 
-       struct l2cap_chan       *(*new_connection) (void *data);
-       int                     (*recv) (void *data, struct sk_buff *skb);
-       void                    (*close) (void *data);
-       void                    (*state_change) (void *data, int state);
+       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
+       int                     (*recv) (struct l2cap_chan * chan,
+                                        struct sk_buff *skb);
+       void                    (*teardown) (struct l2cap_chan *chan, int err);
+       void                    (*close) (struct l2cap_chan *chan);
+       void                    (*state_change) (struct l2cap_chan *chan,
+                                                int state);
+       void                    (*ready) (struct l2cap_chan *chan);
        struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
                                               unsigned long len, int nb);
 };
@@ -575,6 +581,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW                 1
 #define L2CAP_CHAN_CONN_LESS           2
 #define L2CAP_CHAN_CONN_ORIENTED       3
+#define L2CAP_CHAN_CONN_FIX_A2MP       4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
@@ -597,6 +604,7 @@ enum {
        CONF_EWS_RECV,
        CONF_LOC_CONF_PEND,
        CONF_REM_CONF_PEND,
+       CONF_NOT_COMPLETE,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -713,11 +721,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
-#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
-               msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
 #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
-#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
-               msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
 #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
 #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
                msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
@@ -736,173 +740,17 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
        return (seq + 1) % (chan->tx_win_max + 1);
 }
 
-static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
-{
-       int sub;
-
-       sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
-
-       if (sub < 0)
-               sub += 64;
-
-       return sub == ch->remote_tx_win;
-}
-
-static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
-                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
-}
-
-static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
-                                                       L2CAP_EXT_CTRL_REQSEQ;
-       else
-               return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+       return NULL;
 }
 
-static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
-                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
 }
 
-static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
-                                                       L2CAP_EXT_CTRL_TXSEQ;
-       else
-               return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
-}
-
-static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
-       else
-               return ctrl & L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u32 __set_sframe(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_FRAME_TYPE;
-       else
-               return L2CAP_CTRL_FRAME_TYPE;
-}
-
-static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
-}
-
-static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
-       else
-               return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
-}
-
-static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
-{
-       return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
-}
-
-static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_SAR;
-       else
-               return L2CAP_CTRL_SAR;
-}
-
-static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
-                                               L2CAP_EXT_CTRL_SUPER_SHIFT;
-       else
-               return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
-}
-
-static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
-                                               L2CAP_EXT_CTRL_SUPERVISE;
-       else
-               return (super << L2CAP_CTRL_SUPER_SHIFT) &
-                                                       L2CAP_CTRL_SUPERVISE;
-}
-
-static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_FINAL;
-       else
-               return L2CAP_CTRL_FINAL;
-}
-
-static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_FINAL;
-       else
-               return ctrl & L2CAP_CTRL_FINAL;
-}
-
-static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_CTRL_POLL;
-       else
-               return L2CAP_CTRL_POLL;
-}
-
-static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return ctrl & L2CAP_EXT_CTRL_POLL;
-       else
-               return ctrl & L2CAP_CTRL_POLL;
-}
-
-static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return get_unaligned_le32(p);
-       else
-               return get_unaligned_le16(p);
-}
-
-static inline void __put_control(struct l2cap_chan *chan, __u32 control,
-                                                               void *p)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return put_unaligned_le32(control, p);
-       else
-               return put_unaligned_le16(control, p);
-}
-
-static inline __u8 __ctrl_size(struct l2cap_chan *chan)
-{
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
-       else
-               return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
 }
 
 extern bool disable_ertm;
@@ -926,5 +774,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
index 0289d4ce70706be603059b2ea9fdd63d57aa019e..061c01957e54bae76f1bd7e2ba6bd33ca0916576 100644 (file)
@@ -404,6 +404,8 @@ struct cfg80211_beacon_data {
  *
  * Used to configure an AP interface.
  *
+ * @channel: the channel to start the AP on
+ * @channel_type: the channel type to use
  * @beacon: beacon data
  * @beacon_interval: beacon interval
  * @dtim_period: DTIM period
@@ -417,6 +419,9 @@ struct cfg80211_beacon_data {
  * @inactivity_timeout: time in seconds to determine station's inactivity.
  */
 struct cfg80211_ap_settings {
+       struct ieee80211_channel *channel;
+       enum nl80211_channel_type channel_type;
+
        struct cfg80211_beacon_data beacon;
 
        int beacon_interval, dtim_period;
@@ -622,10 +627,10 @@ struct sta_bss_parameters {
  * @llid: mesh local link id
  * @plid: mesh peer link id
  * @plink_state: mesh peer link state
- * @signal: the signal strength, type depends on the wiphy's signal_type
      NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
- * @signal_avg: avg signal strength, type depends on the wiphy's signal_type
      NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal: The signal strength, type depends on the wiphy's signal_type.
*     For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
*     For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
  * @txrate: current unicast bitrate from this station
  * @rxrate: current unicast bitrate to this station
  * @rx_packets: packets received from this station
@@ -785,47 +790,101 @@ struct bss_parameters {
        int ht_opmode;
 };
 
-/*
+/**
  * struct mesh_config - 802.11s mesh configuration
  *
  * These parameters can be changed while the mesh is active.
+ *
+ * @dot11MeshRetryTimeout: the initial retry timeout in millisecond units used
+ *     by the Mesh Peering Open message
+ * @dot11MeshConfirmTimeout: the initial retry timeout in millisecond units
+ *     used by the Mesh Peering Open message
+ * @dot11MeshHoldingTimeout: the confirm timeout in millisecond units used by
+ *     the mesh peering management to close a mesh peering
+ * @dot11MeshMaxPeerLinks: the maximum number of peer links allowed on this
+ *     mesh interface
+ * @dot11MeshMaxRetries: the maximum number of peer link open retries that can
+ *     be sent to establish a new peer link instance in a mesh
+ * @dot11MeshTTL: the value of TTL field set at a source mesh STA
+ * @element_ttl: the value of TTL field set at a mesh STA for path selection
+ *     elements
+ * @auto_open_plinks: whether we should automatically open peer links when we
+ *     detect compatible mesh peers
+ * @dot11MeshNbrOffsetMaxNeighbor: the maximum number of neighbors to
+ *     synchronize to for 11s default synchronization method
+ * @dot11MeshHWMPmaxPREQretries: the number of action frames containing a PREQ
+ *     that an originator mesh STA can send to a particular path target
+ * @path_refresh_time: how frequently to refresh mesh paths in milliseconds
+ * @min_discovery_timeout: the minimum length of time to wait until giving up on
+ *     a path discovery in milliseconds
+ * @dot11MeshHWMPactivePathTimeout: the time (in TUs) for which mesh STAs
+ *     receiving a PREQ shall consider the forwarding information from the
+ *     root to be valid. (TU = time unit)
+ * @dot11MeshHWMPpreqMinInterval: the minimum interval of time (in TUs) during
+ *     which a mesh STA can send only one action frame containing a PREQ
+ *     element
+ * @dot11MeshHWMPperrMinInterval: the minimum interval of time (in TUs) during
+ *     which a mesh STA can send only one Action frame containing a PERR
+ *     element
+ * @dot11MeshHWMPnetDiameterTraversalTime: the interval of time (in TUs) that
+ *     it takes for an HWMP information element to propagate across the mesh
+ * @dot11MeshHWMPRootMode: the configuration of a mesh STA as root mesh STA
+ * @dot11MeshHWMPRannInterval: the interval of time (in TUs) between root
+ *     announcements are transmitted
+ * @dot11MeshGateAnnouncementProtocol: whether to advertise that this mesh
+ *     station has access to a broader network beyond the MBSS. (This is
+ *     missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol set to true
+ *     only means that the station will announce others it's a mesh gate, but
+ *     not necessarily using the gate announcement protocol. Still keeping the
+ *     same nomenclature to be in sync with the spec)
+ * @dot11MeshForwarding: whether the Mesh STA is forwarding or non-forwarding
+ *     entity (default is TRUE - forwarding entity)
+ * @rssi_threshold: the threshold for average signal strength of candidate
+ *     station to establish a peer link
+ * @ht_opmode: mesh HT protection mode
+ *
+ * @dot11MeshHWMPactivePathToRootTimeout: The time (in TUs) for which mesh STAs
+ *     receiving a proactive PREQ shall consider the forwarding information to
+ *     the root mesh STA to be valid.
+ *
+ * @dot11MeshHWMProotInterval: The interval of time (in TUs) between proactive
+ *     PREQs are transmitted.
+ * @dot11MeshHWMPconfirmationInterval: The minimum interval of time (in TUs)
+ *     during which a mesh STA can send only one Action frame containing
+ *     a PREQ element for root path confirmation.
  */
 struct mesh_config {
-       /* Timeouts in ms */
-       /* Mesh plink management parameters */
        u16 dot11MeshRetryTimeout;
        u16 dot11MeshConfirmTimeout;
        u16 dot11MeshHoldingTimeout;
        u16 dot11MeshMaxPeerLinks;
-       u8  dot11MeshMaxRetries;
-       u8  dot11MeshTTL;
-       /* ttl used in path selection information elements */
-       u8  element_ttl;
+       u8 dot11MeshMaxRetries;
+       u8 dot11MeshTTL;
+       u8 element_ttl;
        bool auto_open_plinks;
-       /* neighbor offset synchronization */
        u32 dot11MeshNbrOffsetMaxNeighbor;
-       /* HWMP parameters */
-       u8  dot11MeshHWMPmaxPREQretries;
+       u8 dot11MeshHWMPmaxPREQretries;
        u32 path_refresh_time;
        u16 min_discovery_timeout;
        u32 dot11MeshHWMPactivePathTimeout;
        u16 dot11MeshHWMPpreqMinInterval;
        u16 dot11MeshHWMPperrMinInterval;
        u16 dot11MeshHWMPnetDiameterTraversalTime;
-       u8  dot11MeshHWMPRootMode;
+       u8 dot11MeshHWMPRootMode;
        u16 dot11MeshHWMPRannInterval;
-       /* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
-        * set to true only means that the station will announce others it's a
-        * mesh gate, but not necessarily using the gate announcement protocol.
-        * Still keeping the same nomenclature to be in sync with the spec. */
-       bool  dot11MeshGateAnnouncementProtocol;
+       bool dot11MeshGateAnnouncementProtocol;
        bool dot11MeshForwarding;
        s32 rssi_threshold;
        u16 ht_opmode;
+       u32 dot11MeshHWMPactivePathToRootTimeout;
+       u16 dot11MeshHWMProotInterval;
+       u16 dot11MeshHWMPconfirmationInterval;
 };
 
 /**
  * struct mesh_setup - 802.11s mesh setup configuration
+ * @channel: the channel to start the mesh network on
+ * @channel_type: the channel type to use
  * @mesh_id: the mesh ID
  * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
  * @sync_method: which synchronization method to use
@@ -840,6 +899,8 @@ struct mesh_config {
  * These parameters are fixed when the mesh is created.
  */
 struct mesh_setup {
+       struct ieee80211_channel *channel;
+       enum nl80211_channel_type channel_type;
        const u8 *mesh_id;
        u8 mesh_id_len;
        u8 sync_method;
@@ -966,6 +1027,7 @@ struct cfg80211_match_set {
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @channels: channels to scan
+ * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
  */
 struct cfg80211_sched_scan_request {
        struct cfg80211_ssid *ssids;
@@ -976,6 +1038,7 @@ struct cfg80211_sched_scan_request {
        size_t ie_len;
        struct cfg80211_match_set *match_sets;
        int n_match_sets;
+       s32 rssi_thold;
 
        /* internal */
        struct wiphy *wiphy;
@@ -1411,11 +1474,14 @@ struct cfg80211_gtk_rekey_data {
  *
  * @set_txq_params: Set TX queue parameters
  *
- * @set_channel: Set channel for a given wireless interface. Some devices
- *     may support multi-channel operation (by channel hopping) so cfg80211
- *     doesn't verify much. Note, however, that the passed netdev may be
- *     %NULL as well if the user requested changing the channel for the
- *     device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ *     as it doesn't implement join_mesh and needs to set the channel to
+ *     join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ *     interfaces are active this callback should reject the configuration.
+ *     If no interfaces are active or the device is down, the channel should
+ *     be stored for when a monitor interface becomes active.
  * @get_channel: Get the current operating channel, should return %NULL if
  *     there's no single defined operating channel if for example the
  *     device implements channel hopping for multi-channel virtual interfaces.
@@ -1605,9 +1671,13 @@ struct cfg80211_ops {
        int     (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
                                  struct ieee80211_txq_params *params);
 
-       int     (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
-                              struct ieee80211_channel *chan,
-                              enum nl80211_channel_type channel_type);
+       int     (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+                                            struct net_device *dev,
+                                            struct ieee80211_channel *chan);
+
+       int     (*set_monitor_channel)(struct wiphy *wiphy,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type);
 
        int     (*scan)(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request);
@@ -2263,7 +2333,10 @@ struct cfg80211_cached_keys;
  * @netdev: (private) Used to reference back to the netdev
  * @current_bss: (private) Used by the internal configuration code
  * @channel: (private) Used by the internal configuration code to track
- *     user-set AP, monitor and WDS channels for wireless extensions
+ *     the user-set AP, monitor and WDS channel
+ * @preset_chan: (private) Used by the internal configuration code to
+ *     track the channel to be used for AP later
+ * @preset_chantype: (private) the corresponding channel type
  * @bssid: (private) Used by the internal configuration code
  * @ssid: (private) Used by the internal configuration code
  * @ssid_len: (private) Used by the internal configuration code
@@ -2313,7 +2386,8 @@ struct wireless_dev {
        spinlock_t event_lock;
 
        struct cfg80211_internal_bss *current_bss; /* associated / joined */
-       struct ieee80211_channel *channel;
+       struct ieee80211_channel *preset_chan;
+       enum nl80211_channel_type preset_chantype;
 
        bool ps;
        int ps_timeout;
@@ -3359,11 +3433,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
                                 int freq, int sig_dbm, gfp_t gfp);
 
-/*
+/**
  * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
  * @wiphy: the wiphy
  * @chan: main channel
  * @channel_type: HT mode
+ *
+ * This function returns true if there is no secondary channel or the secondary
+ * channel can be used for beaconing (i.e. is not a radar channel etc.)
  */
 bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
                                  struct ieee80211_channel *chan,
index 95e39b6a02ec924ab1229e728ddb4bd45ff3d682..670a58ba8a41a52d832b7237cc552ef631177f2a 100644 (file)
@@ -1297,6 +1297,10 @@ enum ieee80211_hw_flags {
  *     reports, by default it is set to _MCS, _GI and _BW but doesn't
  *     include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
  *     adding _BW is supported today.
+ *
+ * @netdev_features: netdev features to be set in each netdev created
+ *     from this HW. Note only HW checksum features are currently
+ *     compatible with mac80211. Other feature bits will be rejected.
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
@@ -1319,6 +1323,7 @@ struct ieee80211_hw {
        u8 max_tx_aggregation_subframes;
        u8 offchannel_tx_hw_queue;
        u8 radiotap_mcs_details;
+       netdev_features_t netdev_features;
 };
 
 /**
@@ -2183,7 +2188,10 @@ enum ieee80211_rate_control_changed {
  *     offload. Frames to transmit on the off-channel channel are transmitted
  *     normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
  *     duration (which will always be non-zero) expires, the driver must call
- *     ieee80211_remain_on_channel_expired(). This callback may sleep.
+ *     ieee80211_remain_on_channel_expired().
+ *     Note that this callback may be called while the device is in IDLE and
+ *     must be accepted in this case.
+ *     This callback may sleep.
  * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
  *     aborted before it expires. This callback may sleep.
  *
@@ -2246,6 +2254,9 @@ enum ieee80211_rate_control_changed {
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  *     and perhaps other supported types of ethtool data-sets.
  *
+ * @get_rssi: Get current signal strength in dBm, the function is optional
+ *     and can sleep.
+ *
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -2385,6 +2396,8 @@ struct ieee80211_ops {
        void    (*get_et_strings)(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  u32 sset, u8 *data);
+       int     (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta, s8 *rssi_dbm);
 };
 
 /**
@@ -3556,16 +3569,6 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp);
 
-/**
- * ieee80211_get_operstate - get the operstate of the vif
- *
- * @vif: &struct ieee80211_vif pointer from the add_interface callback.
- *
- * The driver might need to know the operstate of the net_device
- * (specifically, whether the link is IF_OPER_UP after resume)
- */
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif);
-
 /**
  * ieee80211_chswitch_done - Complete channel switch process
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
index 4467c9460857a5d18e3d6dde187875a05b1c4586..e30e6a869714886c3d8be91d67f2d5c870250bc9 100644 (file)
@@ -31,7 +31,8 @@ struct nfc_hci_ops {
        void (*close) (struct nfc_hci_dev *hdev);
        int (*hci_ready) (struct nfc_hci_dev *hdev);
        int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
-       int (*start_poll) (struct nfc_hci_dev *hdev, u32 protocols);
+       int (*start_poll) (struct nfc_hci_dev *hdev,
+                          u32 im_protocols, u32 tm_protocols);
        int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
                                 struct nfc_target *target);
        int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
index b7ca4a2a1d727f2b4738772d52f55d047b40fafc..180964b954abb5ecaf21810d9f2b99d091b612d7 100644 (file)
@@ -53,7 +53,8 @@ struct nfc_target;
 struct nfc_ops {
        int (*dev_up)(struct nfc_dev *dev);
        int (*dev_down)(struct nfc_dev *dev);
-       int (*start_poll)(struct nfc_dev *dev, u32 protocols);
+       int (*start_poll)(struct nfc_dev *dev,
+                         u32 im_protocols, u32 tm_protocols);
        void (*stop_poll)(struct nfc_dev *dev);
        int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target,
                           u8 comm_mode, u8 *gb, size_t gb_len);
@@ -62,9 +63,10 @@ struct nfc_ops {
                               u32 protocol);
        void (*deactivate_target)(struct nfc_dev *dev,
                                  struct nfc_target *target);
-       int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target,
+       int (*im_transceive)(struct nfc_dev *dev, struct nfc_target *target,
                             struct sk_buff *skb, data_exchange_cb_t cb,
                             void *cb_context);
+       int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
 };
 
@@ -99,10 +101,10 @@ struct nfc_dev {
        int targets_generation;
        struct device dev;
        bool dev_up;
+       u8 rf_mode;
        bool polling;
        struct nfc_target *active_target;
        bool dep_link_up;
-       u32 dep_rf_mode;
        struct nfc_genl_data genl_data;
        u32 supported_protocols;
 
@@ -188,6 +190,7 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp);
 
 int nfc_set_remote_general_bytes(struct nfc_dev *dev,
                                 u8 *gt, u8 gt_len);
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len);
 
 int nfc_targets_found(struct nfc_dev *dev,
                      struct nfc_target *targets, int ntargets);
@@ -196,4 +199,9 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);
 int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
                       u8 comm_mode, u8 rf_mode);
 
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+                    u8 *gb, size_t gb_len);
+int nfc_tm_deactivated(struct nfc_dev *dev);
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb);
+
 #endif /* __NET_NFC_H */
index ab06afd462daf4eb5fb3270cc4ba096ece3f41f9..35e930d2f638e2a43146af66d3b0d6c9d4f2371f 100644 (file)
@@ -27,7 +27,8 @@ struct nfc_shdlc_ops {
        void (*close) (struct nfc_shdlc *shdlc);
        int (*hci_ready) (struct nfc_shdlc *shdlc);
        int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb);
-       int (*start_poll) (struct nfc_shdlc *shdlc, u32 protocols);
+       int (*start_poll) (struct nfc_shdlc *shdlc,
+                          u32 im_protocols, u32 tm_protocols);
        int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate,
                                 struct nfc_target *target);
        int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,
index 2dc5a5700f533191558381d8bcc0b16016b185a6..fa6d94a4602a8352a6f2aa9ed13ed18ff7e6c08a 100644 (file)
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)   += cmtp/
 obj-$(CONFIG_BT_HIDP)  += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-       hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+       hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+       a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644 (file)
index 0000000..fb93250
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only 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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
+
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+       struct a2mp_cmd *cmd;
+       int plen;
+
+       plen = sizeof(*cmd) + len;
+       cmd = kzalloc(plen, GFP_KERNEL);
+       if (!cmd)
+               return NULL;
+
+       cmd->code = code;
+       cmd->ident = ident;
+       cmd->len = cpu_to_le16(len);
+
+       memcpy(cmd->data, data, len);
+
+       return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+                     void *data)
+{
+       struct l2cap_chan *chan = mgr->a2mp_chan;
+       struct a2mp_cmd *cmd;
+       u16 total_len = len + sizeof(*cmd);
+       struct kvec iv;
+       struct msghdr msg;
+
+       cmd = __a2mp_build(code, ident, len, data);
+       if (!cmd)
+               return;
+
+       iv.iov_base = cmd;
+       iv.iov_len = total_len;
+
+       memset(&msg, 0, sizeof(msg));
+
+       msg.msg_iov = (struct iovec *) &iv;
+       msg.msg_iovlen = 1;
+
+       l2cap_chan_send(chan, &msg, total_len, 0);
+
+       kfree(cmd);
+}
+
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+       cl->id = 0;
+       cl->type = 0;
+       cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+       int i = 0;
+       struct hci_dev *hdev;
+
+       __a2mp_cl_bredr(cl);
+
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               /* Iterate through AMP controllers */
+               if (hdev->id == HCI_BREDR_ID)
+                       continue;
+
+               /* Starting from second entry */
+               if (++i >= num_ctrl)
+                       return;
+
+               cl[i].id = hdev->id;
+               cl[i].type = hdev->amp_type;
+               cl[i].status = hdev->amp_status;
+       }
+}
+
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_cmd_rej *rej = (void *) skb->data;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*rej))
+               return -EINVAL;
+
+       BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+       skb_pull(skb, sizeof(*rej));
+
+       return 0;
+}
+
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                            struct a2mp_cmd *hdr)
+{
+       struct a2mp_discov_req *req = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct a2mp_discov_rsp *rsp;
+       u16 ext_feat;
+       u8 num_ctrl;
+
+       if (len < sizeof(*req))
+               return -EINVAL;
+
+       skb_pull(skb, sizeof(*req));
+
+       ext_feat = le16_to_cpu(req->ext_feat);
+
+       BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+       /* check that packet is not broken for now */
+       while (ext_feat & A2MP_FEAT_EXT) {
+               if (len < sizeof(ext_feat))
+                       return -EINVAL;
+
+               ext_feat = get_unaligned_le16(skb->data);
+               BT_DBG("efm 0x%4.4x", ext_feat);
+               len -= sizeof(ext_feat);
+               skb_pull(skb, sizeof(ext_feat));
+       }
+
+       read_lock(&hci_dev_list_lock);
+
+       num_ctrl = __hci_num_ctrl();
+       len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+       rsp = kmalloc(len, GFP_ATOMIC);
+       if (!rsp) {
+               read_unlock(&hci_dev_list_lock);
+               return -ENOMEM;
+       }
+
+       rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+       rsp->ext_feat = 0;
+
+       __a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+       read_unlock(&hci_dev_list_lock);
+
+       a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+       kfree(rsp);
+       return 0;
+}
+
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+                             struct a2mp_cmd *hdr)
+{
+       struct a2mp_cl *cl = (void *) skb->data;
+
+       while (skb->len >= sizeof(*cl)) {
+               BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+                      cl->status);
+               cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+       }
+
+       /* TODO send A2MP_CHANGE_RSP */
+
+       return 0;
+}
+
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_info_req *req  = (void *) skb->data;
+       struct a2mp_info_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("id %d", req->id);
+
+       rsp.id = req->id;
+       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+       hdev = hci_dev_get(req->id);
+       if (hdev && hdev->amp_type != HCI_BREDR) {
+               rsp.status = 0;
+               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       }
+
+       if (hdev)
+               hci_dev_put(hdev);
+
+       a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                               struct a2mp_cmd *hdr)
+{
+       struct a2mp_amp_assoc_req *req = (void *) skb->data;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("id %d", req->id);
+
+       hdev = hci_dev_get(req->id);
+       if (!hdev || hdev->amp_type == HCI_BREDR) {
+               struct a2mp_amp_assoc_rsp rsp;
+               rsp.id = req->id;
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+                         &rsp);
+               goto clean;
+       }
+
+       /* Placeholder for HCI Read AMP Assoc */
+
+clean:
+       if (hdev)
+               hci_dev_put(hdev);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                                  struct a2mp_cmd *hdr)
+{
+       struct a2mp_physlink_req *req = (void *) skb->data;
+
+       struct a2mp_physlink_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+       rsp.local_id = req->remote_id;
+       rsp.remote_id = req->local_id;
+
+       hdev = hci_dev_get(req->remote_id);
+       if (!hdev || hdev->amp_type != HCI_AMP) {
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               goto send_rsp;
+       }
+
+       /* TODO process physlink create */
+
+       rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+       if (hdev)
+               hci_dev_put(hdev);
+
+       a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+                 &rsp);
+
+       skb_pull(skb, le16_to_cpu(hdr->len));
+       return 0;
+}
+
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+                                struct a2mp_cmd *hdr)
+{
+       struct a2mp_physlink_req *req = (void *) skb->data;
+       struct a2mp_physlink_rsp rsp;
+       struct hci_dev *hdev;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*req))
+               return -EINVAL;
+
+       BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+       rsp.local_id = req->remote_id;
+       rsp.remote_id = req->local_id;
+       rsp.status = A2MP_STATUS_SUCCESS;
+
+       hdev = hci_dev_get(req->local_id);
+       if (!hdev) {
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               goto send_rsp;
+       }
+
+       /* TODO Disconnect Phys Link here */
+
+       hci_dev_put(hdev);
+
+send_rsp:
+       a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+       skb_pull(skb, sizeof(*req));
+       return 0;
+}
+
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                              struct a2mp_cmd *hdr)
+{
+       BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+       skb_pull(skb, le16_to_cpu(hdr->len));
+       return 0;
+}
+
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       struct a2mp_cmd *hdr = (void *) skb->data;
+       struct amp_mgr *mgr = chan->data;
+       int err = 0;
+
+       amp_mgr_get(mgr);
+
+       while (skb->len >= sizeof(*hdr)) {
+               struct a2mp_cmd *hdr = (void *) skb->data;
+               u16 len = le16_to_cpu(hdr->len);
+
+               BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+               skb_pull(skb, sizeof(*hdr));
+
+               if (len > skb->len || !hdr->ident) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               mgr->ident = hdr->ident;
+
+               switch (hdr->code) {
+               case A2MP_COMMAND_REJ:
+                       a2mp_command_rej(mgr, skb, hdr);
+                       break;
+
+               case A2MP_DISCOVER_REQ:
+                       err = a2mp_discover_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_NOTIFY:
+                       err = a2mp_change_notify(mgr, skb, hdr);
+                       break;
+
+               case A2MP_GETINFO_REQ:
+                       err = a2mp_getinfo_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_GETAMPASSOC_REQ:
+                       err = a2mp_getampassoc_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CREATEPHYSLINK_REQ:
+                       err = a2mp_createphyslink_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_DISCONNPHYSLINK_REQ:
+                       err = a2mp_discphyslink_req(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_RSP:
+               case A2MP_DISCOVER_RSP:
+               case A2MP_GETINFO_RSP:
+               case A2MP_GETAMPASSOC_RSP:
+               case A2MP_CREATEPHYSLINK_RSP:
+               case A2MP_DISCONNPHYSLINK_RSP:
+                       err = a2mp_cmd_rsp(mgr, skb, hdr);
+                       break;
+
+               default:
+                       BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+                       err = -EINVAL;
+                       break;
+               }
+       }
+
+       if (err) {
+               struct a2mp_cmd_rej rej;
+               rej.reason = __constant_cpu_to_le16(0);
+
+               BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+               a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+                         &rej);
+       }
+
+       /* Always free skb and return success error code to prevent
+          from sending L2CAP Disconnect over A2MP channel */
+       kfree_skb(skb);
+
+       amp_mgr_put(mgr);
+
+       return 0;
+}
+
+static void a2mp_chan_close_cb(struct l2cap_chan *chan)
+{
+       l2cap_chan_destroy(chan);
+}
+
+static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
+{
+       struct amp_mgr *mgr = chan->data;
+
+       if (!mgr)
+               return;
+
+       BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+       chan->state = state;
+
+       switch (state) {
+       case BT_CLOSED:
+               if (mgr)
+                       amp_mgr_put(mgr);
+               break;
+       }
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+                                             unsigned long len, int nb)
+{
+       return bt_skb_alloc(len, GFP_KERNEL);
+}
+
+static struct l2cap_ops a2mp_chan_ops = {
+       .name = "L2CAP A2MP channel",
+       .recv = a2mp_chan_recv_cb,
+       .close = a2mp_chan_close_cb,
+       .state_change = a2mp_chan_state_change_cb,
+       .alloc_skb = a2mp_chan_alloc_skb_cb,
+
+       /* Not implemented for A2MP */
+       .new_connection = l2cap_chan_no_new_connection,
+       .teardown = l2cap_chan_no_teardown,
+       .ready = l2cap_chan_no_ready,
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+       struct l2cap_chan *chan;
+       int err;
+
+       chan = l2cap_chan_create();
+       if (!chan)
+               return NULL;
+
+       BT_DBG("chan %p", chan);
+
+       chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
+       chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+       chan->ops = &a2mp_chan_ops;
+
+       l2cap_chan_set_defaults(chan);
+       chan->remote_max_tx = chan->max_tx;
+       chan->remote_tx_win = chan->tx_win;
+
+       chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+       chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+       skb_queue_head_init(&chan->tx_q);
+
+       chan->mode = L2CAP_MODE_ERTM;
+
+       err = l2cap_ertm_init(chan);
+       if (err < 0) {
+               l2cap_chan_del(chan, 0);
+               return NULL;
+       }
+
+       chan->conf_state = 0;
+
+       l2cap_chan_add(conn, chan);
+
+       chan->remote_mps = chan->omtu;
+       chan->mps = chan->omtu;
+
+       chan->state = BT_CONNECTED;
+
+       return chan;
+}
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+       BT_DBG("mgr %p", mgr);
+
+       kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+       struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+       BT_DBG("mgr %p", mgr);
+
+       kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+       BT_DBG("mgr %p", mgr);
+
+       return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+       struct amp_mgr *mgr;
+       struct l2cap_chan *chan;
+
+       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+       if (!mgr)
+               return NULL;
+
+       BT_DBG("conn %p mgr %p", conn, mgr);
+
+       mgr->l2cap_conn = conn;
+
+       chan = a2mp_chan_open(conn);
+       if (!chan) {
+               kfree(mgr);
+               return NULL;
+       }
+
+       mgr->a2mp_chan = chan;
+       chan->data = mgr;
+
+       conn->hcon->amp_mgr = mgr;
+
+       kref_init(&mgr->kref);
+
+       return mgr;
+}
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+                                      struct sk_buff *skb)
+{
+       struct amp_mgr *mgr;
+
+       mgr = amp_mgr_create(conn);
+       if (!mgr) {
+               BT_ERR("Could not create AMP manager");
+               return NULL;
+       }
+
+       BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+       return mgr->a2mp_chan;
+}
index 3e18af4dadc442573960b94abefed550212b9b47..f7db5792ec648d3078d047cb46d0b269a68028bf 100644 (file)
 /* Bluetooth address family and sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <net/sock.h>
 #include <asm/ioctls.h>
-#include <linux/kmod.h>
 
 #include <net/bluetooth/bluetooth.h>
 
@@ -418,7 +407,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
        return 0;
 }
 
-unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
+unsigned int bt_sock_poll(struct file *file, struct socket *sock,
+                         poll_table *wait)
 {
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
index 031d7d656754936ab6c43ae124b339a87fb8f534..4a6620bc1570901c34a1c406ffb83909c27d3348 100644 (file)
 */
 
 #include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/freezer.h>
-#include <linux/errno.h>
-#include <linux/net.h>
-#include <linux/slab.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/socket.h>
 #include <linux/file.h>
-
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -306,7 +289,7 @@ static u8 __bnep_rx_hlen[] = {
        ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
 };
 
-static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
        struct net_device *dev = s->dev;
        struct sk_buff *nskb;
@@ -404,7 +387,7 @@ static u8 __bnep_tx_types[] = {
        BNEP_COMPRESSED
 };
 
-static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
 {
        struct ethhdr *eh = (void *) skb->data;
        struct socket *sock = s->sock;
index bc4086480d97fa7586c3f8b01e07cd1c8ebbc69d..98f86f91d47c691b9e6604b73e2e8248f29921cf 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/socket.h>
-#include <linux/netdevice.h>
+#include <linux/export.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-
-#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -128,7 +120,7 @@ static void bnep_net_timeout(struct net_device *dev)
 }
 
 #ifdef CONFIG_BT_BNEP_MC_FILTER
-static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
        struct ethhdr *eh = (void *) skb->data;
 
@@ -140,7 +132,7 @@ static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
+static u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
        struct ethhdr *eh = (void *) skb->data;
        u16 proto = ntohs(eh->h_proto);
@@ -154,7 +146,7 @@ static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
        return ETH_P_802_2;
 }
 
-static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
+static int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
        u16 proto = bnep_net_eth_proto(skb);
        struct bnep_proto_filter *f = s->proto_filter;
index 180bfc45810da0217e4639dbd6d154a91a63c128..5e5f5b410e0b24f751eb158ad235fe16bfa3ee6f 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <net/sock.h>
-
 
 #include "bnep.h"
 
index 3f18a6ed9731503baf07de27d510691d8e718a98..2fcced377e503ad2e9feded38ec5609748e7d2ff 100644 (file)
 
 /* Bluetooth HCI connection handling. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -54,15 +41,15 @@ static void hci_le_connect(struct hci_conn *conn)
        conn->sec_level = BT_SECURITY_LOW;
 
        memset(&cp, 0, sizeof(cp));
-       cp.scan_interval = cpu_to_le16(0x0060);
-       cp.scan_window = cpu_to_le16(0x0030);
+       cp.scan_interval = __constant_cpu_to_le16(0x0060);
+       cp.scan_window = __constant_cpu_to_le16(0x0030);
        bacpy(&cp.peer_addr, &conn->dst);
        cp.peer_addr_type = conn->dst_type;
-       cp.conn_interval_min = cpu_to_le16(0x0028);
-       cp.conn_interval_max = cpu_to_le16(0x0038);
-       cp.supervision_timeout = cpu_to_le16(0x002a);
-       cp.min_ce_len = cpu_to_le16(0x0000);
-       cp.max_ce_len = cpu_to_le16(0x0000);
+       cp.conn_interval_min = __constant_cpu_to_le16(0x0028);
+       cp.conn_interval_max = __constant_cpu_to_le16(0x0038);
+       cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
+       cp.min_ce_len = __constant_cpu_to_le16(0x0000);
+       cp.max_ce_len = __constant_cpu_to_le16(0x0000);
 
        hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 }
@@ -99,7 +86,7 @@ void hci_acl_connect(struct hci_conn *conn)
                        cp.pscan_rep_mode = ie->data.pscan_rep_mode;
                        cp.pscan_mode     = ie->data.pscan_mode;
                        cp.clock_offset   = ie->data.clock_offset |
-                                                       cpu_to_le16(0x8000);
+                                           __constant_cpu_to_le16(0x8000);
                }
 
                memcpy(conn->dev_class, ie->data.dev_class, 3);
@@ -175,9 +162,9 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
        cp.handle   = cpu_to_le16(handle);
        cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
-       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
-       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
-       cp.max_latency    = cpu_to_le16(0xffff);
+       cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+       cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+       cp.max_latency    = __constant_cpu_to_le16(0xffff);
        cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
        cp.retrans_effort = 0xff;
 
@@ -185,7 +172,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
 }
 
 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
-                                       u16 latency, u16 to_multiplier)
+                       u16 latency, u16 to_multiplier)
 {
        struct hci_cp_le_conn_update cp;
        struct hci_dev *hdev = conn->hdev;
@@ -197,15 +184,14 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
        cp.conn_interval_max    = cpu_to_le16(max);
        cp.conn_latency         = cpu_to_le16(latency);
        cp.supervision_timeout  = cpu_to_le16(to_multiplier);
-       cp.min_ce_len           = cpu_to_le16(0x0001);
-       cp.max_ce_len           = cpu_to_le16(0x0001);
+       cp.min_ce_len           = __constant_cpu_to_le16(0x0001);
+       cp.max_ce_len           = __constant_cpu_to_le16(0x0001);
 
        hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_conn_update);
 
 void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
-                                                       __u8 ltk[16])
+                     __u8 ltk[16])
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_le_start_enc cp;
@@ -221,7 +207,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 
        hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
-EXPORT_SYMBOL(hci_le_start_enc);
 
 /* Device _must_ be locked */
 void hci_sco_setup(struct hci_conn *conn, __u8 status)
@@ -247,7 +232,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
 static void hci_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
-                                                       disc_work.work);
+                                            disc_work.work);
        __u8 reason;
 
        BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
@@ -295,9 +280,9 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
        if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
                struct hci_cp_sniff_subrate cp;
                cp.handle             = cpu_to_le16(conn->handle);
-               cp.max_latency        = cpu_to_le16(0);
-               cp.min_remote_timeout = cpu_to_le16(0);
-               cp.min_local_timeout  = cpu_to_le16(0);
+               cp.max_latency        = __constant_cpu_to_le16(0);
+               cp.min_remote_timeout = __constant_cpu_to_le16(0);
+               cp.min_local_timeout  = __constant_cpu_to_le16(0);
                hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
        }
 
@@ -306,8 +291,8 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.handle       = cpu_to_le16(conn->handle);
                cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
                cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
-               cp.attempt      = cpu_to_le16(4);
-               cp.timeout      = cpu_to_le16(1);
+               cp.attempt      = __constant_cpu_to_le16(4);
+               cp.timeout      = __constant_cpu_to_le16(1);
                hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
        }
 }
@@ -327,7 +312,7 @@ static void hci_conn_auto_accept(unsigned long arg)
        struct hci_dev *hdev = conn->hdev;
 
        hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst),
-                                                               &conn->dst);
+                    &conn->dst);
 }
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
@@ -376,7 +361,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
        INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
        setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
-                                                       (unsigned long) conn);
+                   (unsigned long) conn);
 
        atomic_set(&conn->refcnt, 0);
 
@@ -425,9 +410,11 @@ int hci_conn_del(struct hci_conn *conn)
                }
        }
 
-
        hci_chan_list_flush(conn);
 
+       if (conn->amp_mgr)
+               amp_mgr_put(conn->amp_mgr);
+
        hci_conn_hash_del(hdev, conn);
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -454,7 +441,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
        read_lock(&hci_dev_list_lock);
 
        list_for_each_entry(d, &hci_dev_list, list) {
-               if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
+               if (!test_bit(HCI_UP, &d->flags) ||
+                   test_bit(HCI_RAW, &d->flags))
                        continue;
 
                /* Simple routing:
@@ -495,6 +483,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        if (type == LE_LINK) {
                le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
                if (!le) {
+                       le = hci_conn_hash_lookup_state(hdev, LE_LINK,
+                                                       BT_CONNECT);
+                       if (le)
+                               return ERR_PTR(-EBUSY);
+
                        le = hci_conn_add(hdev, LE_LINK, dst);
                        if (!le)
                                return ERR_PTR(-ENOMEM);
@@ -545,7 +538,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        hci_conn_hold(sco);
 
        if (acl->state == BT_CONNECTED &&
-                       (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+           (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
                set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
                hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
 
@@ -560,7 +553,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
 
        return sco;
 }
-EXPORT_SYMBOL(hci_connect);
 
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
@@ -572,7 +564,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 
        return 1;
 }
-EXPORT_SYMBOL(hci_conn_check_link_mode);
 
 /* Authenticate remote device */
 static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
@@ -600,7 +591,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
                if (conn->key_type != 0xff)
                        set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
        }
@@ -618,7 +609,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 0x01;
                hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-                                                                       &cp);
+                            &cp);
        }
 }
 
@@ -648,8 +639,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
        /* An unauthenticated combination key has sufficient security for
           security level 1 and 2. */
        if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
-                       (sec_level == BT_SECURITY_MEDIUM ||
-                       sec_level == BT_SECURITY_LOW))
+           (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
                goto encrypt;
 
        /* A combination key has always sufficient security for the security
@@ -657,8 +647,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
           is generated using maximum PIN code length (16).
           For pre 2.1 units. */
        if (conn->key_type == HCI_LK_COMBINATION &&
-                       (sec_level != BT_SECURITY_HIGH ||
-                       conn->pin_length == 16))
+           (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
                goto encrypt;
 
 auth:
@@ -701,12 +690,11 @@ int hci_conn_change_link_key(struct hci_conn *conn)
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
        }
 
        return 0;
 }
-EXPORT_SYMBOL(hci_conn_change_link_key);
 
 /* Switch role */
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
@@ -752,7 +740,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
 timer:
        if (hdev->idle_timeout > 0)
                mod_timer(&conn->idle_timer,
-                       jiffies + msecs_to_jiffies(hdev->idle_timeout));
+                         jiffies + msecs_to_jiffies(hdev->idle_timeout));
 }
 
 /* Drop all connection on the device */
@@ -802,7 +790,7 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
-       register struct hci_conn *c;
+       struct hci_conn *c;
        struct hci_conn_list_req req, *cl;
        struct hci_conn_info *ci;
        struct hci_dev *hdev;
index 411ace8e647be4fad7281f6e24c847ad18b28bb8..08994ecc3b6a5e7cc168ee7cd957a38c49d2e579 100644 (file)
 
 /* Bluetooth HCI core. */
 
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/rfkill.h>
-#include <linux/timer.h>
-#include <linux/crypto.h>
-#include <net/sock.h>
+#include <linux/export.h>
+#include <linux/idr.h>
 
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/rfkill.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -65,6 +47,9 @@ DEFINE_RWLOCK(hci_dev_list_lock);
 LIST_HEAD(hci_cb_list);
 DEFINE_RWLOCK(hci_cb_list_lock);
 
+/* HCI ID Numbering */
+static DEFINE_IDA(hci_index_ida);
+
 /* ---- HCI notifications ---- */
 
 static void hci_notify(struct hci_dev *hdev, int event)
@@ -124,8 +109,9 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
 }
 
 /* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-                                       unsigned long opt, __u32 timeout)
+static int __hci_request(struct hci_dev *hdev,
+                        void (*req)(struct hci_dev *hdev, unsigned long opt),
+                        unsigned long opt, __u32 timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
        int err = 0;
@@ -166,8 +152,9 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
        return err;
 }
 
-static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-                                       unsigned long opt, __u32 timeout)
+static int hci_request(struct hci_dev *hdev,
+                      void (*req)(struct hci_dev *hdev, unsigned long opt),
+                      unsigned long opt, __u32 timeout)
 {
        int ret;
 
@@ -202,7 +189,7 @@ static void bredr_init(struct hci_dev *hdev)
        /* Mandatory initialization */
 
        /* Reset */
-       if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
                set_bit(HCI_RESET, &hdev->flags);
                hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
        }
@@ -235,7 +222,7 @@ static void bredr_init(struct hci_dev *hdev)
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
        /* Connection accept timeout ~20 secs */
-       param = cpu_to_le16(0x7d00);
+       param = __constant_cpu_to_le16(0x7d00);
        hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 
        bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -417,7 +404,8 @@ static void inquiry_cache_flush(struct hci_dev *hdev)
        INIT_LIST_HEAD(&cache->resolve);
 }
 
-struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
+                                              bdaddr_t *bdaddr)
 {
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
@@ -478,7 +466,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
 
        list_for_each_entry(p, &cache->resolve, list) {
                if (p->name_state != NAME_PENDING &&
-                               abs(p->data.rssi) >= abs(ie->data.rssi))
+                   abs(p->data.rssi) >= abs(ie->data.rssi))
                        break;
                pos = &p->list;
        }
@@ -503,7 +491,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
                        *ssp = true;
 
                if (ie->name_state == NAME_NEEDED &&
-                                               data->rssi != ie->data.rssi) {
+                   data->rssi != ie->data.rssi) {
                        ie->data.rssi = data->rssi;
                        hci_inquiry_cache_update_resolve(hdev, ie);
                }
@@ -527,7 +515,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
 update:
        if (name_known && ie->name_state != NAME_KNOWN &&
-                                       ie->name_state != NAME_PENDING) {
+           ie->name_state != NAME_PENDING) {
                ie->name_state = NAME_KNOWN;
                list_del(&ie->list);
        }
@@ -605,8 +593,7 @@ int hci_inquiry(void __user *arg)
 
        hci_dev_lock(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-                               inquiry_cache_empty(hdev) ||
-                               ir.flags & IREQ_CACHE_FLUSH) {
+           inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
                do_inquiry = 1;
        }
@@ -620,7 +607,9 @@ int hci_inquiry(void __user *arg)
                        goto done;
        }
 
-       /* for unlimited number of responses we will use buffer with 255 entries */
+       /* for unlimited number of responses we will use buffer with
+        * 255 entries
+        */
        max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
 
        /* cache_dump can't sleep. Therefore we allocate temp buffer and then
@@ -641,7 +630,7 @@ int hci_inquiry(void __user *arg)
        if (!copy_to_user(ptr, &ir, sizeof(ir))) {
                ptr += sizeof(ir);
                if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
-                                       ir.num_rsp))
+                                ir.num_rsp))
                        err = -EFAULT;
        } else
                err = -EFAULT;
@@ -702,11 +691,11 @@ int hci_dev_open(__u16 dev)
                hdev->init_last_cmd = 0;
 
                ret = __hci_request(hdev, hci_init_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                   msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                if (lmp_host_le_capable(hdev))
                        ret = __hci_request(hdev, hci_le_init_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                           msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
@@ -791,10 +780,10 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        skb_queue_purge(&hdev->cmd_q);
        atomic_set(&hdev->cmd_cnt, 1);
        if (!test_bit(HCI_RAW, &hdev->flags) &&
-                               test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+           test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
                set_bit(HCI_INIT, &hdev->flags);
                __hci_request(hdev, hci_reset_req, 0,
-                                       msecs_to_jiffies(250));
+                             msecs_to_jiffies(250));
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
@@ -884,7 +873,7 @@ int hci_dev_reset(__u16 dev)
 
        if (!test_bit(HCI_RAW, &hdev->flags))
                ret = __hci_request(hdev, hci_reset_req, 0,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                   msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
 done:
        hci_req_unlock(hdev);
@@ -924,7 +913,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
        switch (cmd) {
        case HCISETAUTH:
                err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETENCRYPT:
@@ -936,23 +925,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
                if (!test_bit(HCI_AUTH, &hdev->flags)) {
                        /* Auth must be enabled first */
                        err = hci_request(hdev, hci_auth_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                         msecs_to_jiffies(HCI_INIT_TIMEOUT));
                        if (err)
                                break;
                }
 
                err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETSCAN:
                err = hci_request(hdev, hci_scan_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKPOL:
                err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
-                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
+                                 msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETLINKMODE:
@@ -1103,7 +1092,7 @@ static void hci_power_on(struct work_struct *work)
 
        if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                schedule_delayed_work(&hdev->power_off,
-                                       msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+                                     msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
@@ -1112,7 +1101,7 @@ static void hci_power_on(struct work_struct *work)
 static void hci_power_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                                       power_off.work);
+                                           power_off.work);
 
        BT_DBG("%s", hdev->name);
 
@@ -1193,7 +1182,7 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 }
 
 static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
-                                               u8 key_type, u8 old_key_type)
+                              u8 key_type, u8 old_key_type)
 {
        /* Legacy key */
        if (key_type < 0x03)
@@ -1234,7 +1223,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
        list_for_each_entry(k, &hdev->long_term_keys, list) {
                if (k->ediv != ediv ||
-                               memcmp(rand, k->rand, sizeof(k->rand)))
+                   memcmp(rand, k->rand, sizeof(k->rand)))
                        continue;
 
                return k;
@@ -1242,7 +1231,6 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
 
        return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk);
 
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                     u8 addr_type)
@@ -1251,12 +1239,11 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
        list_for_each_entry(k, &hdev->long_term_keys, list)
                if (addr_type == k->bdaddr_type &&
-                                       bacmp(bdaddr, &k->bdaddr) == 0)
+                   bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
 
        return NULL;
 }
-EXPORT_SYMBOL(hci_find_ltk_by_addr);
 
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
@@ -1283,15 +1270,14 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
         * combination key for legacy pairing even when there's no
         * previous key */
        if (type == HCI_LK_CHANGED_COMBINATION &&
-                                       (!conn || conn->remote_auth == 0xff) &&
-                                       old_key_type == 0xff) {
+           (!conn || conn->remote_auth == 0xff) && old_key_type == 0xff) {
                type = HCI_LK_COMBINATION;
                if (conn)
                        conn->key_type = type;
        }
 
        bacpy(&key->bdaddr, bdaddr);
-       memcpy(key->val, val, 16);
+       memcpy(key->val, val, HCI_LINK_KEY_SIZE);
        key->pin_len = pin_len;
 
        if (type == HCI_LK_CHANGED_COMBINATION)
@@ -1540,6 +1526,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
 
        memset(&cp, 0, sizeof(cp));
        cp.enable = 1;
+       cp.filter_dup = 1;
 
        hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 }
@@ -1707,41 +1694,39 @@ EXPORT_SYMBOL(hci_free_dev);
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
-       struct list_head *head, *p;
        int id, error;
 
        if (!hdev->open || !hdev->close)
                return -EINVAL;
 
-       write_lock(&hci_dev_list_lock);
-
        /* Do not allow HCI_AMP devices to register at index 0,
         * so the index can be used as the AMP controller ID.
         */
-       id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-       head = &hci_dev_list;
-
-       /* Find first available device id */
-       list_for_each(p, &hci_dev_list) {
-               int nid = list_entry(p, struct hci_dev, list)->id;
-               if (nid > id)
-                       break;
-               if (nid == id)
-                       id++;
-               head = p;
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL);
+               break;
+       case HCI_AMP:
+               id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL);
+               break;
+       default:
+               return -EINVAL;
        }
 
+       if (id < 0)
+               return id;
+
        sprintf(hdev->name, "hci%d", id);
        hdev->id = id;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       list_add(&hdev->list, head);
-
+       write_lock(&hci_dev_list_lock);
+       list_add(&hdev->list, &hci_dev_list);
        write_unlock(&hci_dev_list_lock);
 
        hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
-                                                       WQ_MEM_RECLAIM, 1);
+                                         WQ_MEM_RECLAIM, 1);
        if (!hdev->workqueue) {
                error = -ENOMEM;
                goto err;
@@ -1752,7 +1737,8 @@ int hci_register_dev(struct hci_dev *hdev)
                goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
-                               RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
+                                   RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
+                                   hdev);
        if (hdev->rfkill) {
                if (rfkill_register(hdev->rfkill) < 0) {
                        rfkill_destroy(hdev->rfkill);
@@ -1772,6 +1758,7 @@ int hci_register_dev(struct hci_dev *hdev)
 err_wqueue:
        destroy_workqueue(hdev->workqueue);
 err:
+       ida_simple_remove(&hci_index_ida, hdev->id);
        write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
@@ -1783,12 +1770,14 @@ EXPORT_SYMBOL(hci_register_dev);
 /* Unregister HCI device */
 void hci_unregister_dev(struct hci_dev *hdev)
 {
-       int i;
+       int i, id;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
        set_bit(HCI_UNREGISTER, &hdev->dev_flags);
 
+       id = hdev->id;
+
        write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
@@ -1799,7 +1788,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
                kfree_skb(hdev->reassembly[i]);
 
        if (!test_bit(HCI_INIT, &hdev->flags) &&
-                               !test_bit(HCI_SETUP, &hdev->dev_flags)) {
+           !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                hci_dev_lock(hdev);
                mgmt_index_removed(hdev);
                hci_dev_unlock(hdev);
@@ -1829,6 +1818,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_unlock(hdev);
 
        hci_dev_put(hdev);
+
+       ida_simple_remove(&hci_index_ida, id);
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1853,7 +1844,7 @@ int hci_recv_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
        if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
-                               && !test_bit(HCI_INIT, &hdev->flags))) {
+                     && !test_bit(HCI_INIT, &hdev->flags))) {
                kfree_skb(skb);
                return -ENXIO;
        }
@@ -1872,7 +1863,7 @@ int hci_recv_frame(struct sk_buff *skb)
 EXPORT_SYMBOL(hci_recv_frame);
 
 static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
-                                                 int count, __u8 index)
+                         int count, __u8 index)
 {
        int len = 0;
        int hlen = 0;
@@ -1881,7 +1872,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
        struct bt_skb_cb *scb;
 
        if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
-                               index >= NUM_REASSEMBLY)
+           index >= NUM_REASSEMBLY)
                return -EILSEQ;
 
        skb = hdev->reassembly[index];
@@ -2023,7 +2014,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
                        type = bt_cb(skb)->pkt_type;
 
                rem = hci_reassembly(hdev, type, data, count,
-                                                       STREAM_REASSEMBLY);
+                                    STREAM_REASSEMBLY);
                if (rem < 0)
                        return rem;
 
@@ -2157,7 +2148,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 }
 
 static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
-                               struct sk_buff *skb, __u16 flags)
+                         struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
@@ -2216,7 +2207,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
@@ -2239,12 +2229,12 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
        skb_queue_tail(&conn->data_q, skb);
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
-EXPORT_SYMBOL(hci_send_sco);
 
 /* ---- HCI TX task (outgoing data) ---- */
 
 /* HCI Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
+                                    int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_conn *conn = NULL, *c;
@@ -2303,7 +2293,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
        return conn;
 }
 
-static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
+static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_conn *c;
@@ -2316,16 +2306,16 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
-                               hdev->name, batostr(&c->dst));
-                       hci_acl_disconn(c, 0x13);
+                              hdev->name, batostr(&c->dst));
+                       hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
                }
        }
 
        rcu_read_unlock();
 }
 
-static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
-                                               int *quote)
+static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+                                     int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        struct hci_chan *chan = NULL;
@@ -2442,7 +2432,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
                        skb->priority = HCI_PRIO_MAX - 1;
 
                        BT_DBG("chan %p skb %p promoted to %d", chan, skb,
-                                                               skb->priority);
+                              skb->priority);
                }
 
                if (hci_conn_num(hdev, type) == num)
@@ -2459,18 +2449,18 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
        return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
 }
 
-static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
+static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
 {
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
                if (!cnt && time_after(jiffies, hdev->acl_last_tx +
-                                       msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
+                                      msecs_to_jiffies(HCI_ACL_TX_TIMEOUT)))
                        hci_link_tx_to(hdev, ACL_LINK);
        }
 }
 
-static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
+static void hci_sched_acl_pkt(struct hci_dev *hdev)
 {
        unsigned int cnt = hdev->acl_cnt;
        struct hci_chan *chan;
@@ -2480,11 +2470,11 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
        __check_timeout(hdev, cnt);
 
        while (hdev->acl_cnt &&
-                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote-- && (skb = skb_peek(&chan->data_q))) {
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                       skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2508,7 +2498,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
                hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl_blk(struct hci_dev *hdev)
+static void hci_sched_acl_blk(struct hci_dev *hdev)
 {
        unsigned int cnt = hdev->block_cnt;
        struct hci_chan *chan;
@@ -2518,13 +2508,13 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
        __check_timeout(hdev, cnt);
 
        while (hdev->block_cnt > 0 &&
-                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
                        int blocks;
 
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                               skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2537,7 +2527,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
                                return;
 
                        hci_conn_enter_active_mode(chan->conn,
-                                               bt_cb(skb)->force_active);
+                                                  bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
@@ -2554,7 +2544,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
                hci_prio_recalculate(hdev, ACL_LINK);
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static void hci_sched_acl(struct hci_dev *hdev)
 {
        BT_DBG("%s", hdev->name);
 
@@ -2573,7 +2563,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 }
 
 /* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
+static void hci_sched_sco(struct hci_dev *hdev)
 {
        struct hci_conn *conn;
        struct sk_buff *skb;
@@ -2596,7 +2586,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
        }
 }
 
-static inline void hci_sched_esco(struct hci_dev *hdev)
+static void hci_sched_esco(struct hci_dev *hdev)
 {
        struct hci_conn *conn;
        struct sk_buff *skb;
@@ -2607,7 +2597,8 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
        if (!hci_conn_num(hdev, ESCO_LINK))
                return;
 
-       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
+                                                    &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
                        hci_send_frame(skb);
@@ -2619,7 +2610,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
        }
 }
 
-static inline void hci_sched_le(struct hci_dev *hdev)
+static void hci_sched_le(struct hci_dev *hdev)
 {
        struct hci_chan *chan;
        struct sk_buff *skb;
@@ -2634,7 +2625,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
                /* LE tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
                if (!hdev->le_cnt && hdev->le_pkts &&
-                               time_after(jiffies, hdev->le_last_tx + HZ * 45))
+                   time_after(jiffies, hdev->le_last_tx + HZ * 45))
                        hci_link_tx_to(hdev, LE_LINK);
        }
 
@@ -2644,7 +2635,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote-- && (skb = skb_peek(&chan->data_q))) {
                        BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
-                                       skb->len, skb->priority);
+                              skb->len, skb->priority);
 
                        /* Stop if priority has changed */
                        if (skb->priority < priority)
@@ -2676,7 +2667,7 @@ static void hci_tx_work(struct work_struct *work)
        struct sk_buff *skb;
 
        BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
-               hdev->sco_cnt, hdev->le_cnt);
+              hdev->sco_cnt, hdev->le_cnt);
 
        /* Schedule queues and send stuff to HCI driver */
 
@@ -2696,7 +2687,7 @@ static void hci_tx_work(struct work_struct *work)
 /* ----- HCI RX task (incoming data processing) ----- */
 
 /* ACL data packet */
-static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_acl_hdr *hdr = (void *) skb->data;
        struct hci_conn *conn;
@@ -2708,7 +2699,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        flags  = hci_flags(handle);
        handle = hci_handle(handle);
 
-       BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+       BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len,
+              handle, flags);
 
        hdev->stat.acl_rx++;
 
@@ -2732,14 +2724,14 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        } else {
                BT_ERR("%s ACL packet for unknown connection handle %d",
-                       hdev->name, handle);
+                      hdev->name, handle);
        }
 
        kfree_skb(skb);
 }
 
 /* SCO data packet */
-static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_sco_hdr *hdr = (void *) skb->data;
        struct hci_conn *conn;
@@ -2763,7 +2755,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        } else {
                BT_ERR("%s SCO packet for unknown connection handle %d",
-                       hdev->name, handle);
+                      hdev->name, handle);
        }
 
        kfree_skb(skb);
index 94ad124a4ea3496c4bd971b3bc4ac9d4dda8860f..1ba929c05d0da41c7c584a9166383a4f29f169da 100644 (file)
 
 /* Bluetooth HCI event handling. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
+#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -95,7 +82,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        hci_conn_check_pending(hdev);
 }
 
-static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
 {
        BT_DBG("%s", hdev->name);
 }
@@ -166,7 +154,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
 {
        struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
 
@@ -178,7 +167,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk
        hdev->link_policy = __le16_to_cpu(rp->policy);
 }
 
-static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
        void *sent;
@@ -329,7 +319,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
                if (hdev->discov_timeout > 0) {
                        int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
                        queue_delayed_work(hdev->workqueue, &hdev->discov_off,
-                                                                       to);
+                                          to);
                }
        } else if (old_iscan)
                mgmt_discoverable(hdev, 0);
@@ -358,7 +348,7 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
        memcpy(hdev->dev_class, rp->dev_class, 3);
 
        BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
-               hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+              hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
 }
 
 static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@ -406,7 +396,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
 }
 
-static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_write_voice_setting(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
        __u16 setting;
@@ -473,7 +464,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
                return 1;
 
        if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
-                                               hdev->lmp_subver == 0x0757)
+           hdev->lmp_subver == 0x0757)
                return 1;
 
        if (hdev->manufacturer == 15) {
@@ -486,7 +477,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
        }
 
        if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
-                                               hdev->lmp_subver == 0x1805)
+           hdev->lmp_subver == 0x1805)
                return 1;
 
        return 0;
@@ -566,7 +557,7 @@ static void hci_setup(struct hci_dev *hdev)
        if (hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
-       if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+       if (lmp_ssp_capable(hdev)) {
                if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
                        u8 mode = 0x01;
                        hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
@@ -618,8 +609,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
        hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
 
        BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
-                                       hdev->manufacturer,
-                                       hdev->hci_ver, hdev->hci_rev);
+              hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
 
        if (test_bit(HCI_INIT, &hdev->flags))
                hci_setup(hdev);
@@ -646,7 +636,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
        hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
 }
 
-static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_commands(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        struct hci_rp_read_local_commands *rp = (void *) skb->data;
 
@@ -664,7 +655,8 @@ done:
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
 }
 
-static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cc_read_local_features(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        struct hci_rp_read_local_features *rp = (void *) skb->data;
 
@@ -713,10 +705,10 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
                hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
 
        BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
-                                       hdev->features[0], hdev->features[1],
-                                       hdev->features[2], hdev->features[3],
-                                       hdev->features[4], hdev->features[5],
-                                       hdev->features[6], hdev->features[7]);
+              hdev->features[0], hdev->features[1],
+              hdev->features[2], hdev->features[3],
+              hdev->features[4], hdev->features[5],
+              hdev->features[6], hdev->features[7]);
 }
 
 static void hci_set_le_support(struct hci_dev *hdev)
@@ -736,7 +728,7 @@ static void hci_set_le_support(struct hci_dev *hdev)
 }
 
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                          struct sk_buff *skb)
 {
        struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
 
@@ -762,7 +754,7 @@ done:
 }
 
 static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
-                                               struct sk_buff *skb)
+                                         struct sk_buff *skb)
 {
        struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
 
@@ -798,9 +790,8 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
        hdev->acl_cnt = hdev->acl_pkts;
        hdev->sco_cnt = hdev->sco_pkts;
 
-       BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
-                                       hdev->acl_mtu, hdev->acl_pkts,
-                                       hdev->sco_mtu, hdev->sco_pkts);
+       BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
+              hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
 }
 
 static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
@@ -816,7 +807,7 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_read_data_block_size(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                       struct sk_buff *skb)
 {
        struct hci_rp_read_data_block_size *rp = (void *) skb->data;
 
@@ -832,7 +823,7 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
        hdev->block_cnt = hdev->num_blocks;
 
        BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
-                                       hdev->block_cnt, hdev->block_len);
+              hdev->block_cnt, hdev->block_len);
 
        hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
 }
@@ -847,7 +838,7 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
-               struct sk_buff *skb)
+                                      struct sk_buff *skb)
 {
        struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
 
@@ -871,7 +862,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 }
 
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                         struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
 
@@ -890,7 +881,7 @@ static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                     struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
 
@@ -900,7 +891,7 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
 }
 
 static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                        struct sk_buff *skb)
 {
        struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
 
@@ -959,7 +950,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
-                                                               rp->status);
+                                                rp->status);
 
        hci_dev_unlock(hdev);
 }
@@ -1000,7 +991,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                         struct sk_buff *skb)
 {
        struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
 
@@ -1031,7 +1022,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                         struct sk_buff *skb)
 {
        struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
 
@@ -1047,7 +1038,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 }
 
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+                                            struct sk_buff *skb)
 {
        struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 
@@ -1076,7 +1067,7 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
-                                       struct sk_buff *skb)
+                                     struct sk_buff *skb)
 {
        struct hci_cp_le_set_scan_enable *cp;
        __u8 status = *((__u8 *) skb->data);
@@ -1156,8 +1147,8 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
 }
 
-static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
+                                          struct sk_buff *skb)
 {
        struct hci_cp_write_le_host_supported *sent;
        __u8 status = *((__u8 *) skb->data);
@@ -1176,13 +1167,13 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        }
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
-                                       !test_bit(HCI_INIT, &hdev->flags))
+           !test_bit(HCI_INIT, &hdev->flags))
                mgmt_le_enable_complete(hdev, sent->le, status);
 
        hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
-static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
+static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
 
@@ -1203,7 +1194,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
+static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 {
        struct hci_cp_create_conn *cp;
        struct hci_conn *conn;
@@ -1333,7 +1324,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
 }
 
 static int hci_outgoing_auth_needed(struct hci_dev *hdev,
-                                                       struct hci_conn *conn)
+                                   struct hci_conn *conn)
 {
        if (conn->state != BT_CONFIG || !conn->out)
                return 0;
@@ -1343,15 +1334,14 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
 
        /* Only request authentication for SSP connections or non-SSP
         * devices with sec_level HIGH or if MITM protection is requested */
-       if (!hci_conn_ssp_enabled(conn) &&
-                               conn->pending_sec_level != BT_SECURITY_HIGH &&
-                               !(conn->auth_type & 0x01))
+       if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
+           conn->pending_sec_level != BT_SECURITY_HIGH)
                return 0;
 
        return 1;
 }
 
-static inline int hci_resolve_name(struct hci_dev *hdev,
+static int hci_resolve_name(struct hci_dev *hdev,
                                   struct inquiry_entry *e)
 {
        struct hci_cp_remote_name_req cp;
@@ -1638,7 +1628,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
 
        BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
-               conn);
+              conn);
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@ -1668,7 +1658,7 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
        BT_DBG("%s status 0x%x", hdev->name, status);
 }
 
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
        struct discovery_state *discov = &hdev->discovery;
@@ -1708,7 +1698,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct inquiry_data data;
        struct inquiry_info *info = (void *) (skb->data + 1);
@@ -1745,7 +1735,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -1823,18 +1813,18 @@ unlock:
        hci_conn_check_pending(hdev);
 }
 
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_conn_request *ev = (void *) skb->data;
        int mask = hdev->link_mode;
 
-       BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
-                                       batostr(&ev->bdaddr), ev->link_type);
+       BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
+              ev->link_type);
 
        mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
        if ((mask & HCI_LM_ACCEPT) &&
-                       !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
+           !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
                /* Connection accepted */
                struct inquiry_entry *ie;
                struct hci_conn *conn;
@@ -1845,7 +1835,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                if (ie)
                        memcpy(ie->data.dev_class, ev->dev_class, 3);
 
-               conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+               conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
+                                              &ev->bdaddr);
                if (!conn) {
                        conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
                        if (!conn) {
@@ -1878,9 +1869,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                        bacpy(&cp.bdaddr, &ev->bdaddr);
                        cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
-                       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
-                       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
-                       cp.max_latency    = cpu_to_le16(0xffff);
+                       cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+                       cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+                       cp.max_latency    = __constant_cpu_to_le16(0xffff);
                        cp.content_format = cpu_to_le16(hdev->voice_setting);
                        cp.retrans_effort = 0xff;
 
@@ -1897,7 +1888,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
        }
 }
 
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -1914,10 +1905,10 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
                conn->state = BT_CLOSED;
 
        if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
-                       (conn->type == ACL_LINK || conn->type == LE_LINK)) {
+           (conn->type == ACL_LINK || conn->type == LE_LINK)) {
                if (ev->status != 0)
                        mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
-                                               conn->dst_type, ev->status);
+                                              conn->dst_type, ev->status);
                else
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
                                                 conn->dst_type);
@@ -1934,7 +1925,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_auth_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -1949,7 +1940,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
        if (!ev->status) {
                if (!hci_conn_ssp_enabled(conn) &&
-                               test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
+                   test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
                        BT_INFO("re-auth of legacy device is not possible.");
                } else {
                        conn->link_mode |= HCI_LM_AUTH;
@@ -1969,7 +1960,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        cp.handle  = ev->handle;
                        cp.encrypt = 0x01;
                        hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-                                                                       &cp);
+                                    &cp);
                } else {
                        conn->state = BT_CONNECTED;
                        hci_proto_connect_cfm(conn, ev->status);
@@ -1989,7 +1980,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        cp.handle  = ev->handle;
                        cp.encrypt = 0x01;
                        hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-                                                                       &cp);
+                                    &cp);
                } else {
                        clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
                        hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -2000,7 +1991,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_remote_name *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2039,7 +2030,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_encrypt_change *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2082,7 +2073,8 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
+                                            struct sk_buff *skb)
 {
        struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2104,7 +2096,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_features_evt(struct hci_dev *hdev,
+                                   struct sk_buff *skb)
 {
        struct hci_ev_remote_features *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2128,7 +2121,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
                cp.handle = ev->handle;
                cp.page = 0x01;
                hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
                goto unlock;
        }
 
@@ -2153,17 +2146,18 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_cmd_complete *ev = (void *) skb->data;
        __u16 opcode;
@@ -2384,7 +2378,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
        }
 }
 
-static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_cmd_status *ev = (void *) skb->data;
        __u16 opcode;
@@ -2465,7 +2459,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_role_change *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2491,7 +2485,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
        int i;
@@ -2502,7 +2496,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        }
 
        if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
-                       ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
+           ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
@@ -2557,8 +2551,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
-static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
-                                          struct sk_buff *skb)
+static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
        int i;
@@ -2569,13 +2562,13 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
        }
 
        if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
-                       ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
+           ev->num_hndl * sizeof(struct hci_comp_blocks_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
 
        BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks,
-                                                               ev->num_hndl);
+              ev->num_hndl);
 
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_blocks_info *info = &ev->handles[i];
@@ -2607,7 +2600,7 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_mode_change *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2621,7 +2614,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
                conn->mode = ev->mode;
                conn->interval = __le16_to_cpu(ev->interval);
 
-               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
+               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
+                                       &conn->flags)) {
                        if (conn->mode == HCI_CM_ACTIVE)
                                set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
                        else
@@ -2635,7 +2629,7 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_pin_code_req *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2656,7 +2650,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 
        if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
                hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
-                                       sizeof(ev->bdaddr), &ev->bdaddr);
+                            sizeof(ev->bdaddr), &ev->bdaddr);
        else if (test_bit(HCI_MGMT, &hdev->dev_flags)) {
                u8 secure;
 
@@ -2672,7 +2666,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_link_key_req *ev = (void *) skb->data;
        struct hci_cp_link_key_reply cp;
@@ -2689,15 +2683,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        key = hci_find_link_key(hdev, &ev->bdaddr);
        if (!key) {
                BT_DBG("%s link key not found for %s", hdev->name,
-                                                       batostr(&ev->bdaddr));
+                      batostr(&ev->bdaddr));
                goto not_found;
        }
 
        BT_DBG("%s found key type %u for %s", hdev->name, key->type,
-                                                       batostr(&ev->bdaddr));
+              batostr(&ev->bdaddr));
 
        if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
-                               key->type == HCI_LK_DEBUG_COMBINATION) {
+           key->type == HCI_LK_DEBUG_COMBINATION) {
                BT_DBG("%s ignoring debug key", hdev->name);
                goto not_found;
        }
@@ -2705,16 +2699,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn) {
                if (key->type == HCI_LK_UNAUTH_COMBINATION &&
-                               conn->auth_type != 0xff &&
-                               (conn->auth_type & 0x01)) {
+                   conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
                        BT_DBG("%s ignoring unauthenticated key", hdev->name);
                        goto not_found;
                }
 
                if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
-                               conn->pending_sec_level == BT_SECURITY_HIGH) {
-                       BT_DBG("%s ignoring key unauthenticated for high \
-                                                       security", hdev->name);
+                   conn->pending_sec_level == BT_SECURITY_HIGH) {
+                       BT_DBG("%s ignoring key unauthenticated for high security",
+                              hdev->name);
                        goto not_found;
                }
 
@@ -2723,7 +2716,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        bacpy(&cp.bdaddr, &ev->bdaddr);
-       memcpy(cp.link_key, key->val, 16);
+       memcpy(cp.link_key, key->val, HCI_LINK_KEY_SIZE);
 
        hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
 
@@ -2736,7 +2729,7 @@ not_found:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_link_key_notify *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2760,12 +2753,12 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 
        if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
                hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
-                                                       ev->key_type, pin_len);
+                                ev->key_type, pin_len);
 
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_clock_offset *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2788,7 +2781,7 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_pkt_type_change *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2804,7 +2797,7 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
        struct inquiry_entry *ie;
@@ -2822,7 +2815,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
+                                            struct sk_buff *skb)
 {
        struct inquiry_data data;
        int num_rsp = *((__u8 *) skb->data);
@@ -2881,7 +2875,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_ext_features_evt(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
 {
        struct hci_ev_remote_ext_features *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2929,7 +2924,8 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -2984,19 +2980,20 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        BT_DBG("%s", hdev->name);
 }
 
-static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_sniff_subrate *ev = (void *) skb->data;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 }
 
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
+                                           struct sk_buff *skb)
 {
        struct inquiry_data data;
        struct extended_inquiry_info *info = (void *) (skb->data + 1);
@@ -3087,7 +3084,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline u8 hci_get_auth_req(struct hci_conn *conn)
+static u8 hci_get_auth_req(struct hci_conn *conn)
 {
        /* If remote requests dedicated bonding follow that lead */
        if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
@@ -3106,7 +3103,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
        return conn->auth_type;
 }
 
-static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_io_capa_request *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -3125,7 +3122,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                goto unlock;
 
        if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) ||
-                       (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
+           (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
                struct hci_cp_io_capability_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
@@ -3136,14 +3133,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                conn->auth_type = hci_get_auth_req(conn);
                cp.authentication = conn->auth_type;
 
-               if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
-                               hci_find_remote_oob_data(hdev, &conn->dst))
+               if (hci_find_remote_oob_data(hdev, &conn->dst) &&
+                   (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
                        cp.oob_data = 0x01;
                else
                        cp.oob_data = 0x00;
 
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
        } else {
                struct hci_cp_io_capability_neg_reply cp;
 
@@ -3151,14 +3148,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
 
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
-                                                       sizeof(cp), &cp);
+                            sizeof(cp), &cp);
        }
 
 unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_io_capa_reply *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -3180,8 +3177,8 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+static void hci_user_confirm_request_evt(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
 {
        struct hci_ev_user_confirm_req *ev = (void *) skb->data;
        int loc_mitm, rem_mitm, confirm_hint = 0;
@@ -3209,13 +3206,13 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
                BT_DBG("Rejecting request: remote device can't provide MITM");
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
-                                       sizeof(ev->bdaddr), &ev->bdaddr);
+                            sizeof(ev->bdaddr), &ev->bdaddr);
                goto unlock;
        }
 
        /* If no side requires MITM protection; auto-accept */
        if ((!loc_mitm || conn->remote_cap == 0x03) &&
-                               (!rem_mitm || conn->io_capability == 0x03)) {
+           (!rem_mitm || conn->io_capability == 0x03)) {
 
                /* If we're not the initiators request authorization to
                 * proceed from user space (mgmt_user_confirm with
@@ -3227,7 +3224,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
                }
 
                BT_DBG("Auto-accept of user confirmation with %ums delay",
-                                               hdev->auto_accept_delay);
+                      hdev->auto_accept_delay);
 
                if (hdev->auto_accept_delay > 0) {
                        int delay = msecs_to_jiffies(hdev->auto_accept_delay);
@@ -3236,7 +3233,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
                }
 
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
-                                               sizeof(ev->bdaddr), &ev->bdaddr);
+                            sizeof(ev->bdaddr), &ev->bdaddr);
                goto unlock;
        }
 
@@ -3248,8 +3245,8 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
-                                                       struct sk_buff *skb)
+static void hci_user_passkey_request_evt(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
 {
        struct hci_ev_user_passkey_req *ev = (void *) skb->data;
 
@@ -3263,7 +3260,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
 {
        struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -3291,7 +3289,8 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_remote_host_features_evt(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
 {
        struct hci_ev_remote_host_features *ev = (void *) skb->data;
        struct inquiry_entry *ie;
@@ -3307,8 +3306,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
-                                                  struct sk_buff *skb)
+static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
+                                           struct sk_buff *skb)
 {
        struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
        struct oob_data *data;
@@ -3329,20 +3328,20 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
                memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
 
                hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
-                                                                       &cp);
+                            &cp);
        } else {
                struct hci_cp_remote_oob_data_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
                hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
-                                                                       &cp);
+                            &cp);
        }
 
 unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
@@ -3351,6 +3350,19 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        hci_dev_lock(hdev);
 
+       if (ev->status) {
+               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (!conn)
+                       goto unlock;
+
+               mgmt_connect_failed(hdev, &conn->dst, conn->type,
+                                   conn->dst_type, ev->status);
+               hci_proto_connect_cfm(conn, ev->status);
+               conn->state = BT_CLOSED;
+               hci_conn_del(conn);
+               goto unlock;
+       }
+
        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
        if (!conn) {
                conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
@@ -3363,15 +3375,6 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
                conn->dst_type = ev->bdaddr_type;
        }
 
-       if (ev->status) {
-               mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
-                                               conn->dst_type, ev->status);
-               hci_proto_connect_cfm(conn, ev->status);
-               conn->state = BT_CLOSED;
-               hci_conn_del(conn);
-               goto unlock;
-       }
-
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
                                      conn->dst_type, 0, NULL, 0, NULL);
@@ -3389,8 +3392,7 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
-                                               struct sk_buff *skb)
+static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
@@ -3411,8 +3413,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
-                                               struct sk_buff *skb)
+static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_ltk_req *ev = (void *) skb->data;
        struct hci_cp_le_ltk_reply cp;
@@ -3455,7 +3456,7 @@ not_found:
        hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_meta *le_ev = (void *) skb->data;
 
index 5914623f426aa835aadee48c6ec8eb8400ab7728..a7f04de03d7916add5a20cf44d8e88e5daad495d 100644 (file)
 
 /* Bluetooth HCI sockets. */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/compat.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
+#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -113,11 +95,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                flt = &hci_pi(sk)->filter;
 
                if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
-                               0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+                             0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
+                             &flt->type_mask))
                        continue;
 
                if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
-                       register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
+                       int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 
                        if (!hci_test_bit(evt, &flt->event_mask))
                                continue;
@@ -240,7 +223,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
                        struct hci_mon_hdr *hdr;
 
                        /* Create a private copy with headroom */
-                       skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
+                       skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE,
+                                              GFP_ATOMIC);
                        if (!skb_copy)
                                continue;
 
@@ -495,7 +479,8 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 }
 
 /* Ioctls that require bound socket */
-static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
+                               unsigned long arg)
 {
        struct hci_dev *hdev = hci_pi(sk)->hdev;
 
@@ -540,7 +525,8 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
        }
 }
 
-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
 {
        struct sock *sk = sock->sk;
        void __user *argp = (void __user *) arg;
@@ -601,7 +587,8 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
        }
 }
 
-static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
+                        int addr_len)
 {
        struct sockaddr_hci haddr;
        struct sock *sk = sock->sk;
@@ -690,7 +677,8 @@ done:
        return err;
 }
 
-static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
+                           int *addr_len, int peer)
 {
        struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
        struct sock *sk = sock->sk;
@@ -711,13 +699,15 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add
        return 0;
 }
 
-static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
+                         struct sk_buff *skb)
 {
        __u32 mask = hci_pi(sk)->cmsg_mask;
 
        if (mask & HCI_CMSG_DIR) {
                int incoming = bt_cb(skb)->incoming;
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming),
+                        &incoming);
        }
 
        if (mask & HCI_CMSG_TSTAMP) {
@@ -747,7 +737,7 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 }
 
 static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-                               struct msghdr *msg, size_t len, int flags)
+                           struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -857,8 +847,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                u16 ocf = hci_opcode_ocf(opcode);
 
                if (((ogf > HCI_SFLT_MAX_OGF) ||
-                               !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-                                       !capable(CAP_NET_RAW)) {
+                    !hci_test_bit(ocf & HCI_FLT_OCF_BITS,
+                                  &hci_sec_filter.ocf_mask[ogf])) &&
+                   !capable(CAP_NET_RAW)) {
                        err = -EPERM;
                        goto drop;
                }
@@ -891,7 +882,8 @@ drop:
        goto done;
 }
 
-static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
+static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, unsigned int len)
 {
        struct hci_ufilter uf = { .opcode = 0 };
        struct sock *sk = sock->sk;
@@ -973,7 +965,8 @@ done:
        return err;
 }
 
-static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int __user *optlen)
 {
        struct hci_ufilter uf;
        struct sock *sk = sock->sk;
index 937f3187eafa51bbb540db6352535cfb4a30485e..a20e61c3653dbf84f3c567977757f61239fd2a82 100644 (file)
@@ -1,10 +1,6 @@
 /* Bluetooth HCI driver model support. */
 
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
 #include <linux/module.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -31,27 +27,30 @@ static inline char *link_typetostr(int type)
        }
 }
 
-static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_type(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", link_typetostr(conn->type));
 }
 
-static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_address(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
        return sprintf(buf, "%s\n", batostr(&conn->dst));
 }
 
-static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_link_features(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                               conn->features[0], conn->features[1],
-                               conn->features[2], conn->features[3],
-                               conn->features[4], conn->features[5],
-                               conn->features[6], conn->features[7]);
+                      conn->features[0], conn->features[1],
+                      conn->features[2], conn->features[3],
+                      conn->features[4], conn->features[5],
+                      conn->features[6], conn->features[7]);
 }
 
 #define LINK_ATTR(_name, _mode, _show, _store) \
@@ -185,19 +184,22 @@ static inline char *host_typetostr(int type)
        }
 }
 
-static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_bus(struct device *dev,
+                       struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
 }
 
-static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_type(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
 }
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        char name[HCI_MAX_NAME_LENGTH + 1];
@@ -210,55 +212,64 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
        return sprintf(buf, "%s\n", name);
 }
 
-static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_class(struct device *dev,
+                         struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
-       return sprintf(buf, "0x%.2x%.2x%.2x\n",
-                       hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+       return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
+                      hdev->dev_class[1], hdev->dev_class[0]);
 }
 
-static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_address(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
 }
 
-static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_features(struct device *dev,
+                            struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
 
        return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                               hdev->features[0], hdev->features[1],
-                               hdev->features[2], hdev->features[3],
-                               hdev->features[4], hdev->features[5],
-                               hdev->features[6], hdev->features[7]);
+                      hdev->features[0], hdev->features[1],
+                      hdev->features[2], hdev->features[3],
+                      hdev->features[4], hdev->features[5],
+                      hdev->features[6], hdev->features[7]);
 }
 
-static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_manufacturer(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->manufacturer);
 }
 
-static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_version(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_ver);
 }
 
-static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_hci_revision(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->hci_rev);
 }
 
-static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_idle_timeout(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->idle_timeout);
 }
 
-static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_idle_timeout(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        unsigned int val;
@@ -276,13 +287,16 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
        return count;
 }
 
-static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_max_interval(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_max_interval);
 }
 
-static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_max_interval(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
@@ -300,13 +314,16 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
        return count;
 }
 
-static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_sniff_min_interval(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        return sprintf(buf, "%d\n", hdev->sniff_min_interval);
 }
 
-static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_sniff_min_interval(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
        u16 val;
@@ -335,11 +352,11 @@ static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
 
 static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
-                               show_idle_timeout, store_idle_timeout);
+                  show_idle_timeout, store_idle_timeout);
 static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
-                               show_sniff_max_interval, store_sniff_max_interval);
+                  show_sniff_max_interval, store_sniff_max_interval);
 static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
-                               show_sniff_min_interval, store_sniff_min_interval);
+                  show_sniff_min_interval, store_sniff_min_interval);
 
 static struct attribute *bt_host_attrs[] = {
        &dev_attr_bus.attr,
@@ -455,8 +472,8 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
        memcpy(&data5, &uuid[14], 2);
 
        seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
-                               ntohl(data0), ntohs(data1), ntohs(data2),
-                               ntohs(data3), ntohl(data4), ntohs(data5));
+                  ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3),
+                  ntohl(data4), ntohs(data5));
 }
 
 static int uuids_show(struct seq_file *f, void *p)
@@ -513,7 +530,7 @@ static int auto_accept_delay_get(void *data, u64 *val)
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
-                                       auto_accept_delay_set, "%llu\n");
+                       auto_accept_delay_set, "%llu\n");
 
 void hci_init_sysfs(struct hci_dev *hdev)
 {
@@ -547,15 +564,15 @@ int hci_add_sysfs(struct hci_dev *hdev)
                return 0;
 
        debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
-                                               hdev, &inquiry_cache_fops);
+                           hdev, &inquiry_cache_fops);
 
        debugfs_create_file("blacklist", 0444, hdev->debugfs,
-                                               hdev, &blacklist_fops);
+                           hdev, &blacklist_fops);
 
        debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
 
        debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev,
-                                               &auto_accept_delay_fops);
+                           &auto_accept_delay_fops);
        return 0;
 }
 
index 2c20d765b394841bf878c331b4f7c69a897e6e28..ccd985da65180656d7df83a986655c4b82258220 100644 (file)
 */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/freezer.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <net/sock.h>
-
-#include <linux/input.h>
-#include <linux/hid.h>
 #include <linux/hidraw.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -244,7 +225,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 }
 
 static int __hidp_send_ctrl_message(struct hidp_session *session,
-                       unsigned char hdr, unsigned char *data, int size)
+                                   unsigned char hdr, unsigned char *data,
+                                   int size)
 {
        struct sk_buff *skb;
 
@@ -268,7 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
        return 0;
 }
 
-static inline int hidp_send_ctrl_message(struct hidp_session *session,
+static int hidp_send_ctrl_message(struct hidp_session *session,
                        unsigned char hdr, unsigned char *data, int size)
 {
        int err;
@@ -471,7 +453,7 @@ static void hidp_set_timer(struct hidp_session *session)
                mod_timer(&session->timer, jiffies + HZ * session->idle_to);
 }
 
-static inline void hidp_del_timer(struct hidp_session *session)
+static void hidp_del_timer(struct hidp_session *session)
 {
        if (session->idle_to > 0)
                del_timer(&session->timer);
index 73a32d705c1fc14f423c5178c367ee4064cd9284..18b3f6892a36847de621954cbae7358ae719c0be 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/ioctl.h>
+#include <linux/export.h>
 #include <linux/file.h>
-#include <linux/init.h>
-#include <linux/compat.h>
-#include <linux/gfp.h>
-#include <net/sock.h>
 
 #include "hidp.h"
 
index 4554e80d16a37b8ffdc0a7ac86805da2f2ee06e9..d42dfdc83ebbaa596b01f86c1e7c764393a7f567 100644 (file)
 
 #include <linux/module.h>
 
-#include <linux/types.h>
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
 #include <linux/crc16.h>
-#include <net/sock.h>
-
-#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -73,6 +55,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                   struct l2cap_chan *chan, int err);
 
+static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+                   struct sk_buff_head *skbs, u8 event);
+
 /* ---- L2CAP channels ---- */
 
 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
@@ -196,7 +181,7 @@ static void __l2cap_state_change(struct l2cap_chan *chan, int state)
                                                state_to_string(state));
 
        chan->state = state;
-       chan->ops->state_change(chan->data, state);
+       chan->ops->state_change(chan, state);
 }
 
 static void l2cap_state_change(struct l2cap_chan *chan, int state)
@@ -224,6 +209,37 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
        release_sock(sk);
 }
 
+static void __set_retrans_timer(struct l2cap_chan *chan)
+{
+       if (!delayed_work_pending(&chan->monitor_timer) &&
+           chan->retrans_timeout) {
+               l2cap_set_timer(chan, &chan->retrans_timer,
+                               msecs_to_jiffies(chan->retrans_timeout));
+       }
+}
+
+static void __set_monitor_timer(struct l2cap_chan *chan)
+{
+       __clear_retrans_timer(chan);
+       if (chan->monitor_timeout) {
+               l2cap_set_timer(chan, &chan->monitor_timer,
+                               msecs_to_jiffies(chan->monitor_timeout));
+       }
+}
+
+static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head,
+                                              u16 seq)
+{
+       struct sk_buff *skb;
+
+       skb_queue_walk(head, skb) {
+               if (bt_cb(skb)->control.txseq == seq)
+                       return skb;
+       }
+
+       return NULL;
+}
+
 /* ---- L2CAP sequence number lists ---- */
 
 /* For ERTM, ordered lists of sequence numbers must be tracked for
@@ -366,7 +382,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        mutex_unlock(&conn->chan_lock);
 
        l2cap_chan_put(chan);
@@ -392,6 +408,9 @@ struct l2cap_chan *l2cap_chan_create(void)
 
        atomic_set(&chan->refcnt, 1);
 
+       /* This flag is cleared in l2cap_chan_ready() */
+       set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
+
        BT_DBG("chan %p", chan);
 
        return chan;
@@ -430,7 +449,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        case L2CAP_CHAN_CONN_ORIENTED:
                if (conn->hcon->type == LE_LINK) {
                        /* LE connection */
-                       chan->omtu = L2CAP_LE_DEFAULT_MTU;
+                       chan->omtu = L2CAP_DEFAULT_MTU;
                        chan->scid = L2CAP_CID_LE_DATA;
                        chan->dcid = L2CAP_CID_LE_DATA;
                } else {
@@ -447,6 +466,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                chan->omtu = L2CAP_DEFAULT_MTU;
                break;
 
+       case L2CAP_CHAN_CONN_FIX_A2MP:
+               chan->scid = L2CAP_CID_A2MP;
+               chan->dcid = L2CAP_CID_A2MP;
+               chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+               chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+               break;
+
        default:
                /* Raw socket can send/recv signalling messages only */
                chan->scid = L2CAP_CID_SIGNALING;
@@ -466,18 +492,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
        mutex_lock(&conn->chan_lock);
        __l2cap_chan_add(conn, chan);
        mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
-       struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
-       struct sock *parent = bt_sk(sk)->parent;
 
        __clear_chan_timer(chan);
 
@@ -490,34 +514,22 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
                l2cap_chan_put(chan);
 
                chan->conn = NULL;
-               hci_conn_put(conn->hcon);
-       }
-
-       lock_sock(sk);
-
-       __l2cap_state_change(chan, BT_CLOSED);
-       sock_set_flag(sk, SOCK_ZAPPED);
 
-       if (err)
-               __l2cap_chan_set_err(chan, err);
-
-       if (parent) {
-               bt_accept_unlink(sk);
-               parent->sk_data_ready(parent, 0);
-       } else
-               sk->sk_state_change(sk);
+               if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
+                       hci_conn_put(conn->hcon);
+       }
 
-       release_sock(sk);
+       if (chan->ops->teardown)
+               chan->ops->teardown(chan, err);
 
-       if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
-                       test_bit(CONF_INPUT_DONE, &chan->conf_state)))
+       if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
                return;
 
-       skb_queue_purge(&chan->tx_q);
-
-       if (chan->mode == L2CAP_MODE_ERTM) {
-               struct srej_list *l, *tmp;
+       switch(chan->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
 
+       case L2CAP_MODE_ERTM:
                __clear_retrans_timer(chan);
                __clear_monitor_timer(chan);
                __clear_ack_timer(chan);
@@ -526,30 +538,15 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
                l2cap_seq_list_free(&chan->srej_list);
                l2cap_seq_list_free(&chan->retrans_list);
-               list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
-                       list_del(&l->list);
-                       kfree(l);
-               }
-       }
-}
-
-static void l2cap_chan_cleanup_listen(struct sock *parent)
-{
-       struct sock *sk;
 
-       BT_DBG("parent %p", parent);
-
-       /* Close not yet accepted channels */
-       while ((sk = bt_accept_dequeue(parent, NULL))) {
-               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
-               l2cap_chan_lock(chan);
-               __clear_chan_timer(chan);
-               l2cap_chan_close(chan, ECONNRESET);
-               l2cap_chan_unlock(chan);
+               /* fall through */
 
-               chan->ops->close(chan->data);
+       case L2CAP_MODE_STREAMING:
+               skb_queue_purge(&chan->tx_q);
+               break;
        }
+
+       return;
 }
 
 void l2cap_chan_close(struct l2cap_chan *chan, int reason)
@@ -562,12 +559,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
        switch (chan->state) {
        case BT_LISTEN:
-               lock_sock(sk);
-               l2cap_chan_cleanup_listen(sk);
-
-               __l2cap_state_change(chan, BT_CLOSED);
-               sock_set_flag(sk, SOCK_ZAPPED);
-               release_sock(sk);
+               if (chan->ops->teardown)
+                       chan->ops->teardown(chan, 0);
                break;
 
        case BT_CONNECTED:
@@ -595,7 +588,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                        rsp.scid   = cpu_to_le16(chan->dcid);
                        rsp.dcid   = cpu_to_le16(chan->scid);
                        rsp.result = cpu_to_le16(result);
-                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
                                                        sizeof(rsp), &rsp);
                }
@@ -609,9 +602,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
-               lock_sock(sk);
-               sock_set_flag(sk, SOCK_ZAPPED);
-               release_sock(sk);
+               if (chan->ops->teardown)
+                       chan->ops->teardown(chan, 0);
                break;
        }
 }
@@ -627,7 +619,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
                default:
                        return HCI_AT_NO_BONDING;
                }
-       } else if (chan->psm == cpu_to_le16(0x0001)) {
+       } else if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) {
                if (chan->sec_level == BT_SECURITY_LOW)
                        chan->sec_level = BT_SECURITY_SDP;
 
@@ -773,9 +765,11 @@ static inline void __unpack_control(struct l2cap_chan *chan,
        if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
                __unpack_extended_control(get_unaligned_le32(skb->data),
                                          &bt_cb(skb)->control);
+               skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
        } else {
                __unpack_enhanced_control(get_unaligned_le16(skb->data),
                                          &bt_cb(skb)->control);
+               skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
        }
 }
 
@@ -830,66 +824,102 @@ static inline void __pack_control(struct l2cap_chan *chan,
        }
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
+static inline unsigned int __ertm_hdr_size(struct l2cap_chan *chan)
 {
-       struct sk_buff *skb;
-       struct l2cap_hdr *lh;
-       struct l2cap_conn *conn = chan->conn;
-       int count, hlen;
-
-       if (chan->state != BT_CONNECTED)
-               return;
-
        if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               hlen = L2CAP_EXT_HDR_SIZE;
+               return L2CAP_EXT_HDR_SIZE;
        else
-               hlen = L2CAP_ENH_HDR_SIZE;
+               return L2CAP_ENH_HDR_SIZE;
+}
+
+static struct sk_buff *l2cap_create_sframe_pdu(struct l2cap_chan *chan,
+                                              u32 control)
+{
+       struct sk_buff *skb;
+       struct l2cap_hdr *lh;
+       int hlen = __ertm_hdr_size(chan);
 
        if (chan->fcs == L2CAP_FCS_CRC16)
                hlen += L2CAP_FCS_SIZE;
 
-       BT_DBG("chan %p, control 0x%8.8x", chan, control);
-
-       count = min_t(unsigned int, conn->mtu, hlen);
-
-       control |= __set_sframe(chan);
-
-       if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= __set_ctrl_final(chan);
+       skb = bt_skb_alloc(hlen, GFP_KERNEL);
 
-       if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-               control |= __set_ctrl_poll(chan);
-
-       skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
-               return;
+               return ERR_PTR(-ENOMEM);
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
 
-       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               put_unaligned_le32(control, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
+       else
+               put_unaligned_le16(control, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+               u16 fcs = crc16(0, (u8 *)skb->data, skb->len);
                put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
        }
 
        skb->priority = HCI_PRIO_MAX;
-       l2cap_do_send(chan, skb);
+       return skb;
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
+static void l2cap_send_sframe(struct l2cap_chan *chan,
+                             struct l2cap_ctrl *control)
 {
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
+       struct sk_buff *skb;
+       u32 control_field;
+
+       BT_DBG("chan %p, control %p", chan, control);
+
+       if (!control->sframe)
+               return;
+
+       if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
+           !control->poll)
+               control->final = 1;
+
+       if (control->super == L2CAP_SUPER_RR)
+               clear_bit(CONN_RNR_SENT, &chan->conn_state);
+       else if (control->super == L2CAP_SUPER_RNR)
                set_bit(CONN_RNR_SENT, &chan->conn_state);
-       } else
-               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-       control |= __set_reqseq(chan, chan->buffer_seq);
+       if (control->super != L2CAP_SUPER_SREJ) {
+               chan->last_acked_seq = control->reqseq;
+               __clear_ack_timer(chan);
+       }
+
+       BT_DBG("reqseq %d, final %d, poll %d, super %d", control->reqseq,
+              control->final, control->poll, control->super);
+
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               control_field = __pack_extended_control(control);
+       else
+               control_field = __pack_enhanced_control(control);
+
+       skb = l2cap_create_sframe_pdu(chan, control_field);
+       if (!IS_ERR(skb))
+               l2cap_do_send(chan, skb);
+}
+
+static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
+{
+       struct l2cap_ctrl control;
+
+       BT_DBG("chan %p, poll %d", chan, poll);
+
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
+       control.poll = poll;
+
+       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+               control.super = L2CAP_SUPER_RNR;
+       else
+               control.super = L2CAP_SUPER_RR;
 
-       l2cap_send_sframe(chan, control);
+       control.reqseq = chan->buffer_seq;
+       l2cap_send_sframe(chan, &control);
 }
 
 static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
@@ -914,25 +944,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
 
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
-       struct sock *sk = chan->sk;
-       struct sock *parent;
-
-       lock_sock(sk);
-
-       parent = bt_sk(sk)->parent;
-
-       BT_DBG("sk %p, parent %p", sk, parent);
-
+       /* This clears all conf flags, including CONF_NOT_COMPLETE */
        chan->conf_state = 0;
        __clear_chan_timer(chan);
 
-       __l2cap_state_change(chan, BT_CONNECTED);
-       sk->sk_state_change(sk);
-
-       if (parent)
-               parent->sk_data_ready(parent, 0);
+       chan->state = BT_CONNECTED;
 
-       release_sock(sk);
+       chan->ops->ready(chan);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
@@ -953,7 +971,7 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                        l2cap_send_conn_req(chan);
        } else {
                struct l2cap_info_req req;
-               req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+               req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
 
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
@@ -995,6 +1013,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
                __clear_ack_timer(chan);
        }
 
+       if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+               __l2cap_state_change(chan, BT_DISCONN);
+               return;
+       }
+
        req.dcid = cpu_to_le16(chan->dcid);
        req.scid = cpu_to_le16(chan->scid);
        l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@ -1053,20 +1076,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
                                        struct sock *parent = bt_sk(sk)->parent;
-                                       rsp.result = cpu_to_le16(L2CAP_CR_PEND);
-                                       rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
+                                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
+                                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
                                        if (parent)
                                                parent->sk_data_ready(parent, 0);
 
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
-                                       rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-                                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+                                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                                }
                                release_sock(sk);
                        } else {
-                               rsp.result = cpu_to_le16(L2CAP_CR_PEND);
-                               rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
+                               rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
+                               rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
                        }
 
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
@@ -1150,13 +1173,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        lock_sock(parent);
 
-       /* Check for backlog size */
-       if (sk_acceptq_is_full(parent)) {
-               BT_DBG("backlog full %d", parent->sk_ack_backlog);
-               goto clean;
-       }
-
-       chan = pchan->ops->new_connection(pchan->data);
+       chan = pchan->ops->new_connection(pchan);
        if (!chan)
                goto clean;
 
@@ -1171,10 +1188,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        l2cap_chan_add(conn, chan);
 
-       __set_chan_timer(chan, sk->sk_sndtimeo);
-
-       __l2cap_state_change(chan, BT_CONNECTED);
-       parent->sk_data_ready(parent, 0);
+       l2cap_chan_ready(chan);
 
 clean:
        release_sock(parent);
@@ -1198,6 +1212,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
                l2cap_chan_lock(chan);
 
+               if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+                       l2cap_chan_unlock(chan);
+                       continue;
+               }
+
                if (conn->hcon->type == LE_LINK) {
                        if (smp_conn_security(conn, chan->sec_level))
                                l2cap_chan_ready(chan);
@@ -1270,7 +1289,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
                l2cap_chan_unlock(chan);
 
-               chan->ops->close(chan->data);
+               chan->ops->close(chan);
                l2cap_chan_put(chan);
        }
 
@@ -1444,21 +1463,17 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                goto done;
        }
 
-       lock_sock(sk);
-
-       switch (sk->sk_state) {
+       switch (chan->state) {
        case BT_CONNECT:
        case BT_CONNECT2:
        case BT_CONFIG:
                /* Already connecting */
                err = 0;
-               release_sock(sk);
                goto done;
 
        case BT_CONNECTED:
                /* Already connected */
                err = -EISCONN;
-               release_sock(sk);
                goto done;
 
        case BT_OPEN:
@@ -1468,13 +1483,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
        default:
                err = -EBADFD;
-               release_sock(sk);
                goto done;
        }
 
        /* Set destination address and psm */
+       lock_sock(sk);
        bacpy(&bt_sk(sk)->dst, dst);
-
        release_sock(sk);
 
        chan->psm = psm;
@@ -1576,23 +1590,20 @@ int __l2cap_wait_ack(struct sock *sk)
 static void l2cap_monitor_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-                                                       monitor_timer.work);
+                                              monitor_timer.work);
 
        BT_DBG("chan %p", chan);
 
        l2cap_chan_lock(chan);
 
-       if (chan->retry_count >= chan->remote_max_tx) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
+       if (!chan->conn) {
                l2cap_chan_unlock(chan);
                l2cap_chan_put(chan);
                return;
        }
 
-       chan->retry_count++;
-       __set_monitor_timer(chan);
+       l2cap_tx(chan, NULL, NULL, L2CAP_EV_MONITOR_TO);
 
-       l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
        l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
 }
@@ -1600,234 +1611,293 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 static void l2cap_retrans_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-                                                       retrans_timer.work);
+                                              retrans_timer.work);
 
        BT_DBG("chan %p", chan);
 
        l2cap_chan_lock(chan);
 
-       chan->retry_count = 1;
-       __set_monitor_timer(chan);
-
-       set_bit(CONN_WAIT_F, &chan->conn_state);
-
-       l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
+       if (!chan->conn) {
+               l2cap_chan_unlock(chan);
+               l2cap_chan_put(chan);
+               return;
+       }
 
+       l2cap_tx(chan, NULL, NULL, L2CAP_EV_RETRANS_TO);
        l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
 }
 
-static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
+static void l2cap_streaming_send(struct l2cap_chan *chan,
+                                struct sk_buff_head *skbs)
 {
        struct sk_buff *skb;
+       struct l2cap_ctrl *control;
 
-       while ((skb = skb_peek(&chan->tx_q)) &&
-                       chan->unacked_frames) {
-               if (bt_cb(skb)->control.txseq == chan->expected_ack_seq)
-                       break;
+       BT_DBG("chan %p, skbs %p", chan, skbs);
 
-               skb = skb_dequeue(&chan->tx_q);
-               kfree_skb(skb);
+       skb_queue_splice_tail_init(skbs, &chan->tx_q);
 
-               chan->unacked_frames--;
-       }
+       while (!skb_queue_empty(&chan->tx_q)) {
 
-       if (!chan->unacked_frames)
-               __clear_retrans_timer(chan);
-}
+               skb = skb_dequeue(&chan->tx_q);
 
-static void l2cap_streaming_send(struct l2cap_chan *chan)
-{
-       struct sk_buff *skb;
-       u32 control;
-       u16 fcs;
+               bt_cb(skb)->control.retries = 1;
+               control = &bt_cb(skb)->control;
 
-       while ((skb = skb_dequeue(&chan->tx_q))) {
-               control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
-               control |= __set_txseq(chan, chan->next_tx_seq);
-               control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
-               __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
+               control->reqseq = 0;
+               control->txseq = chan->next_tx_seq;
+
+               __pack_control(chan, control, skb);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data,
-                                               skb->len - L2CAP_FCS_SIZE);
-                       put_unaligned_le16(fcs,
-                                       skb->data + skb->len - L2CAP_FCS_SIZE);
+                       u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
+                       put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
                }
 
                l2cap_do_send(chan, skb);
 
+               BT_DBG("Sent txseq %d", (int)control->txseq);
+
                chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
+               chan->frames_sent++;
        }
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
+static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 fcs;
-       u32 control;
+       struct l2cap_ctrl *control;
+       int sent = 0;
 
-       skb = skb_peek(&chan->tx_q);
-       if (!skb)
-               return;
+       BT_DBG("chan %p", chan);
 
-       while (bt_cb(skb)->control.txseq != tx_seq) {
-               if (skb_queue_is_last(&chan->tx_q, skb))
-                       return;
+       if (chan->state != BT_CONNECTED)
+               return -ENOTCONN;
 
-               skb = skb_queue_next(&chan->tx_q, skb);
-       }
+       if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
+               return 0;
 
-       if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
-           chan->remote_max_tx) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-               return;
-       }
+       while (chan->tx_send_head &&
+              chan->unacked_frames < chan->remote_tx_win &&
+              chan->tx_state == L2CAP_TX_STATE_XMIT) {
 
-       tx_skb = skb_clone(skb, GFP_ATOMIC);
-       bt_cb(skb)->control.retries++;
+               skb = chan->tx_send_head;
 
-       control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
-       control &= __get_sar_mask(chan);
+               bt_cb(skb)->control.retries = 1;
+               control = &bt_cb(skb)->control;
 
-       if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= __set_ctrl_final(chan);
+               if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
+                       control->final = 1;
 
-       control |= __set_reqseq(chan, chan->buffer_seq);
-       control |= __set_txseq(chan, tx_seq);
+               control->reqseq = chan->buffer_seq;
+               chan->last_acked_seq = chan->buffer_seq;
+               control->txseq = chan->next_tx_seq;
 
-       __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
+               __pack_control(chan, control, skb);
 
-       if (chan->fcs == L2CAP_FCS_CRC16) {
-               fcs = crc16(0, (u8 *)tx_skb->data,
-                                               tx_skb->len - L2CAP_FCS_SIZE);
-               put_unaligned_le16(fcs,
-                               tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
+               if (chan->fcs == L2CAP_FCS_CRC16) {
+                       u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
+                       put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
+               }
+
+               /* Clone after data has been modified. Data is assumed to be
+                  read-only (for locking purposes) on cloned sk_buffs.
+                */
+               tx_skb = skb_clone(skb, GFP_KERNEL);
+
+               if (!tx_skb)
+                       break;
+
+               __set_retrans_timer(chan);
+
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
+               chan->unacked_frames++;
+               chan->frames_sent++;
+               sent++;
+
+               if (skb_queue_is_last(&chan->tx_q, skb))
+                       chan->tx_send_head = NULL;
+               else
+                       chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
+
+               l2cap_do_send(chan, tx_skb);
+               BT_DBG("Sent txseq %d", (int)control->txseq);
        }
 
-       l2cap_do_send(chan, tx_skb);
+       BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent,
+              (int) chan->unacked_frames, skb_queue_len(&chan->tx_q));
+
+       return sent;
 }
 
-static int l2cap_ertm_send(struct l2cap_chan *chan)
+static void l2cap_ertm_resend(struct l2cap_chan *chan)
 {
-       struct sk_buff *skb, *tx_skb;
-       u16 fcs;
-       u32 control;
-       int nsent = 0;
+       struct l2cap_ctrl control;
+       struct sk_buff *skb;
+       struct sk_buff *tx_skb;
+       u16 seq;
 
-       if (chan->state != BT_CONNECTED)
-               return -ENOTCONN;
+       BT_DBG("chan %p", chan);
 
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
-               return 0;
+               return;
 
-       while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
+       while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
+               seq = l2cap_seq_list_pop(&chan->retrans_list);
 
-               if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
-                   chan->remote_max_tx) {
-                       l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-                       break;
+               skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
+               if (!skb) {
+                       BT_DBG("Error: Can't retransmit seq %d, frame missing",
+                               seq);
+                       continue;
                }
 
-               tx_skb = skb_clone(skb, GFP_ATOMIC);
-
                bt_cb(skb)->control.retries++;
+               control = bt_cb(skb)->control;
 
-               control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
-               control &= __get_sar_mask(chan);
+               if (chan->max_tx != 0 &&
+                   bt_cb(skb)->control.retries > chan->max_tx) {
+                       BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+                       l2cap_seq_list_clear(&chan->retrans_list);
+                       break;
+               }
 
+               control.reqseq = chan->buffer_seq;
                if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-                       control |= __set_ctrl_final(chan);
+                       control.final = 1;
+               else
+                       control.final = 0;
+
+               if (skb_cloned(skb)) {
+                       /* Cloned sk_buffs are read-only, so we need a
+                        * writeable copy
+                        */
+                       tx_skb = skb_copy(skb, GFP_ATOMIC);
+               } else {
+                       tx_skb = skb_clone(skb, GFP_ATOMIC);
+               }
 
-               control |= __set_reqseq(chan, chan->buffer_seq);
-               control |= __set_txseq(chan, chan->next_tx_seq);
-               control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
+               if (!tx_skb) {
+                       l2cap_seq_list_clear(&chan->retrans_list);
+                       break;
+               }
 
-               __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
+               /* Update skb contents */
+               if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+                       put_unaligned_le32(__pack_extended_control(&control),
+                                          tx_skb->data + L2CAP_HDR_SIZE);
+               } else {
+                       put_unaligned_le16(__pack_enhanced_control(&control),
+                                          tx_skb->data + L2CAP_HDR_SIZE);
+               }
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data,
-                                               tx_skb->len - L2CAP_FCS_SIZE);
-                       put_unaligned_le16(fcs, skb->data +
-                                               tx_skb->len - L2CAP_FCS_SIZE);
+                       u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
+                       put_unaligned_le16(fcs, skb_put(tx_skb,
+                                                       L2CAP_FCS_SIZE));
                }
 
                l2cap_do_send(chan, tx_skb);
 
-               __set_retrans_timer(chan);
-
-               bt_cb(skb)->control.txseq = chan->next_tx_seq;
+               BT_DBG("Resent txseq %d", control.txseq);
 
-               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
-
-               if (bt_cb(skb)->control.retries == 1) {
-                       chan->unacked_frames++;
-
-                       if (!nsent++)
-                               __clear_ack_timer(chan);
-               }
-
-               chan->frames_sent++;
-
-               if (skb_queue_is_last(&chan->tx_q, skb))
-                       chan->tx_send_head = NULL;
-               else
-                       chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
+               chan->last_acked_seq = chan->buffer_seq;
        }
-
-       return nsent;
 }
 
-static int l2cap_retransmit_frames(struct l2cap_chan *chan)
+static void l2cap_retransmit(struct l2cap_chan *chan,
+                            struct l2cap_ctrl *control)
 {
-       int ret;
+       BT_DBG("chan %p, control %p", chan, control);
 
-       if (!skb_queue_empty(&chan->tx_q))
-               chan->tx_send_head = chan->tx_q.next;
-
-       chan->next_tx_seq = chan->expected_ack_seq;
-       ret = l2cap_ertm_send(chan);
-       return ret;
+       l2cap_seq_list_append(&chan->retrans_list, control->reqseq);
+       l2cap_ertm_resend(chan);
 }
 
-static void __l2cap_send_ack(struct l2cap_chan *chan)
+static void l2cap_retransmit_all(struct l2cap_chan *chan,
+                                struct l2cap_ctrl *control)
 {
-       u32 control = 0;
+       struct sk_buff *skb;
 
-       control |= __set_reqseq(chan, chan->buffer_seq);
+       BT_DBG("chan %p, control %p", chan, control);
 
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-               set_bit(CONN_RNR_SENT, &chan->conn_state);
-               l2cap_send_sframe(chan, control);
-               return;
-       }
+       if (control->poll)
+               set_bit(CONN_SEND_FBIT, &chan->conn_state);
+
+       l2cap_seq_list_clear(&chan->retrans_list);
 
-       if (l2cap_ertm_send(chan) > 0)
+       if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return;
 
-       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-       l2cap_send_sframe(chan, control);
+       if (chan->unacked_frames) {
+               skb_queue_walk(&chan->tx_q, skb) {
+                       if (bt_cb(skb)->control.txseq == control->reqseq ||
+                               skb == chan->tx_send_head)
+                               break;
+               }
+
+               skb_queue_walk_from(&chan->tx_q, skb) {
+                       if (skb == chan->tx_send_head)
+                               break;
+
+                       l2cap_seq_list_append(&chan->retrans_list,
+                                             bt_cb(skb)->control.txseq);
+               }
+
+               l2cap_ertm_resend(chan);
+       }
 }
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-       __clear_ack_timer(chan);
-       __l2cap_send_ack(chan);
-}
+       struct l2cap_ctrl control;
+       u16 frames_to_ack = __seq_offset(chan, chan->buffer_seq,
+                                        chan->last_acked_seq);
+       int threshold;
 
-static void l2cap_send_srejtail(struct l2cap_chan *chan)
-{
-       struct srej_list *tail;
-       u32 control;
+       BT_DBG("chan %p last_acked_seq %d buffer_seq %d",
+              chan, chan->last_acked_seq, chan->buffer_seq);
+
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
 
-       control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-       control |= __set_ctrl_final(chan);
+       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
+           chan->rx_state == L2CAP_RX_STATE_RECV) {
+               __clear_ack_timer(chan);
+               control.super = L2CAP_SUPER_RNR;
+               control.reqseq = chan->buffer_seq;
+               l2cap_send_sframe(chan, &control);
+       } else {
+               if (!test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) {
+                       l2cap_ertm_send(chan);
+                       /* If any i-frames were sent, they included an ack */
+                       if (chan->buffer_seq == chan->last_acked_seq)
+                               frames_to_ack = 0;
+               }
 
-       tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-       control |= __set_reqseq(chan, tail->tx_seq);
+               /* Ack now if the tx window is 3/4ths full.
+                * Calculate without mul or div
+                */
+               threshold = chan->tx_win;
+               threshold += threshold << 1;
+               threshold >>= 2;
+
+               BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack,
+                      threshold);
+
+               if (frames_to_ack >= threshold) {
+                       __clear_ack_timer(chan);
+                       control.super = L2CAP_SUPER_RR;
+                       control.reqseq = chan->buffer_seq;
+                       l2cap_send_sframe(chan, &control);
+                       frames_to_ack = 0;
+               }
 
-       l2cap_send_sframe(chan, control);
+               if (frames_to_ack)
+                       __set_ack_timer(chan);
+       }
 }
 
 static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
@@ -1956,10 +2026,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (!conn)
                return ERR_PTR(-ENOTCONN);
 
-       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
-               hlen = L2CAP_EXT_HDR_SIZE;
-       else
-               hlen = L2CAP_ENH_HDR_SIZE;
+       hlen = __ertm_hdr_size(chan);
 
        if (sdulen)
                hlen += L2CAP_SDULEN_SIZE;
@@ -1979,7 +2046,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
-       __put_control(chan, 0, skb_put(skb, __ctrl_size(chan)));
+       /* Control header is populated later */
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
+       else
+               put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
 
        if (sdulen)
                put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
@@ -1990,9 +2061,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                return ERR_PTR(err);
        }
 
-       if (chan->fcs == L2CAP_FCS_CRC16)
-               put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
-
+       bt_cb(skb)->control.fcs = chan->fcs;
        bt_cb(skb)->control.retries = 0;
        return skb;
 }
@@ -2004,7 +2073,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        struct sk_buff *skb;
        u16 sdu_len;
        size_t pdu_len;
-       int err = 0;
        u8 sar;
 
        BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len);
@@ -2020,7 +2088,10 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
 
        /* Adjust for largest possible L2CAP overhead. */
-       pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE;
+       if (chan->fcs)
+               pdu_len -= L2CAP_FCS_SIZE;
+
+       pdu_len -= __ertm_hdr_size(chan);
 
        /* Remote device may have requested smaller PDUs */
        pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
@@ -2060,7 +2131,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
                }
        }
 
-       return err;
+       return 0;
 }
 
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
@@ -2122,17 +2193,12 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
                if (err)
                        break;
 
-               if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL)
-                       chan->tx_send_head = seg_queue.next;
-               skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
-
                if (chan->mode == L2CAP_MODE_ERTM)
-                       err = l2cap_ertm_send(chan);
+                       l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST);
                else
-                       l2cap_streaming_send(chan);
+                       l2cap_streaming_send(chan, &seg_queue);
 
-               if (err >= 0)
-                       err = len;
+               err = len;
 
                /* If the skbs were not queued for sending, they'll still be in
                 * seg_queue and need to be purged.
@@ -2148,6 +2214,296 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
        return err;
 }
 
+static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
+{
+       struct l2cap_ctrl control;
+       u16 seq;
+
+       BT_DBG("chan %p, txseq %d", chan, txseq);
+
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
+       control.super = L2CAP_SUPER_SREJ;
+
+       for (seq = chan->expected_tx_seq; seq != txseq;
+            seq = __next_seq(chan, seq)) {
+               if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) {
+                       control.reqseq = seq;
+                       l2cap_send_sframe(chan, &control);
+                       l2cap_seq_list_append(&chan->srej_list, seq);
+               }
+       }
+
+       chan->expected_tx_seq = __next_seq(chan, txseq);
+}
+
+static void l2cap_send_srej_tail(struct l2cap_chan *chan)
+{
+       struct l2cap_ctrl control;
+
+       BT_DBG("chan %p", chan);
+
+       if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR)
+               return;
+
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
+       control.super = L2CAP_SUPER_SREJ;
+       control.reqseq = chan->srej_list.tail;
+       l2cap_send_sframe(chan, &control);
+}
+
+static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq)
+{
+       struct l2cap_ctrl control;
+       u16 initial_head;
+       u16 seq;
+
+       BT_DBG("chan %p, txseq %d", chan, txseq);
+
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
+       control.super = L2CAP_SUPER_SREJ;
+
+       /* Capture initial list head to allow only one pass through the list. */
+       initial_head = chan->srej_list.head;
+
+       do {
+               seq = l2cap_seq_list_pop(&chan->srej_list);
+               if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR)
+                       break;
+
+               control.reqseq = seq;
+               l2cap_send_sframe(chan, &control);
+               l2cap_seq_list_append(&chan->srej_list, seq);
+       } while (chan->srej_list.head != initial_head);
+}
+
+static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq)
+{
+       struct sk_buff *acked_skb;
+       u16 ackseq;
+
+       BT_DBG("chan %p, reqseq %d", chan, reqseq);
+
+       if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq)
+               return;
+
+       BT_DBG("expected_ack_seq %d, unacked_frames %d",
+              chan->expected_ack_seq, chan->unacked_frames);
+
+       for (ackseq = chan->expected_ack_seq; ackseq != reqseq;
+            ackseq = __next_seq(chan, ackseq)) {
+
+               acked_skb = l2cap_ertm_seq_in_queue(&chan->tx_q, ackseq);
+               if (acked_skb) {
+                       skb_unlink(acked_skb, &chan->tx_q);
+                       kfree_skb(acked_skb);
+                       chan->unacked_frames--;
+               }
+       }
+
+       chan->expected_ack_seq = reqseq;
+
+       if (chan->unacked_frames == 0)
+               __clear_retrans_timer(chan);
+
+       BT_DBG("unacked_frames %d", (int) chan->unacked_frames);
+}
+
+static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan)
+{
+       BT_DBG("chan %p", chan);
+
+       chan->expected_tx_seq = chan->buffer_seq;
+       l2cap_seq_list_clear(&chan->srej_list);
+       skb_queue_purge(&chan->srej_q);
+       chan->rx_state = L2CAP_RX_STATE_RECV;
+}
+
+static void l2cap_tx_state_xmit(struct l2cap_chan *chan,
+                               struct l2cap_ctrl *control,
+                               struct sk_buff_head *skbs, u8 event)
+{
+       BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
+              event);
+
+       switch (event) {
+       case L2CAP_EV_DATA_REQUEST:
+               if (chan->tx_send_head == NULL)
+                       chan->tx_send_head = skb_peek(skbs);
+
+               skb_queue_splice_tail_init(skbs, &chan->tx_q);
+               l2cap_ertm_send(chan);
+               break;
+       case L2CAP_EV_LOCAL_BUSY_DETECTED:
+               BT_DBG("Enter LOCAL_BUSY");
+               set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+               if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+                       /* The SREJ_SENT state must be aborted if we are to
+                        * enter the LOCAL_BUSY state.
+                        */
+                       l2cap_abort_rx_srej_sent(chan);
+               }
+
+               l2cap_send_ack(chan);
+
+               break;
+       case L2CAP_EV_LOCAL_BUSY_CLEAR:
+               BT_DBG("Exit LOCAL_BUSY");
+               clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+               if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
+                       struct l2cap_ctrl local_control;
+
+                       memset(&local_control, 0, sizeof(local_control));
+                       local_control.sframe = 1;
+                       local_control.super = L2CAP_SUPER_RR;
+                       local_control.poll = 1;
+                       local_control.reqseq = chan->buffer_seq;
+                       l2cap_send_sframe(chan, &local_control);
+
+                       chan->retry_count = 1;
+                       __set_monitor_timer(chan);
+                       chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+               }
+               break;
+       case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
+               l2cap_process_reqseq(chan, control->reqseq);
+               break;
+       case L2CAP_EV_EXPLICIT_POLL:
+               l2cap_send_rr_or_rnr(chan, 1);
+               chan->retry_count = 1;
+               __set_monitor_timer(chan);
+               __clear_ack_timer(chan);
+               chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+               break;
+       case L2CAP_EV_RETRANS_TO:
+               l2cap_send_rr_or_rnr(chan, 1);
+               chan->retry_count = 1;
+               __set_monitor_timer(chan);
+               chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+               break;
+       case L2CAP_EV_RECV_FBIT:
+               /* Nothing to process */
+               break;
+       default:
+               break;
+       }
+}
+
+static void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
+                                 struct l2cap_ctrl *control,
+                                 struct sk_buff_head *skbs, u8 event)
+{
+       BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
+              event);
+
+       switch (event) {
+       case L2CAP_EV_DATA_REQUEST:
+               if (chan->tx_send_head == NULL)
+                       chan->tx_send_head = skb_peek(skbs);
+               /* Queue data, but don't send. */
+               skb_queue_splice_tail_init(skbs, &chan->tx_q);
+               break;
+       case L2CAP_EV_LOCAL_BUSY_DETECTED:
+               BT_DBG("Enter LOCAL_BUSY");
+               set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+               if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+                       /* The SREJ_SENT state must be aborted if we are to
+                        * enter the LOCAL_BUSY state.
+                        */
+                       l2cap_abort_rx_srej_sent(chan);
+               }
+
+               l2cap_send_ack(chan);
+
+               break;
+       case L2CAP_EV_LOCAL_BUSY_CLEAR:
+               BT_DBG("Exit LOCAL_BUSY");
+               clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+               if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
+                       struct l2cap_ctrl local_control;
+                       memset(&local_control, 0, sizeof(local_control));
+                       local_control.sframe = 1;
+                       local_control.super = L2CAP_SUPER_RR;
+                       local_control.poll = 1;
+                       local_control.reqseq = chan->buffer_seq;
+                       l2cap_send_sframe(chan, &local_control);
+
+                       chan->retry_count = 1;
+                       __set_monitor_timer(chan);
+                       chan->tx_state = L2CAP_TX_STATE_WAIT_F;
+               }
+               break;
+       case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
+               l2cap_process_reqseq(chan, control->reqseq);
+
+               /* Fall through */
+
+       case L2CAP_EV_RECV_FBIT:
+               if (control && control->final) {
+                       __clear_monitor_timer(chan);
+                       if (chan->unacked_frames > 0)
+                               __set_retrans_timer(chan);
+                       chan->retry_count = 0;
+                       chan->tx_state = L2CAP_TX_STATE_XMIT;
+                       BT_DBG("recv fbit tx_state 0x2.2%x", chan->tx_state);
+               }
+               break;
+       case L2CAP_EV_EXPLICIT_POLL:
+               /* Ignore */
+               break;
+       case L2CAP_EV_MONITOR_TO:
+               if (chan->max_tx == 0 || chan->retry_count < chan->max_tx) {
+                       l2cap_send_rr_or_rnr(chan, 1);
+                       __set_monitor_timer(chan);
+                       chan->retry_count++;
+               } else {
+                       l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+                    struct sk_buff_head *skbs, u8 event)
+{
+       BT_DBG("chan %p, control %p, skbs %p, event %d, state %d",
+              chan, control, skbs, event, chan->tx_state);
+
+       switch (chan->tx_state) {
+       case L2CAP_TX_STATE_XMIT:
+               l2cap_tx_state_xmit(chan, control, skbs, event);
+               break;
+       case L2CAP_TX_STATE_WAIT_F:
+               l2cap_tx_state_wait_f(chan, control, skbs, event);
+               break;
+       default:
+               /* Ignore event */
+               break;
+       }
+}
+
+static void l2cap_pass_to_tx(struct l2cap_chan *chan,
+                            struct l2cap_ctrl *control)
+{
+       BT_DBG("chan %p, control %p", chan, control);
+       l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
+}
+
+static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
+                                 struct l2cap_ctrl *control)
+{
+       BT_DBG("chan %p, control %p", chan, control);
+       l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_FBIT);
+}
+
 /* Copy frame to all raw sockets on that connection */
 static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
@@ -2170,7 +2526,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                if (!nskb)
                        continue;
 
-               if (chan->ops->recv(chan->data, nskb))
+               if (chan->ops->recv(chan, nskb))
                        kfree_skb(nskb);
        }
 
@@ -2200,9 +2556,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
        lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
 
        if (conn->hcon->type == LE_LINK)
-               lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
+               lh->cid = __constant_cpu_to_le16(L2CAP_CID_LE_SIGNALING);
        else
-               lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
+               lh->cid = __constant_cpu_to_le16(L2CAP_CID_SIGNALING);
 
        cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
        cmd->code  = code;
@@ -2314,8 +2670,8 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
                efs.stype       = chan->local_stype;
                efs.msdu        = cpu_to_le16(chan->local_msdu);
                efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
-               efs.acc_lat     = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
-               efs.flush_to    = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               efs.acc_lat     = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
+               efs.flush_to    = __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -2338,20 +2694,24 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
 static void l2cap_ack_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-                                                       ack_timer.work);
+                                              ack_timer.work);
+       u16 frames_to_ack;
 
        BT_DBG("chan %p", chan);
 
        l2cap_chan_lock(chan);
 
-       __l2cap_send_ack(chan);
+       frames_to_ack = __seq_offset(chan, chan->buffer_seq,
+                                    chan->last_acked_seq);
 
-       l2cap_chan_unlock(chan);
+       if (frames_to_ack)
+               l2cap_send_rr_or_rnr(chan, 0);
 
+       l2cap_chan_unlock(chan);
        l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
        int err;
 
@@ -2360,7 +2720,6 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
        chan->expected_ack_seq = 0;
        chan->unacked_frames = 0;
        chan->buffer_seq = 0;
-       chan->num_acked = 0;
        chan->frames_sent = 0;
        chan->last_acked_seq = 0;
        chan->sdu = NULL;
@@ -2381,12 +2740,15 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan)
 
        skb_queue_head_init(&chan->srej_q);
 
-       INIT_LIST_HEAD(&chan->srej_l);
        err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
        if (err < 0)
                return err;
 
-       return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
+       err = l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
+       if (err < 0)
+               l2cap_seq_list_free(&chan->srej_list);
+
+       return err;
 }
 
 static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2512,6 +2874,7 @@ done:
                break;
 
        case L2CAP_MODE_STREAMING:
+               l2cap_txwin_setup(chan);
                rfc.mode            = L2CAP_MODE_STREAMING;
                rfc.txwin_size      = 0;
                rfc.max_transmit    = 0;
@@ -2542,7 +2905,7 @@ done:
        }
 
        req->dcid  = cpu_to_le16(chan->dcid);
-       req->flags = cpu_to_le16(0);
+       req->flags = __constant_cpu_to_le16(0);
 
        return ptr - data;
 }
@@ -2762,7 +3125,7 @@ done:
        }
        rsp->scid   = cpu_to_le16(chan->dcid);
        rsp->result = cpu_to_le16(result);
-       rsp->flags  = cpu_to_le16(0x0000);
+       rsp->flags  = __constant_cpu_to_le16(0);
 
        return ptr - data;
 }
@@ -2861,7 +3224,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        }
 
        req->dcid   = cpu_to_le16(chan->dcid);
-       req->flags  = cpu_to_le16(0x0000);
+       req->flags  = __constant_cpu_to_le16(0);
 
        return ptr - data;
 }
@@ -2888,8 +3251,8 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
 
        rsp.scid   = cpu_to_le16(chan->dcid);
        rsp.dcid   = cpu_to_le16(chan->scid);
-       rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+       rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
        l2cap_send_cmd(conn, chan->ident,
                                L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
@@ -2929,8 +3292,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
         * did not send an RFC option.
         */
        rfc.mode = chan->mode;
-       rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
-       rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+       rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+       rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
        rfc.max_pdu_size = cpu_to_le16(chan->imtu);
 
        BT_ERR("Expected RFC option was not found, using defaults");
@@ -2993,7 +3356,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        lock_sock(parent);
 
        /* Check if the ACL is secure enough (if not SDP) */
-       if (psm != cpu_to_le16(0x0001) &&
+       if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
                conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
@@ -3002,25 +3365,16 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        result = L2CAP_CR_NO_MEM;
 
-       /* Check for backlog size */
-       if (sk_acceptq_is_full(parent)) {
-               BT_DBG("backlog full %d", parent->sk_ack_backlog);
+       /* Check if we already have channel with that dcid */
+       if (__l2cap_get_chan_by_dcid(conn, scid))
                goto response;
-       }
 
-       chan = pchan->ops->new_connection(pchan->data);
+       chan = pchan->ops->new_connection(pchan);
        if (!chan)
                goto response;
 
        sk = chan->sk;
 
-       /* Check if we already have channel with that dcid */
-       if (__l2cap_get_chan_by_dcid(conn, scid)) {
-               sock_set_flag(sk, SOCK_ZAPPED);
-               chan->ops->close(chan->data);
-               goto response;
-       }
-
        hci_conn_hold(conn->hcon);
 
        bacpy(&bt_sk(sk)->src, conn->src);
@@ -3074,7 +3428,7 @@ sendresp:
 
        if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
                struct l2cap_info_req info;
-               info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+               info.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
 
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
@@ -3196,7 +3550,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
                struct l2cap_cmd_rej_cid rej;
 
-               rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
+               rej.reason = __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID);
                rej.scid = cpu_to_le16(chan->scid);
                rej.dcid = cpu_to_le16(chan->dcid);
 
@@ -3218,11 +3572,11 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        memcpy(chan->conf_req + chan->conf_len, req->data, len);
        chan->conf_len += len;
 
-       if (flags & 0x0001) {
+       if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
                /* Incomplete config. Send empty response. */
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, 0x0001), rsp);
+                                       L2CAP_CONF_SUCCESS, flags), rsp);
                goto unlock;
        }
 
@@ -3245,8 +3599,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
 
-               l2cap_state_change(chan, BT_CONNECTED);
-
                if (chan->mode == L2CAP_MODE_ERTM ||
                    chan->mode == L2CAP_MODE_STREAMING)
                        err = l2cap_ertm_init(chan);
@@ -3278,7 +3630,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                        l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, 0x0000), rsp);
+                                       L2CAP_CONF_SUCCESS, flags), rsp);
        }
 
 unlock:
@@ -3369,7 +3721,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                goto done;
        }
 
-       if (flags & 0x01)
+       if (flags & L2CAP_CONF_FLAG_CONTINUATION)
                goto done;
 
        set_bit(CONF_INPUT_DONE, &chan->conf_state);
@@ -3377,7 +3729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
                set_default_fcs(chan);
 
-               l2cap_state_change(chan, BT_CONNECTED);
                if (chan->mode == L2CAP_MODE_ERTM ||
                    chan->mode == L2CAP_MODE_STREAMING)
                        err = l2cap_ertm_init(chan);
@@ -3431,7 +3782,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        l2cap_chan_put(chan);
 
        mutex_unlock(&conn->chan_lock);
@@ -3465,7 +3816,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
        l2cap_chan_unlock(chan);
 
-       chan->ops->close(chan->data);
+       chan->ops->close(chan);
        l2cap_chan_put(chan);
 
        mutex_unlock(&conn->chan_lock);
@@ -3486,8 +3837,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                u8 buf[8];
                u32 feat_mask = l2cap_feat_mask;
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
-               rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
-               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
+               rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                                         | L2CAP_FEAT_FCS;
@@ -3507,15 +3858,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                else
                        l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
 
-               rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
-               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+               rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
-               rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
+               rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(rsp), &rsp);
        }
@@ -3555,7 +3906,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
                if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
                        struct l2cap_info_req req;
-                       req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+                       req.type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 
                        conn->info_ident = l2cap_get_ident(conn);
 
@@ -3790,9 +4141,9 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 
        err = l2cap_check_conn_param(min, max, latency, to_multiplier);
        if (err)
-               rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
+               rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
        else
-               rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+               rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
                                                        sizeof(rsp), &rsp);
@@ -3940,7 +4291,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                        BT_ERR("Wrong link type (%d)", err);
 
                        /* FIXME: Map err to a valid reason */
-                       rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
+                       rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
                        l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
                }
 
@@ -3972,65 +4323,38 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
        return 0;
 }
 
-static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
+static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-       u32 control = 0;
+       struct l2cap_ctrl control;
 
-       chan->frames_sent = 0;
+       BT_DBG("chan %p", chan);
 
-       control |= __set_reqseq(chan, chan->buffer_seq);
+       memset(&control, 0, sizeof(control));
+       control.sframe = 1;
+       control.final = 1;
+       control.reqseq = chan->buffer_seq;
+       set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
-               l2cap_send_sframe(chan, control);
-               set_bit(CONN_RNR_SENT, &chan->conn_state);
+               control.super = L2CAP_SUPER_RNR;
+               l2cap_send_sframe(chan, &control);
        }
 
-       if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
-               l2cap_retransmit_frames(chan);
+       if (test_and_clear_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
+           chan->unacked_frames > 0)
+               __set_retrans_timer(chan);
 
+       /* Send pending iframes */
        l2cap_ertm_send(chan);
 
        if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
-                       chan->frames_sent == 0) {
-               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-               l2cap_send_sframe(chan, control);
-       }
-}
-
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
-{
-       struct sk_buff *next_skb;
-       int tx_seq_offset, next_tx_seq_offset;
-
-       bt_cb(skb)->control.txseq = tx_seq;
-       bt_cb(skb)->control.sar = sar;
-
-       next_skb = skb_peek(&chan->srej_q);
-
-       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
-
-       while (next_skb) {
-               if (bt_cb(next_skb)->control.txseq == tx_seq)
-                       return -EINVAL;
-
-               next_tx_seq_offset = __seq_offset(chan,
-                       bt_cb(next_skb)->control.txseq, chan->buffer_seq);
-
-               if (next_tx_seq_offset > tx_seq_offset) {
-                       __skb_queue_before(&chan->srej_q, next_skb, skb);
-                       return 0;
-               }
-
-               if (skb_queue_is_last(&chan->srej_q, next_skb))
-                       next_skb = NULL;
-               else
-                       next_skb = skb_queue_next(&chan->srej_q, next_skb);
+           test_bit(CONN_SEND_FBIT, &chan->conn_state)) {
+               /* F-bit wasn't sent in an s-frame or i-frame yet, so
+                * send it now.
+                */
+               control.super = L2CAP_SUPER_RR;
+               l2cap_send_sframe(chan, &control);
        }
-
-       __skb_queue_tail(&chan->srej_q, skb);
-
-       return 0;
 }
 
 static void append_skb_frag(struct sk_buff *skb,
@@ -4052,16 +4376,17 @@ static void append_skb_frag(struct sk_buff *skb,
        skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
+                               struct l2cap_ctrl *control)
 {
        int err = -EINVAL;
 
-       switch (__get_ctrl_sar(chan, control)) {
+       switch (control->sar) {
        case L2CAP_SAR_UNSEGMENTED:
                if (chan->sdu)
                        break;
 
-               err = chan->ops->recv(chan->data, skb);
+               err = chan->ops->recv(chan, skb);
                break;
 
        case L2CAP_SAR_START:
@@ -4111,7 +4436,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
                if (chan->sdu->len != chan->sdu_len)
                        break;
 
-               err = chan->ops->recv(chan->data, chan->sdu);
+               err = chan->ops->recv(chan, chan->sdu);
 
                if (!err) {
                        /* Reassembly complete */
@@ -4133,448 +4458,609 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3
        return err;
 }
 
-static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 {
-       BT_DBG("chan %p, Enter local busy", chan);
+       u8 event;
 
-       set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-       l2cap_seq_list_clear(&chan->srej_list);
+       if (chan->mode != L2CAP_MODE_ERTM)
+               return;
 
-       __set_ack_timer(chan);
+       event = busy ? L2CAP_EV_LOCAL_BUSY_DETECTED : L2CAP_EV_LOCAL_BUSY_CLEAR;
+       l2cap_tx(chan, NULL, NULL, event);
 }
 
-static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
+static int l2cap_rx_queued_iframes(struct l2cap_chan *chan)
 {
-       u32 control;
-
-       if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
-               goto done;
+       int err = 0;
+       /* Pass sequential frames to l2cap_reassemble_sdu()
+        * until a gap is encountered.
+        */
 
-       control = __set_reqseq(chan, chan->buffer_seq);
-       control |= __set_ctrl_poll(chan);
-       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
-       l2cap_send_sframe(chan, control);
-       chan->retry_count = 1;
+       BT_DBG("chan %p", chan);
 
-       __clear_retrans_timer(chan);
-       __set_monitor_timer(chan);
+       while (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+               struct sk_buff *skb;
+               BT_DBG("Searching for skb with txseq %d (queue len %d)",
+                      chan->buffer_seq, skb_queue_len(&chan->srej_q));
 
-       set_bit(CONN_WAIT_F, &chan->conn_state);
+               skb = l2cap_ertm_seq_in_queue(&chan->srej_q, chan->buffer_seq);
 
-done:
-       clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-       clear_bit(CONN_RNR_SENT, &chan->conn_state);
+               if (!skb)
+                       break;
 
-       BT_DBG("chan %p, Exit local busy", chan);
-}
+               skb_unlink(skb, &chan->srej_q);
+               chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+               err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->control);
+               if (err)
+                       break;
+       }
 
-void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
-{
-       if (chan->mode == L2CAP_MODE_ERTM) {
-               if (busy)
-                       l2cap_ertm_enter_local_busy(chan);
-               else
-                       l2cap_ertm_exit_local_busy(chan);
+       if (skb_queue_empty(&chan->srej_q)) {
+               chan->rx_state = L2CAP_RX_STATE_RECV;
+               l2cap_send_ack(chan);
        }
+
+       return err;
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
+static void l2cap_handle_srej(struct l2cap_chan *chan,
+                             struct l2cap_ctrl *control)
 {
        struct sk_buff *skb;
-       u32 control;
 
-       while ((skb = skb_peek(&chan->srej_q)) &&
-                       !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               int err;
+       BT_DBG("chan %p, control %p", chan, control);
 
-               if (bt_cb(skb)->control.txseq != tx_seq)
-                       break;
+       if (control->reqseq == chan->next_tx_seq) {
+               BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
+       }
 
-               skb = skb_dequeue(&chan->srej_q);
-               control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
-               err = l2cap_reassemble_sdu(chan, skb, control);
+       skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
 
-               if (err < 0) {
-                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-                       break;
-               }
+       if (skb == NULL) {
+               BT_DBG("Seq %d not available for retransmission",
+                      control->reqseq);
+               return;
+       }
 
-               chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
-               tx_seq = __next_seq(chan, tx_seq);
+       if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
+               BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
        }
-}
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
-{
-       struct srej_list *l, *tmp;
-       u32 control;
+       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-       list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
-               if (l->tx_seq == tx_seq) {
-                       list_del(&l->list);
-                       kfree(l);
-                       return;
+       if (control->poll) {
+               l2cap_pass_to_tx(chan, control);
+
+               set_bit(CONN_SEND_FBIT, &chan->conn_state);
+               l2cap_retransmit(chan, control);
+               l2cap_ertm_send(chan);
+
+               if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
+                       set_bit(CONN_SREJ_ACT, &chan->conn_state);
+                       chan->srej_save_reqseq = control->reqseq;
+               }
+       } else {
+               l2cap_pass_to_tx_fbit(chan, control);
+
+               if (control->final) {
+                       if (chan->srej_save_reqseq != control->reqseq ||
+                           !test_and_clear_bit(CONN_SREJ_ACT,
+                                               &chan->conn_state))
+                               l2cap_retransmit(chan, control);
+               } else {
+                       l2cap_retransmit(chan, control);
+                       if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
+                               set_bit(CONN_SREJ_ACT, &chan->conn_state);
+                               chan->srej_save_reqseq = control->reqseq;
+                       }
                }
-               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-               control |= __set_reqseq(chan, l->tx_seq);
-               l2cap_send_sframe(chan, control);
-               list_del(&l->list);
-               list_add_tail(&l->list, &chan->srej_l);
        }
 }
 
-static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
+static void l2cap_handle_rej(struct l2cap_chan *chan,
+                            struct l2cap_ctrl *control)
 {
-       struct srej_list *new;
-       u32 control;
-
-       while (tx_seq != chan->expected_tx_seq) {
-               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
-               control |= __set_reqseq(chan, chan->expected_tx_seq);
-               l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq);
-               l2cap_send_sframe(chan, control);
+       struct sk_buff *skb;
 
-               new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
-               if (!new)
-                       return -ENOMEM;
+       BT_DBG("chan %p, control %p", chan, control);
 
-               new->tx_seq = chan->expected_tx_seq;
+       if (control->reqseq == chan->next_tx_seq) {
+               BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
+       }
 
-               chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+       skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
 
-               list_add_tail(&new->list, &chan->srej_l);
+       if (chan->max_tx && skb &&
+           bt_cb(skb)->control.retries >= chan->max_tx) {
+               BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
        }
 
-       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-       return 0;
+       l2cap_pass_to_tx(chan, control);
+
+       if (control->final) {
+               if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
+                       l2cap_retransmit_all(chan, control);
+       } else {
+               l2cap_retransmit_all(chan, control);
+               l2cap_ertm_send(chan);
+               if (chan->tx_state == L2CAP_TX_STATE_WAIT_F)
+                       set_bit(CONN_REJ_ACT, &chan->conn_state);
+       }
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
+static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
 {
-       u16 tx_seq = __get_txseq(chan, rx_control);
-       u16 req_seq = __get_reqseq(chan, rx_control);
-       u8 sar = __get_ctrl_sar(chan, rx_control);
-       int tx_seq_offset, expected_tx_seq_offset;
-       int num_to_ack = (chan->tx_win/6) + 1;
-       int err = 0;
+       BT_DBG("chan %p, txseq %d", chan, txseq);
 
-       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
-                                                       tx_seq, rx_control);
+       BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq,
+              chan->expected_tx_seq);
 
-       if (__is_ctrl_final(chan, rx_control) &&
-                       test_bit(CONN_WAIT_F, &chan->conn_state)) {
-               __clear_monitor_timer(chan);
-               if (chan->unacked_frames > 0)
-                       __set_retrans_timer(chan);
-               clear_bit(CONN_WAIT_F, &chan->conn_state);
-       }
+       if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
+               if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
+                                                               chan->tx_win) {
+                       /* See notes below regarding "double poll" and
+                        * invalid packets.
+                        */
+                       if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
+                               BT_DBG("Invalid/Ignore - after SREJ");
+                               return L2CAP_TXSEQ_INVALID_IGNORE;
+                       } else {
+                               BT_DBG("Invalid - in window after SREJ sent");
+                               return L2CAP_TXSEQ_INVALID;
+                       }
+               }
 
-       chan->expected_ack_seq = req_seq;
-       l2cap_drop_acked_frames(chan);
+               if (chan->srej_list.head == txseq) {
+                       BT_DBG("Expected SREJ");
+                       return L2CAP_TXSEQ_EXPECTED_SREJ;
+               }
 
-       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
+               if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) {
+                       BT_DBG("Duplicate SREJ - txseq already stored");
+                       return L2CAP_TXSEQ_DUPLICATE_SREJ;
+               }
 
-       /* invalid tx_seq */
-       if (tx_seq_offset >= chan->tx_win) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-               goto drop;
+               if (l2cap_seq_list_contains(&chan->srej_list, txseq)) {
+                       BT_DBG("Unexpected SREJ - not requested");
+                       return L2CAP_TXSEQ_UNEXPECTED_SREJ;
+               }
        }
 
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
-                       l2cap_send_ack(chan);
-               goto drop;
+       if (chan->expected_tx_seq == txseq) {
+               if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
+                   chan->tx_win) {
+                       BT_DBG("Invalid - txseq outside tx window");
+                       return L2CAP_TXSEQ_INVALID;
+               } else {
+                       BT_DBG("Expected");
+                       return L2CAP_TXSEQ_EXPECTED;
+               }
        }
 
-       if (tx_seq == chan->expected_tx_seq)
-               goto expected;
+       if (__seq_offset(chan, txseq, chan->last_acked_seq) <
+               __seq_offset(chan, chan->expected_tx_seq,
+                            chan->last_acked_seq)){
+               BT_DBG("Duplicate - expected_tx_seq later than txseq");
+               return L2CAP_TXSEQ_DUPLICATE;
+       }
+
+       if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) {
+               /* A source of invalid packets is a "double poll" condition,
+                * where delays cause us to send multiple poll packets.  If
+                * the remote stack receives and processes both polls,
+                * sequence numbers can wrap around in such a way that a
+                * resent frame has a sequence number that looks like new data
+                * with a sequence gap.  This would trigger an erroneous SREJ
+                * request.
+                *
+                * Fortunately, this is impossible with a tx window that's
+                * less than half of the maximum sequence number, which allows
+                * invalid frames to be safely ignored.
+                *
+                * With tx window sizes greater than half of the tx window
+                * maximum, the frame is invalid and cannot be ignored.  This
+                * causes a disconnect.
+                */
 
-       if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-               struct srej_list *first;
+               if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
+                       BT_DBG("Invalid/Ignore - txseq outside tx window");
+                       return L2CAP_TXSEQ_INVALID_IGNORE;
+               } else {
+                       BT_DBG("Invalid - txseq outside tx window");
+                       return L2CAP_TXSEQ_INVALID;
+               }
+       } else {
+               BT_DBG("Unexpected - txseq indicates missing frames");
+               return L2CAP_TXSEQ_UNEXPECTED;
+       }
+}
 
-               first = list_first_entry(&chan->srej_l,
-                               struct srej_list, list);
-               if (tx_seq == first->tx_seq) {
-                       l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
-                       l2cap_check_srej_gap(chan, tx_seq);
+static int l2cap_rx_state_recv(struct l2cap_chan *chan,
+                              struct l2cap_ctrl *control,
+                              struct sk_buff *skb, u8 event)
+{
+       int err = 0;
+       bool skb_in_use = 0;
 
-                       list_del(&first->list);
-                       kfree(first);
+       BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
+              event);
 
-                       if (list_empty(&chan->srej_l)) {
-                               chan->buffer_seq = chan->buffer_seq_srej;
-                               clear_bit(CONN_SREJ_SENT, &chan->conn_state);
-                               l2cap_send_ack(chan);
-                               BT_DBG("chan %p, Exit SREJ_SENT", chan);
+       switch (event) {
+       case L2CAP_EV_RECV_IFRAME:
+               switch (l2cap_classify_txseq(chan, control->txseq)) {
+               case L2CAP_TXSEQ_EXPECTED:
+                       l2cap_pass_to_tx(chan, control);
+
+                       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+                               BT_DBG("Busy, discarding expected seq %d",
+                                      control->txseq);
+                               break;
                        }
-               } else {
-                       struct srej_list *l;
 
-                       /* duplicated tx_seq */
-                       if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
-                               goto drop;
+                       chan->expected_tx_seq = __next_seq(chan,
+                                                          control->txseq);
 
-                       list_for_each_entry(l, &chan->srej_l, list) {
-                               if (l->tx_seq == tx_seq) {
-                                       l2cap_resend_srejframe(chan, tx_seq);
-                                       return 0;
+                       chan->buffer_seq = chan->expected_tx_seq;
+                       skb_in_use = 1;
+
+                       err = l2cap_reassemble_sdu(chan, skb, control);
+                       if (err)
+                               break;
+
+                       if (control->final) {
+                               if (!test_and_clear_bit(CONN_REJ_ACT,
+                                                       &chan->conn_state)) {
+                                       control->final = 0;
+                                       l2cap_retransmit_all(chan, control);
+                                       l2cap_ertm_send(chan);
                                }
                        }
 
-                       err = l2cap_send_srejframe(chan, tx_seq);
-                       if (err < 0) {
-                               l2cap_send_disconn_req(chan->conn, chan, -err);
-                               return err;
+                       if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
+                               l2cap_send_ack(chan);
+                       break;
+               case L2CAP_TXSEQ_UNEXPECTED:
+                       l2cap_pass_to_tx(chan, control);
+
+                       /* Can't issue SREJ frames in the local busy state.
+                        * Drop this frame, it will be seen as missing
+                        * when local busy is exited.
+                        */
+                       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+                               BT_DBG("Busy, discarding unexpected seq %d",
+                                      control->txseq);
+                               break;
                        }
-               }
-       } else {
-               expected_tx_seq_offset = __seq_offset(chan,
-                               chan->expected_tx_seq, chan->buffer_seq);
-
-               /* duplicated tx_seq */
-               if (tx_seq_offset < expected_tx_seq_offset)
-                       goto drop;
 
-               set_bit(CONN_SREJ_SENT, &chan->conn_state);
+                       /* There was a gap in the sequence, so an SREJ
+                        * must be sent for each missing frame.  The
+                        * current frame is stored for later use.
+                        */
+                       skb_queue_tail(&chan->srej_q, skb);
+                       skb_in_use = 1;
+                       BT_DBG("Queued %p (queue len %d)", skb,
+                              skb_queue_len(&chan->srej_q));
 
-               BT_DBG("chan %p, Enter SREJ", chan);
+                       clear_bit(CONN_SREJ_ACT, &chan->conn_state);
+                       l2cap_seq_list_clear(&chan->srej_list);
+                       l2cap_send_srej(chan, control->txseq);
 
-               INIT_LIST_HEAD(&chan->srej_l);
-               chan->buffer_seq_srej = chan->buffer_seq;
+                       chan->rx_state = L2CAP_RX_STATE_SREJ_SENT;
+                       break;
+               case L2CAP_TXSEQ_DUPLICATE:
+                       l2cap_pass_to_tx(chan, control);
+                       break;
+               case L2CAP_TXSEQ_INVALID_IGNORE:
+                       break;
+               case L2CAP_TXSEQ_INVALID:
+               default:
+                       l2cap_send_disconn_req(chan->conn, chan,
+                                              ECONNRESET);
+                       break;
+               }
+               break;
+       case L2CAP_EV_RECV_RR:
+               l2cap_pass_to_tx(chan, control);
+               if (control->final) {
+                       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-               __skb_queue_head_init(&chan->srej_q);
-               l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
+                       if (!test_and_clear_bit(CONN_REJ_ACT,
+                                               &chan->conn_state)) {
+                               control->final = 0;
+                               l2cap_retransmit_all(chan, control);
+                       }
 
-               /* Set P-bit only if there are some I-frames to ack. */
-               if (__clear_ack_timer(chan))
-                       set_bit(CONN_SEND_PBIT, &chan->conn_state);
+                       l2cap_ertm_send(chan);
+               } else if (control->poll) {
+                       l2cap_send_i_or_rr_or_rnr(chan);
+               } else {
+                       if (test_and_clear_bit(CONN_REMOTE_BUSY,
+                                              &chan->conn_state) &&
+                           chan->unacked_frames)
+                               __set_retrans_timer(chan);
 
-               err = l2cap_send_srejframe(chan, tx_seq);
-               if (err < 0) {
-                       l2cap_send_disconn_req(chan->conn, chan, -err);
-                       return err;
+                       l2cap_ertm_send(chan);
                }
-       }
-       return 0;
-
-expected:
-       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
-
-       if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-               bt_cb(skb)->control.txseq = tx_seq;
-               bt_cb(skb)->control.sar = sar;
-               __skb_queue_tail(&chan->srej_q, skb);
-               return 0;
+               break;
+       case L2CAP_EV_RECV_RNR:
+               set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+               l2cap_pass_to_tx(chan, control);
+               if (control && control->poll) {
+                       set_bit(CONN_SEND_FBIT, &chan->conn_state);
+                       l2cap_send_rr_or_rnr(chan, 0);
+               }
+               __clear_retrans_timer(chan);
+               l2cap_seq_list_clear(&chan->retrans_list);
+               break;
+       case L2CAP_EV_RECV_REJ:
+               l2cap_handle_rej(chan, control);
+               break;
+       case L2CAP_EV_RECV_SREJ:
+               l2cap_handle_srej(chan, control);
+               break;
+       default:
+               break;
        }
 
-       err = l2cap_reassemble_sdu(chan, skb, rx_control);
-       chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
-
-       if (err < 0) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-               return err;
+       if (skb && !skb_in_use) {
+               BT_DBG("Freeing %p", skb);
+               kfree_skb(skb);
        }
 
-       if (__is_ctrl_final(chan, rx_control)) {
-               if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-                       l2cap_retransmit_frames(chan);
-       }
+       return err;
+}
 
+static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
+                                   struct l2cap_ctrl *control,
+                                   struct sk_buff *skb, u8 event)
+{
+       int err = 0;
+       u16 txseq = control->txseq;
+       bool skb_in_use = 0;
+
+       BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
+              event);
+
+       switch (event) {
+       case L2CAP_EV_RECV_IFRAME:
+               switch (l2cap_classify_txseq(chan, txseq)) {
+               case L2CAP_TXSEQ_EXPECTED:
+                       /* Keep frame for reassembly later */
+                       l2cap_pass_to_tx(chan, control);
+                       skb_queue_tail(&chan->srej_q, skb);
+                       skb_in_use = 1;
+                       BT_DBG("Queued %p (queue len %d)", skb,
+                              skb_queue_len(&chan->srej_q));
+
+                       chan->expected_tx_seq = __next_seq(chan, txseq);
+                       break;
+               case L2CAP_TXSEQ_EXPECTED_SREJ:
+                       l2cap_seq_list_pop(&chan->srej_list);
 
-       chan->num_acked = (chan->num_acked + 1) % num_to_ack;
-       if (chan->num_acked == num_to_ack - 1)
-               l2cap_send_ack(chan);
-       else
-               __set_ack_timer(chan);
+                       l2cap_pass_to_tx(chan, control);
+                       skb_queue_tail(&chan->srej_q, skb);
+                       skb_in_use = 1;
+                       BT_DBG("Queued %p (queue len %d)", skb,
+                              skb_queue_len(&chan->srej_q));
 
-       return 0;
+                       err = l2cap_rx_queued_iframes(chan);
+                       if (err)
+                               break;
 
-drop:
-       kfree_skb(skb);
-       return 0;
-}
+                       break;
+               case L2CAP_TXSEQ_UNEXPECTED:
+                       /* Got a frame that can't be reassembled yet.
+                        * Save it for later, and send SREJs to cover
+                        * the missing frames.
+                        */
+                       skb_queue_tail(&chan->srej_q, skb);
+                       skb_in_use = 1;
+                       BT_DBG("Queued %p (queue len %d)", skb,
+                              skb_queue_len(&chan->srej_q));
+
+                       l2cap_pass_to_tx(chan, control);
+                       l2cap_send_srej(chan, control->txseq);
+                       break;
+               case L2CAP_TXSEQ_UNEXPECTED_SREJ:
+                       /* This frame was requested with an SREJ, but
+                        * some expected retransmitted frames are
+                        * missing.  Request retransmission of missing
+                        * SREJ'd frames.
+                        */
+                       skb_queue_tail(&chan->srej_q, skb);
+                       skb_in_use = 1;
+                       BT_DBG("Queued %p (queue len %d)", skb,
+                              skb_queue_len(&chan->srej_q));
+
+                       l2cap_pass_to_tx(chan, control);
+                       l2cap_send_srej_list(chan, control->txseq);
+                       break;
+               case L2CAP_TXSEQ_DUPLICATE_SREJ:
+                       /* We've already queued this frame.  Drop this copy. */
+                       l2cap_pass_to_tx(chan, control);
+                       break;
+               case L2CAP_TXSEQ_DUPLICATE:
+                       /* Expecting a later sequence number, so this frame
+                        * was already received.  Ignore it completely.
+                        */
+                       break;
+               case L2CAP_TXSEQ_INVALID_IGNORE:
+                       break;
+               case L2CAP_TXSEQ_INVALID:
+               default:
+                       l2cap_send_disconn_req(chan->conn, chan,
+                                              ECONNRESET);
+                       break;
+               }
+               break;
+       case L2CAP_EV_RECV_RR:
+               l2cap_pass_to_tx(chan, control);
+               if (control->final) {
+                       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
-{
-       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
-                               __get_reqseq(chan, rx_control), rx_control);
+                       if (!test_and_clear_bit(CONN_REJ_ACT,
+                                               &chan->conn_state)) {
+                               control->final = 0;
+                               l2cap_retransmit_all(chan, control);
+                       }
 
-       chan->expected_ack_seq = __get_reqseq(chan, rx_control);
-       l2cap_drop_acked_frames(chan);
+                       l2cap_ertm_send(chan);
+               } else if (control->poll) {
+                       if (test_and_clear_bit(CONN_REMOTE_BUSY,
+                                              &chan->conn_state) &&
+                           chan->unacked_frames) {
+                               __set_retrans_timer(chan);
+                       }
 
-       if (__is_ctrl_poll(chan, rx_control)) {
-               set_bit(CONN_SEND_FBIT, &chan->conn_state);
-               if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-                       if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
-                                       (chan->unacked_frames > 0))
+                       set_bit(CONN_SEND_FBIT, &chan->conn_state);
+                       l2cap_send_srej_tail(chan);
+               } else {
+                       if (test_and_clear_bit(CONN_REMOTE_BUSY,
+                                              &chan->conn_state) &&
+                           chan->unacked_frames)
                                __set_retrans_timer(chan);
 
-                       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-                       l2cap_send_srejtail(chan);
+                       l2cap_send_ack(chan);
+               }
+               break;
+       case L2CAP_EV_RECV_RNR:
+               set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+               l2cap_pass_to_tx(chan, control);
+               if (control->poll) {
+                       l2cap_send_srej_tail(chan);
                } else {
-                       l2cap_send_i_or_rr_or_rnr(chan);
+                       struct l2cap_ctrl rr_control;
+                       memset(&rr_control, 0, sizeof(rr_control));
+                       rr_control.sframe = 1;
+                       rr_control.super = L2CAP_SUPER_RR;
+                       rr_control.reqseq = chan->buffer_seq;
+                       l2cap_send_sframe(chan, &rr_control);
                }
 
-       } else if (__is_ctrl_final(chan, rx_control)) {
-               clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-               if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-                       l2cap_retransmit_frames(chan);
-
-       } else {
-               if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
-                               (chan->unacked_frames > 0))
-                       __set_retrans_timer(chan);
+               break;
+       case L2CAP_EV_RECV_REJ:
+               l2cap_handle_rej(chan, control);
+               break;
+       case L2CAP_EV_RECV_SREJ:
+               l2cap_handle_srej(chan, control);
+               break;
+       }
 
-               clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-               if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
-                       l2cap_send_ack(chan);
-               else
-                       l2cap_ertm_send(chan);
+       if (skb && !skb_in_use) {
+               BT_DBG("Freeing %p", skb);
+               kfree_skb(skb);
        }
+
+       return err;
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
+static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
 {
-       u16 tx_seq = __get_reqseq(chan, rx_control);
-
-       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
-       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-       chan->expected_ack_seq = tx_seq;
-       l2cap_drop_acked_frames(chan);
+       /* Make sure reqseq is for a packet that has been sent but not acked */
+       u16 unacked;
 
-       if (__is_ctrl_final(chan, rx_control)) {
-               if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
-                       l2cap_retransmit_frames(chan);
-       } else {
-               l2cap_retransmit_frames(chan);
-
-               if (test_bit(CONN_WAIT_F, &chan->conn_state))
-                       set_bit(CONN_REJ_ACT, &chan->conn_state);
-       }
+       unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq);
+       return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked;
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
-{
-       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
-
-       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-
-       if (__is_ctrl_poll(chan, rx_control)) {
-               chan->expected_ack_seq = tx_seq;
-               l2cap_drop_acked_frames(chan);
-
-               set_bit(CONN_SEND_FBIT, &chan->conn_state);
-               l2cap_retransmit_one_frame(chan, tx_seq);
+static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+                   struct sk_buff *skb, u8 event)
+{
+       int err = 0;
 
-               l2cap_ertm_send(chan);
+       BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan,
+              control, skb, event, chan->rx_state);
 
-               if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
-                       chan->srej_save_reqseq = tx_seq;
-                       set_bit(CONN_SREJ_ACT, &chan->conn_state);
+       if (__valid_reqseq(chan, control->reqseq)) {
+               switch (chan->rx_state) {
+               case L2CAP_RX_STATE_RECV:
+                       err = l2cap_rx_state_recv(chan, control, skb, event);
+                       break;
+               case L2CAP_RX_STATE_SREJ_SENT:
+                       err = l2cap_rx_state_srej_sent(chan, control, skb,
+                                                      event);
+                       break;
+               default:
+                       /* shut it down */
+                       break;
                }
-       } else if (__is_ctrl_final(chan, rx_control)) {
-               if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
-                               chan->srej_save_reqseq == tx_seq)
-                       clear_bit(CONN_SREJ_ACT, &chan->conn_state);
-               else
-                       l2cap_retransmit_one_frame(chan, tx_seq);
        } else {
-               l2cap_retransmit_one_frame(chan, tx_seq);
-               if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
-                       chan->srej_save_reqseq = tx_seq;
-                       set_bit(CONN_SREJ_ACT, &chan->conn_state);
-               }
+               BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
+                      control->reqseq, chan->next_tx_seq,
+                      chan->expected_ack_seq);
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
        }
+
+       return err;
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
+static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
+                          struct sk_buff *skb)
 {
-       u16 tx_seq = __get_reqseq(chan, rx_control);
+       int err = 0;
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb,
+              chan->rx_state);
 
-       set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
-       chan->expected_ack_seq = tx_seq;
-       l2cap_drop_acked_frames(chan);
+       if (l2cap_classify_txseq(chan, control->txseq) ==
+           L2CAP_TXSEQ_EXPECTED) {
+               l2cap_pass_to_tx(chan, control);
 
-       if (__is_ctrl_poll(chan, rx_control))
-               set_bit(CONN_SEND_FBIT, &chan->conn_state);
+               BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
+                      __next_seq(chan, chan->buffer_seq));
 
-       if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
-               __clear_retrans_timer(chan);
-               if (__is_ctrl_poll(chan, rx_control))
-                       l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
-               return;
-       }
+               chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
 
-       if (__is_ctrl_poll(chan, rx_control)) {
-               l2cap_send_srejtail(chan);
+               l2cap_reassemble_sdu(chan, skb, control);
        } else {
-               rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
-               l2cap_send_sframe(chan, rx_control);
-       }
-}
-
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
-{
-       BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
+               if (chan->sdu) {
+                       kfree_skb(chan->sdu);
+                       chan->sdu = NULL;
+               }
+               chan->sdu_last_frag = NULL;
+               chan->sdu_len = 0;
 
-       if (__is_ctrl_final(chan, rx_control) &&
-                       test_bit(CONN_WAIT_F, &chan->conn_state)) {
-               __clear_monitor_timer(chan);
-               if (chan->unacked_frames > 0)
-                       __set_retrans_timer(chan);
-               clear_bit(CONN_WAIT_F, &chan->conn_state);
+               if (skb) {
+                       BT_DBG("Freeing %p", skb);
+                       kfree_skb(skb);
+               }
        }
 
-       switch (__get_ctrl_super(chan, rx_control)) {
-       case L2CAP_SUPER_RR:
-               l2cap_data_channel_rrframe(chan, rx_control);
-               break;
-
-       case L2CAP_SUPER_REJ:
-               l2cap_data_channel_rejframe(chan, rx_control);
-               break;
-
-       case L2CAP_SUPER_SREJ:
-               l2cap_data_channel_srejframe(chan, rx_control);
-               break;
-
-       case L2CAP_SUPER_RNR:
-               l2cap_data_channel_rnrframe(chan, rx_control);
-               break;
-       }
+       chan->last_acked_seq = control->txseq;
+       chan->expected_tx_seq = __next_seq(chan, control->txseq);
 
-       kfree_skb(skb);
-       return 0;
+       return err;
 }
 
-static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
+static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       u32 control;
-       u16 req_seq;
-       int len, next_tx_seq_offset, req_seq_offset;
+       struct l2cap_ctrl *control = &bt_cb(skb)->control;
+       u16 len;
+       u8 event;
 
        __unpack_control(chan, skb);
 
-       control = __get_control(chan, skb->data);
-       skb_pull(skb, __ctrl_size(chan));
        len = skb->len;
 
        /*
         * We can just drop the corrupted I-frame here.
         * Receiver will miss it and start proper recovery
-        * procedures and ask retransmission.
+        * procedures and ask for retransmission.
         */
        if (l2cap_check_fcs(chan, skb))
                goto drop;
 
-       if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+       if (!control->sframe && control->sar == L2CAP_SAR_START)
                len -= L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
@@ -4585,34 +5071,57 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
                goto drop;
        }
 
-       req_seq = __get_reqseq(chan, control);
-
-       req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
-
-       next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
-                                               chan->expected_ack_seq);
+       if (!control->sframe) {
+               int err;
 
-       /* check for invalid req-seq */
-       if (req_seq_offset > next_tx_seq_offset) {
-               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-               goto drop;
-       }
+               BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d",
+                      control->sar, control->reqseq, control->final,
+                      control->txseq);
 
-       if (!__is_sframe(chan, control)) {
-               if (len < 0) {
-                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               /* Validate F-bit - F=0 always valid, F=1 only
+                * valid in TX WAIT_F
+                */
+               if (control->final && chan->tx_state != L2CAP_TX_STATE_WAIT_F)
                        goto drop;
+
+               if (chan->mode != L2CAP_MODE_STREAMING) {
+                       event = L2CAP_EV_RECV_IFRAME;
+                       err = l2cap_rx(chan, control, skb, event);
+               } else {
+                       err = l2cap_stream_rx(chan, control, skb);
                }
 
-               l2cap_data_channel_iframe(chan, control, skb);
+               if (err)
+                       l2cap_send_disconn_req(chan->conn, chan,
+                                              ECONNRESET);
        } else {
+               const u8 rx_func_to_event[4] = {
+                       L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
+                       L2CAP_EV_RECV_RNR, L2CAP_EV_RECV_SREJ
+               };
+
+               /* Only I-frames are expected in streaming mode */
+               if (chan->mode == L2CAP_MODE_STREAMING)
+                       goto drop;
+
+               BT_DBG("sframe reqseq %d, final %d, poll %d, super %d",
+                      control->reqseq, control->final, control->poll,
+                      control->super);
+
                if (len != 0) {
                        BT_ERR("%d", len);
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
                }
 
-               l2cap_data_channel_sframe(chan, control, skb);
+               /* Validate F and P bits */
+               if (control->final && (control->poll ||
+                                      chan->tx_state != L2CAP_TX_STATE_WAIT_F))
+                       goto drop;
+
+               event = rx_func_to_event[control->super];
+               if (l2cap_rx(chan, control, skb, event))
+                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
        }
 
        return 0;
@@ -4622,19 +5131,27 @@ drop:
        return 0;
 }
 
-static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
+static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
+                              struct sk_buff *skb)
 {
        struct l2cap_chan *chan;
-       u32 control;
-       u16 tx_seq;
-       int len;
 
        chan = l2cap_get_chan_by_scid(conn, cid);
        if (!chan) {
-               BT_DBG("unknown cid 0x%4.4x", cid);
-               /* Drop packet and return */
-               kfree_skb(skb);
-               return 0;
+               if (cid == L2CAP_CID_A2MP) {
+                       chan = a2mp_channel_create(conn, skb);
+                       if (!chan) {
+                               kfree_skb(skb);
+                               return;
+                       }
+
+                       l2cap_chan_lock(chan);
+               } else {
+                       BT_DBG("unknown cid 0x%4.4x", cid);
+                       /* Drop packet and return */
+                       kfree_skb(skb);
+                       return;
+               }
        }
 
        BT_DBG("chan %p, len %d", chan, skb->len);
@@ -4652,49 +5169,13 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                if (chan->imtu < skb->len)
                        goto drop;
 
-               if (!chan->ops->recv(chan->data, skb))
+               if (!chan->ops->recv(chan, skb))
                        goto done;
                break;
 
        case L2CAP_MODE_ERTM:
-               l2cap_ertm_data_rcv(chan, skb);
-
-               goto done;
-
        case L2CAP_MODE_STREAMING:
-               control = __get_control(chan, skb->data);
-               skb_pull(skb, __ctrl_size(chan));
-               len = skb->len;
-
-               if (l2cap_check_fcs(chan, skb))
-                       goto drop;
-
-               if (__is_sar_start(chan, control))
-                       len -= L2CAP_SDULEN_SIZE;
-
-               if (chan->fcs == L2CAP_FCS_CRC16)
-                       len -= L2CAP_FCS_SIZE;
-
-               if (len > chan->mps || len < 0 || __is_sframe(chan, control))
-                       goto drop;
-
-               tx_seq = __get_txseq(chan, control);
-
-               if (chan->expected_tx_seq != tx_seq) {
-                       /* Frame(s) missing - must discard partial SDU */
-                       kfree_skb(chan->sdu);
-                       chan->sdu = NULL;
-                       chan->sdu_last_frag = NULL;
-                       chan->sdu_len = 0;
-
-                       /* TODO: Notify userland of missing data */
-               }
-
-               chan->expected_tx_seq = __next_seq(chan, tx_seq);
-
-               if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
-                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
-
+               l2cap_data_rcv(chan, skb);
                goto done;
 
        default:
@@ -4707,11 +5188,10 @@ drop:
 
 done:
        l2cap_chan_unlock(chan);
-
-       return 0;
 }
 
-static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
+static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
+                                 struct sk_buff *skb)
 {
        struct l2cap_chan *chan;
 
@@ -4727,17 +5207,15 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
        if (chan->imtu < skb->len)
                goto drop;
 
-       if (!chan->ops->recv(chan->data, skb))
-               return 0;
+       if (!chan->ops->recv(chan, skb))
+               return;
 
 drop:
        kfree_skb(skb);
-
-       return 0;
 }
 
-static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
-                                   struct sk_buff *skb)
+static void l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
+                             struct sk_buff *skb)
 {
        struct l2cap_chan *chan;
 
@@ -4753,13 +5231,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
        if (chan->imtu < skb->len)
                goto drop;
 
-       if (!chan->ops->recv(chan->data, skb))
-               return 0;
+       if (!chan->ops->recv(chan, skb))
+               return;
 
 drop:
        kfree_skb(skb);
-
-       return 0;
 }
 
 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
@@ -4787,7 +5263,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 
        case L2CAP_CID_CONN_LESS:
                psm = get_unaligned((__le16 *) skb->data);
-               skb_pull(skb, 2);
+               skb_pull(skb, L2CAP_PSMLEN_SIZE);
                l2cap_conless_channel(conn, psm, skb);
                break;
 
@@ -4981,6 +5457,17 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        rsp.status = cpu_to_le16(stat);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
                                                        sizeof(rsp), &rsp);
+
+                       if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
+                           res == L2CAP_CR_SUCCESS) {
+                               char buf[128];
+                               set_bit(CONF_REQ_SENT, &chan->conf_state);
+                               l2cap_send_cmd(conn, l2cap_get_ident(conn),
+                                              L2CAP_CONF_REQ,
+                                              l2cap_build_conf_req(chan, buf),
+                                              buf);
+                               chan->num_conf_req++;
+                       }
                }
 
                l2cap_chan_unlock(chan);
index 3bb1611b9d487c1c8406748d069af917d269b86c..a4bb27e8427e9aabaa48b90727cb23bcf5568f96 100644 (file)
@@ -27,7 +27,6 @@
 
 /* Bluetooth L2CAP sockets. */
 
-#include <linux/security.h>
 #include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (err < 0)
                goto done;
 
-       if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
-                               __le16_to_cpu(la.l2_psm) == 0x0003)
+       if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
+           __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
                chan->sec_level = BT_SECURITY_SDP;
 
        bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
@@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
+static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
+{
+       switch (chan->scid) {
+       case L2CAP_CID_LE_DATA:
+               if (mtu < L2CAP_LE_MIN_MTU)
+                       return false;
+               break;
+
+       default:
+               if (mtu < L2CAP_DEFAULT_MIN_MTU)
+                       return false;
+       }
+
+       return true;
+}
+
 static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
@@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
+               if (!l2cap_valid_mtu(chan, opts.imtu)) {
+                       err = -EINVAL;
+                       break;
+               }
+
                chan->mode = opts.mode;
                switch (chan->mode) {
                case L2CAP_MODE_BASIC:
@@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock)
        return err;
 }
 
-static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
+static void l2cap_sock_cleanup_listen(struct sock *parent)
 {
-       struct sock *sk, *parent = data;
+       struct sock *sk;
+
+       BT_DBG("parent %p", parent);
+
+       /* Close not yet accepted channels */
+       while ((sk = bt_accept_dequeue(parent, NULL))) {
+               struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+               l2cap_chan_lock(chan);
+               __clear_chan_timer(chan);
+               l2cap_chan_close(chan, ECONNRESET);
+               l2cap_chan_unlock(chan);
+
+               l2cap_sock_kill(sk);
+       }
+}
+
+static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk, *parent = chan->data;
+
+       /* Check for backlog size */
+       if (sk_acceptq_is_full(parent)) {
+               BT_DBG("backlog full %d", parent->sk_ack_backlog);
+               return NULL;
+       }
 
        sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
                                                                GFP_ATOMIC);
@@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
        return l2cap_pi(sk)->chan;
 }
 
-static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
+static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
        int err;
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
 
        lock_sock(sk);
@@ -925,16 +970,57 @@ done:
        return err;
 }
 
-static void l2cap_sock_close_cb(void *data)
+static void l2cap_sock_close_cb(struct l2cap_chan *chan)
 {
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
 
        l2cap_sock_kill(sk);
 }
 
-static void l2cap_sock_state_change_cb(void *data, int state)
+static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
 {
-       struct sock *sk = data;
+       struct sock *sk = chan->data;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
+
+       sock_set_flag(sk, SOCK_ZAPPED);
+
+       switch (chan->state) {
+       case BT_OPEN:
+       case BT_BOUND:
+       case BT_CLOSED:
+               break;
+       case BT_LISTEN:
+               l2cap_sock_cleanup_listen(sk);
+               sk->sk_state = BT_CLOSED;
+               chan->state = BT_CLOSED;
+
+               break;
+       default:
+               sk->sk_state = BT_CLOSED;
+               chan->state = BT_CLOSED;
+
+               sk->sk_err = err;
+
+               if (parent) {
+                       bt_accept_unlink(sk);
+                       parent->sk_data_ready(parent, 0);
+               } else {
+                       sk->sk_state_change(sk);
+               }
+
+               break;
+       }
+
+       release_sock(sk);
+}
+
+static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state)
+{
+       struct sock *sk = chan->data;
 
        sk->sk_state = state;
 }
@@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
        return skb;
 }
 
+static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk = chan->data;
+       struct sock *parent;
+
+       lock_sock(sk);
+
+       parent = bt_sk(sk)->parent;
+
+       BT_DBG("sk %p, parent %p", sk, parent);
+
+       sk->sk_state = BT_CONNECTED;
+       sk->sk_state_change(sk);
+
+       if (parent)
+               parent->sk_data_ready(parent, 0);
+
+       release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
        .recv           = l2cap_sock_recv_cb,
        .close          = l2cap_sock_close_cb,
+       .teardown       = l2cap_sock_teardown_cb,
        .state_change   = l2cap_sock_state_change_cb,
+       .ready          = l2cap_sock_ready_cb,
        .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
index 506628876f3604dcdf9530852e6a27095dbf1f21..e1c97527e16ca352d4e55016b3a1f70b3e40d5b6 100644 (file)
 
 #define pr_fmt(fmt) "Bluetooth: " fmt
 
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <asm/errno.h>
+#include <linux/export.h>
 
 #include <net/bluetooth/bluetooth.h>
 
index 3e5e3362ea00443b8f1954c1487bf47625b6288f..a6e0f3d8da6cb21eb9391660fc5e2df121210050 100644 (file)
@@ -24,8 +24,6 @@
 
 /* Bluetooth HCI Management interface */
 
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
 #include <linux/module.h>
 #include <asm/unaligned.h>
 
@@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 }
 
 static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
-                                void (*cb)(struct pending_cmd *cmd, void *data),
+                                void (*cb)(struct pending_cmd *cmd,
+                                           void *data),
                                 void *data)
 {
        struct list_head *p, *n;
@@ -871,7 +870,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
+           mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
                                 MGMT_STATUS_BUSY);
                goto failed;
@@ -978,7 +977,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
+           mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
                                 MGMT_STATUS_BUSY);
                goto failed;
@@ -1001,7 +1000,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                scan = 0;
 
                if (test_bit(HCI_ISCAN, &hdev->flags) &&
-                                               hdev->discov_timeout > 0)
+                   hdev->discov_timeout > 0)
                        cancel_delayed_work(&hdev->discov_off);
        }
 
@@ -1056,7 +1055,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
                bool changed = false;
 
                if (!!cp->val != test_bit(HCI_LINK_SECURITY,
-                                                       &hdev->dev_flags)) {
+                                         &hdev->dev_flags)) {
                        change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
                        changed = true;
                }
@@ -1317,7 +1316,7 @@ static bool enable_service_cache(struct hci_dev *hdev)
 }
 
 static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
-                                                               u16 len)
+                      u16 len)
 {
        struct mgmt_cp_remove_uuid *cp = data;
        struct pending_cmd *cmd;
@@ -1442,7 +1441,7 @@ unlock:
 }
 
 static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
-                                                               u16 len)
+                         u16 len)
 {
        struct mgmt_cp_load_link_keys *cp = data;
        u16 key_count, expected_len;
@@ -1454,13 +1453,13 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
                                        sizeof(struct mgmt_link_key_info);
        if (expected_len != len) {
                BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
-                                                       len, expected_len);
+                      len, expected_len);
                return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
                                  MGMT_STATUS_INVALID_PARAMS);
        }
 
        BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
-                                                               key_count);
+              key_count);
 
        hci_dev_lock(hdev);
 
@@ -1535,10 +1534,10 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        if (cp->disconnect) {
                if (cp->addr.type == BDADDR_BREDR)
                        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
-                                                       &cp->addr.bdaddr);
+                                                      &cp->addr.bdaddr);
                else
                        conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
-                                                       &cp->addr.bdaddr);
+                                                      &cp->addr.bdaddr);
        } else {
                conn = NULL;
        }
@@ -1594,7 +1593,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        if (cp->addr.type == BDADDR_BREDR)
-               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                              &cp->addr.bdaddr);
        else
                conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
 
@@ -1813,7 +1813,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
        hdev->io_capability = cp->io_capability;
 
        BT_DBG("%s IO capability set to 0x%02x", hdev->name,
-                                                       hdev->io_capability);
+              hdev->io_capability);
 
        hci_dev_unlock(hdev);
 
@@ -1821,7 +1821,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
                            0);
 }
 
-static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
+static struct pending_cmd *find_pairing(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct pending_cmd *cmd;
@@ -1927,8 +1927,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        rp.addr.type = cp->addr.type;
 
        if (IS_ERR(conn)) {
+               int status;
+
+               if (PTR_ERR(conn) == -EBUSY)
+                       status = MGMT_STATUS_BUSY;
+               else
+                       status = MGMT_STATUS_CONNECT_FAILED;
+
                err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
-                                  MGMT_STATUS_CONNECT_FAILED, &rp,
+                                  status, &rp,
                                   sizeof(rp));
                goto unlock;
        }
@@ -1959,7 +1966,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        cmd->user_data = conn;
 
        if (conn->state == BT_CONNECTED &&
-                               hci_conn_security(conn, sec_level, auth_type))
+           hci_conn_security(conn, sec_level, auth_type))
                pairing_complete(cmd, 0);
 
        err = 0;
@@ -2256,7 +2263,7 @@ unlock:
 }
 
 static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
-                                               void *data, u16 len)
+                                 void *data, u16 len)
 {
        struct mgmt_cp_remove_remote_oob_data *cp = data;
        u8 status;
@@ -2425,7 +2432,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
 
        case DISCOVERY_RESOLVING:
                e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
-                                                       NAME_PENDING);
+                                                    NAME_PENDING);
                if (!e) {
                        mgmt_pending_remove(cmd);
                        err = cmd_complete(sk, hdev->id,
@@ -2647,7 +2654,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                                        sizeof(struct mgmt_ltk_info);
        if (expected_len != len) {
                BT_ERR("load_keys: expected %u bytes, got %u bytes",
-                                                       len, expected_len);
+                      len, expected_len);
                return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
                                  EINVAL);
        }
@@ -2772,7 +2779,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        }
 
        if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
-                                       mgmt_handlers[opcode].func == NULL) {
+           mgmt_handlers[opcode].func == NULL) {
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_UNKNOWN_COMMAND);
@@ -2780,7 +2787,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        }
 
        if ((hdev && opcode < MGMT_OP_READ_INFO) ||
-                       (!hdev && opcode >= MGMT_OP_READ_INFO)) {
+           (!hdev && opcode >= MGMT_OP_READ_INFO)) {
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_INVALID_INDEX);
                goto done;
@@ -2789,7 +2796,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        handler = &mgmt_handlers[opcode];
 
        if ((handler->var_len && len < handler->data_len) ||
-                       (!handler->var_len && len != handler->data_len)) {
+           (!handler->var_len && len != handler->data_len)) {
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_INVALID_PARAMS);
                goto done;
@@ -2973,7 +2980,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
        bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
        ev.key.addr.type = BDADDR_BREDR;
        ev.key.type = key->type;
-       memcpy(ev.key.val, key->val, 16);
+       memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
        ev.key.pin_len = key->pin_len;
 
        return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
@@ -3108,7 +3115,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
        mgmt_pending_remove(cmd);
 
        mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
-                                                                       hdev);
+                            hdev);
        return err;
 }
 
@@ -3198,7 +3205,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                               u8 link_type, u8 addr_type)
+                             u8 link_type, u8 addr_type)
 {
        struct mgmt_ev_user_passkey_request ev;
 
@@ -3212,8 +3219,8 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                       u8 link_type, u8 addr_type, u8 status,
-                                       u8 opcode)
+                                     u8 link_type, u8 addr_type, u8 status,
+                                     u8 opcode)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
@@ -3244,7 +3251,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                         u8 link_type, u8 addr_type, u8 status)
 {
        return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
-                                         status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
+                                         status,
+                                         MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
 int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -3258,7 +3266,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                         u8 link_type, u8 addr_type, u8 status)
 {
        return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
-                                         status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
+                                         status,
+                                         MGMT_OP_USER_PASSKEY_NEG_REPLY);
 }
 
 int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
index 8a602388f1e73c185aa24499e9ff636c9358fcee..c75107ef89204877315ea8d61248c2fa4e2bddd2 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/net.h>
-#include <linux/mutex.h>
 #include <linux/kthread.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -115,14 +101,14 @@ static void rfcomm_session_del(struct rfcomm_session *s);
 #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
 #define __get_rpn_parity(line)    (((line) >> 3) & 0x7)
 
-static inline void rfcomm_schedule(void)
+static void rfcomm_schedule(void)
 {
        if (!rfcomm_thread)
                return;
        wake_up_process(rfcomm_thread);
 }
 
-static inline void rfcomm_session_put(struct rfcomm_session *s)
+static void rfcomm_session_put(struct rfcomm_session *s)
 {
        if (atomic_dec_and_test(&s->refcnt))
                rfcomm_session_del(s);
@@ -227,7 +213,7 @@ static int rfcomm_l2sock_create(struct socket **sock)
        return err;
 }
 
-static inline int rfcomm_check_security(struct rfcomm_dlc *d)
+static int rfcomm_check_security(struct rfcomm_dlc *d)
 {
        struct sock *sk = d->session->sock->sk;
        struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
@@ -1750,7 +1736,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
 /* Send data queued for the DLC.
  * Return number of frames left in the queue.
  */
-static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
+static int rfcomm_process_tx(struct rfcomm_dlc *d)
 {
        struct sk_buff *skb;
        int err;
@@ -1798,7 +1784,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
        return skb_queue_len(&d->tx_queue);
 }
 
-static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+static void rfcomm_process_dlcs(struct rfcomm_session *s)
 {
        struct rfcomm_dlc *d;
        struct list_head *p, *n;
@@ -1858,7 +1844,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_process_rx(struct rfcomm_session *s)
+static void rfcomm_process_rx(struct rfcomm_session *s)
 {
        struct socket *sock = s->sock;
        struct sock *sk = sock->sk;
@@ -1883,7 +1869,7 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_accept_connection(struct rfcomm_session *s)
+static void rfcomm_accept_connection(struct rfcomm_session *s)
 {
        struct socket *sock = s->sock, *nsock;
        int err;
@@ -1917,7 +1903,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
                sock_release(nsock);
 }
 
-static inline void rfcomm_check_connection(struct rfcomm_session *s)
+static void rfcomm_check_connection(struct rfcomm_session *s)
 {
        struct sock *sk = s->sock->sk;
 
@@ -1941,7 +1927,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
        }
 }
 
-static inline void rfcomm_process_sessions(void)
+static void rfcomm_process_sessions(void)
 {
        struct list_head *p, *n;
 
index e8707debb8642cff6cc08755a6400134bcf5b8c7..7e1e59645c056f71400ad9ed4dc0444548c41951 100644 (file)
  * RFCOMM sockets.
  */
 
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/list.h>
-#include <linux/device.h>
+#include <linux/export.h>
 #include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
index d1820ff14aee46cfc55cd1c169495004c3130818..cb960773c002efafeb45b888ee8f3ba3e9208490 100644 (file)
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 
-#include <linux/capability.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/rfcomm.h>
@@ -132,7 +127,7 @@ static struct rfcomm_dev *__rfcomm_dev_get(int id)
        return NULL;
 }
 
-static inline struct rfcomm_dev *rfcomm_dev_get(int id)
+static struct rfcomm_dev *rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
 
@@ -345,7 +340,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
        tty_port_put(&dev->port);
 }
 
-static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
+static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
        tty_port_get(&dev->port);
        atomic_add(skb->truesize, &dev->wmem_alloc);
index cbdd313659a78f3bf9133d10ee01e487fd2d9053..40bbe25dcff7f97c9a279c6d087eaed078563364 100644 (file)
 /* Bluetooth SCO sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/device.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/list.h>
-#include <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -123,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
        return conn;
 }
 
-static inline struct sock *sco_chan_get(struct sco_conn *conn)
+static struct sock *sco_chan_get(struct sco_conn *conn)
 {
        struct sock *sk = NULL;
        sco_conn_lock(conn);
@@ -157,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        return 0;
 }
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+                       struct sock *parent)
 {
        int err = 0;
 
@@ -228,7 +211,7 @@ done:
        return err;
 }
 
-static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 {
        struct sco_conn *conn = sco_pi(sk)->conn;
        struct sk_buff *skb;
@@ -254,7 +237,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
        return len;
 }
 
-static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 {
        struct sock *sk = sco_chan_get(conn);
 
@@ -523,7 +506,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
                goto done;
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
 done:
        release_sock(sk);
@@ -788,7 +771,7 @@ static int sco_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
        release_sock(sk);
        return err;
@@ -878,7 +861,7 @@ static void sco_conn_ready(struct sco_conn *conn)
                bh_lock_sock(parent);
 
                sk = sco_sock_alloc(sock_net(parent), NULL,
-                               BTPROTO_SCO, GFP_ATOMIC);
+                                   BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
                        goto done;
@@ -907,7 +890,7 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       register struct sock *sk;
+       struct sock *sk;
        struct hlist_node *node;
        int lm = 0;
 
@@ -920,7 +903,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
-                               !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                   !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm |= HCI_LM_ACCEPT;
                        break;
                }
@@ -981,7 +964,7 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
 
        sk_for_each(sk, node, &sco_sk_list.head) {
                seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-                               batostr(&bt_sk(sk)->dst), sk->sk_state);
+                          batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
        read_unlock(&sco_sk_list.lock);
@@ -1044,8 +1027,8 @@ int __init sco_init(void)
        }
 
        if (bt_debugfs) {
-               sco_debugfs = debugfs_create_file("sco", 0444,
-                                       bt_debugfs, NULL, &sco_debugfs_fops);
+               sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
+                                                 NULL, &sco_debugfs_fops);
                if (!sco_debugfs)
                        BT_ERR("Failed to create SCO debug file");
        }
index 37df4e9b3896435164adf36a0c52b8ab8c08030c..16ef0dc85a0a87580c311563028cc567fa826bce 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <crypto/b128ops.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/mgmt.h>
 #include <net/bluetooth/smp.h>
-#include <linux/crypto.h>
-#include <linux/scatterlist.h>
-#include <crypto/b128ops.h>
 
 #define SMP_TIMEOUT    msecs_to_jiffies(30000)
 
index fdf9e61d0651fab74e2836593a872586cd8efec3..72607174ea5a4af158855f588b767b5c4c86d973 100644 (file)
@@ -417,72 +417,6 @@ static struct attribute_group netstat_group = {
        .name  = "statistics",
        .attrs  = netstat_attrs,
 };
-
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
-/* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct device *d, char *buf,
-                            ssize_t (*format)(const struct iw_statistics *,
-                                              char *))
-{
-       struct net_device *dev = to_net_dev(d);
-       const struct iw_statistics *iw;
-       ssize_t ret = -EINVAL;
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-       if (dev_isalive(dev)) {
-               iw = get_wireless_stats(dev);
-               if (iw)
-                       ret = (*format)(iw, buf);
-       }
-       rtnl_unlock();
-
-       return ret;
-}
-
-/* show function template for wireless fields */
-#define WIRELESS_SHOW(name, field, format_string)                      \
-static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
-{                                                                      \
-       return sprintf(buf, format_string, iw->field);                  \
-}                                                                      \
-static ssize_t show_iw_##name(struct device *d,                                \
-                             struct device_attribute *attr, char *buf) \
-{                                                                      \
-       return wireless_show(d, buf, format_iw_##name);                 \
-}                                                                      \
-static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
-
-WIRELESS_SHOW(status, status, fmt_hex);
-WIRELESS_SHOW(link, qual.qual, fmt_dec);
-WIRELESS_SHOW(level, qual.level, fmt_dec);
-WIRELESS_SHOW(noise, qual.noise, fmt_dec);
-WIRELESS_SHOW(nwid, discard.nwid, fmt_dec);
-WIRELESS_SHOW(crypt, discard.code, fmt_dec);
-WIRELESS_SHOW(fragment, discard.fragment, fmt_dec);
-WIRELESS_SHOW(misc, discard.misc, fmt_dec);
-WIRELESS_SHOW(retries, discard.retries, fmt_dec);
-WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
-
-static struct attribute *wireless_attrs[] = {
-       &dev_attr_status.attr,
-       &dev_attr_link.attr,
-       &dev_attr_level.attr,
-       &dev_attr_noise.attr,
-       &dev_attr_nwid.attr,
-       &dev_attr_crypt.attr,
-       &dev_attr_fragment.attr,
-       &dev_attr_retries.attr,
-       &dev_attr_misc.attr,
-       &dev_attr_beacon.attr,
-       NULL
-};
-
-static struct attribute_group wireless_group = {
-       .name = "wireless",
-       .attrs = wireless_attrs,
-};
-#endif
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_RPS
@@ -1463,14 +1397,6 @@ int netdev_register_kobject(struct net_device *net)
                groups++;
 
        *groups++ = &netstat_group;
-#ifdef CONFIG_WIRELESS_EXT_SYSFS
-       if (net->ieee80211_ptr)
-               *groups++ = &wireless_group;
-#ifdef CONFIG_WIRELESS_EXT
-       else if (net->wireless_handlers)
-               *groups++ = &wireless_group;
-#endif
-#endif
 #endif /* CONFIG_SYSFS */
 
        error = device_add(dev);
index 8d249d70598048741157faff91ca28c7389e4591..63af25458fdad7afd6ec253ac365a35d26772dbd 100644 (file)
@@ -107,6 +107,19 @@ config MAC80211_DEBUGFS
 
          Say N unless you know you need this.
 
+config MAC80211_MESSAGE_TRACING
+       bool "Trace all mac80211 debug messages"
+       depends on MAC80211
+       ---help---
+         Select this option to have mac80211 register the
+         mac80211_msg trace subsystem with tracepoints to
+         collect all debugging messages, independent of
+         printing them into the kernel log.
+
+         The overhead in this option is that all the messages
+         need to be present in the binary and formatted at
+         runtime for tracing.
+
 menuconfig MAC80211_DEBUG_MENU
        bool "Select mac80211 debugging features"
        depends on MAC80211
@@ -140,26 +153,35 @@ config MAC80211_VERBOSE_DEBUG
 
          Do not select this option.
 
-config MAC80211_HT_DEBUG
-       bool "Verbose HT debugging"
+config MAC80211_MLME_DEBUG
+       bool "Verbose managed MLME output"
        depends on MAC80211_DEBUG_MENU
        ---help---
-         This option enables 802.11n High Throughput features
-         debug tracing output.
-
-         It should not be selected on production systems as some
+         Selecting this option causes mac80211 to print out
+         debugging messages for the managed-mode MLME. It
+         should not be selected on production systems as some
          of the messages are remotely triggerable.
 
          Do not select this option.
 
-config MAC80211_TKIP_DEBUG
-       bool "Verbose TKIP debugging"
+config MAC80211_STA_DEBUG
+       bool "Verbose station debugging"
        depends on MAC80211_DEBUG_MENU
        ---help---
          Selecting this option causes mac80211 to print out
-         very verbose TKIP debugging messages. It should not
-         be selected on production systems as those messages
-         are remotely triggerable.
+         debugging messages for station addition/removal.
+
+         Do not select this option.
+
+config MAC80211_HT_DEBUG
+       bool "Verbose HT debugging"
+       depends on MAC80211_DEBUG_MENU
+       ---help---
+         This option enables 802.11n High Throughput features
+         debug tracing output.
+
+         It should not be selected on production systems as some
+         of the messages are remotely triggerable.
 
          Do not select this option.
 
@@ -174,7 +196,7 @@ config MAC80211_IBSS_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_PS_DEBUG
+config MAC80211_PS_DEBUG
        bool "Verbose powersave mode debugging"
        depends on MAC80211_DEBUG_MENU
        ---help---
@@ -186,7 +208,7 @@ config MAC80211_VERBOSE_PS_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_MPL_DEBUG
+config MAC80211_MPL_DEBUG
        bool "Verbose mesh peer link debugging"
        depends on MAC80211_DEBUG_MENU
        depends on MAC80211_MESH
@@ -199,7 +221,7 @@ config MAC80211_VERBOSE_MPL_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_MPATH_DEBUG
+config MAC80211_MPATH_DEBUG
        bool "Verbose mesh path debugging"
        depends on MAC80211_DEBUG_MENU
        depends on MAC80211_MESH
@@ -212,7 +234,7 @@ config MAC80211_VERBOSE_MPATH_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_MHWMP_DEBUG
+config MAC80211_MHWMP_DEBUG
        bool "Verbose mesh HWMP routing debugging"
        depends on MAC80211_DEBUG_MENU
        depends on MAC80211_MESH
@@ -225,7 +247,7 @@ config MAC80211_VERBOSE_MHWMP_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_MESH_SYNC_DEBUG
+config MAC80211_MESH_SYNC_DEBUG
        bool "Verbose mesh mesh synchronization debugging"
        depends on MAC80211_DEBUG_MENU
        depends on MAC80211_MESH
@@ -236,7 +258,7 @@ config MAC80211_VERBOSE_MESH_SYNC_DEBUG
 
          Do not select this option.
 
-config MAC80211_VERBOSE_TDLS_DEBUG
+config MAC80211_TDLS_DEBUG
        bool "Verbose TDLS debugging"
        depends on MAC80211_DEBUG_MENU
        ---help---
index 3e9d931bba3542a884d1892ecf7e464435b7516a..a7dd110faafaf80509d75849ce982744af41d2b2 100644 (file)
@@ -9,7 +9,6 @@ mac80211-y := \
        scan.o offchannel.o \
        ht.o agg-tx.o agg-rx.o \
        ibss.o \
-       work.o \
        iface.o \
        rate.o \
        michael.o \
@@ -25,7 +24,7 @@ mac80211-y := \
        wme.o \
        event.o \
        chan.o \
-       driver-trace.o mlme.o
+       trace.o mlme.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
@@ -43,7 +42,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
 
 mac80211-$(CONFIG_PM) += pm.o
 
-CFLAGS_driver-trace.o := -I$(src)
+CFLAGS_trace.o := -I$(src)
 
 # objects for PID algorithm
 rc80211_pid-y := rc80211_pid_algo.o
@@ -59,4 +58,4 @@ mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
 mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
 mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
 
-ccflags-y += -D__CHECK_ENDIAN__
+ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG
index c649188314cce99c17fca198e75d597c24701197..186d9919b043cc41fbaea7aee56e0cb5e688bf94 100644 (file)
@@ -74,18 +74,17 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
        RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG
+       ht_dbg(sta->sdata,
               "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
               sta->sta.addr, tid,
               initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
               (int)reason);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
                             &sta->sta, tid, NULL, 0))
-               printk(KERN_DEBUG "HW problem - can not stop rx "
-                               "aggregation for tid %d\n", tid);
+               sdata_info(sta->sdata,
+                          "HW problem - can not stop rx aggregation for tid %d\n",
+                          tid);
 
        /* check if this is a self generated aggregation halt */
        if (initiator == WLAN_BACK_RECIPIENT && tx)
@@ -160,9 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
        }
        rcu_read_unlock();
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+       ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid);
+
        set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
        ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
@@ -249,10 +247,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        status = WLAN_STATUS_REQUEST_DECLINED;
 
        if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Suspend in progress. "
-                      "Denying ADDBA request\n");
-#endif
+               ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n");
                goto end_no_lock;
        }
 
@@ -264,10 +259,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
             (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
            (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
                status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               net_dbg_ratelimited("AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
-                                   mgmt->sa, tid, ba_policy, buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg_ratelimited(sta->sdata,
+                                  "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
+                                  mgmt->sa, tid, ba_policy, buf_size);
                goto end_no_lock;
        }
        /* determine default buffer size */
@@ -282,10 +276,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        mutex_lock(&sta->ampdu_mlme.mtx);
 
        if (sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               net_dbg_ratelimited("unexpected AddBA Req from %pM on tid %u\n",
-                                   mgmt->sa, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg_ratelimited(sta->sdata,
+                                  "unexpected AddBA Req from %pM on tid %u\n",
+                                  mgmt->sa, tid);
 
                /* delete existing Rx BA session on the same tid */
                ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
@@ -324,10 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
        ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
                               &sta->sta, tid, &start_seq_num, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
+       ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret);
        if (ret) {
                kfree(tid_agg_rx->reorder_buf);
                kfree(tid_agg_rx->reorder_time);
index 7cf07158805c198e827af160a9f705881c4b20fa..5cc1bf7d803336619a39f7e2e7370829db6aa230 100644 (file)
@@ -184,10 +184,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        spin_unlock_bh(&sta->lock);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+       ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n",
               sta->sta.addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
        del_timer_sync(&tid_tx->addba_resp_timer);
        del_timer_sync(&tid_tx->session_timer);
@@ -253,17 +251,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)
        if (!tid_tx ||
            test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
                rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "timer expired on tid %d but we are not "
-                               "(or no longer) expecting addBA response there\n",
-                       tid);
-#endif
+               ht_dbg(sta->sdata,
+                      "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n",
+                      tid);
                return;
        }
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid);
 
        ieee80211_stop_tx_ba_session(&sta->sta, tid);
        rcu_read_unlock();
@@ -323,8 +317,9 @@ ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_stop_queue_agg(sdata, tid);
 
-       if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
-                         " from the pending queue\n", tid))
+       if (WARN(!tid_tx,
+                "TID %d gone but expected when splicing aggregates from the pending queue\n",
+                tid))
                return;
 
        if (!skb_queue_empty(&tid_tx->pending)) {
@@ -372,10 +367,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
        ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
                               &sta->sta, tid, &start_seq_num, 0);
        if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - HW unavailable for"
-                                       " tid %d\n", tid);
-#endif
+               ht_dbg(sdata,
+                      "BA request denied - HW unavailable for tid %d\n", tid);
                spin_lock_bh(&sta->lock);
                ieee80211_agg_splice_packets(sdata, tid_tx, tid);
                ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -388,9 +381,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 
        /* activate the timer for the recipient's addBA response */
        mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
+       ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid);
 
        spin_lock_bh(&sta->lock);
        sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
@@ -437,9 +428,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
 
        rcu_read_unlock();
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
-#endif
+       ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid);
 
        ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
 }
@@ -463,10 +452,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
            (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
                return -EINVAL;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+       ht_dbg(sdata, "Open BA session requested for %pM tid %u\n",
               pubsta->addr, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
            sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
@@ -476,10 +463,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                return -EINVAL;
 
        if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA sessions blocked. "
-                      "Denying BA session request\n");
-#endif
+               ht_dbg(sdata,
+                      "BA sessions blocked - Denying BA session request\n");
                return -EINVAL;
        }
 
@@ -497,10 +482,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
         */
        if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
            !sta->sta.ht_cap.ht_supported) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
-                      "does not advertise HT support\n", pubsta->addr);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg(sdata,
+                      "BA request denied - IBSS STA %pM does not advertise HT support\n",
+                      pubsta->addr);
                return -EINVAL;
        }
 
@@ -520,12 +504,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
            time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
                        HT_AGG_RETRIES_PERIOD)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - "
-                      "waiting a grace period after %d failed requests "
-                      "on tid %u\n",
+               ht_dbg(sdata,
+                      "BA request denied - waiting a grace period after %d failed requests on tid %u\n",
                       sta->ampdu_mlme.addba_req_num[tid], tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
                ret = -EBUSY;
                goto err_unlock_sta;
        }
@@ -533,10 +514,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        /* check if the TID is not in aggregation flow already */
        if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "BA request denied - session is not "
-                                "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+               ht_dbg(sdata,
+                      "BA request denied - session is not idle on tid %u\n",
+                      tid);
                ret = -EAGAIN;
                goto err_unlock_sta;
        }
@@ -591,9 +571,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid);
 
        drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
@@ -627,10 +605,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        trace_api_start_tx_ba_cb(sdata, ra, tid);
 
        if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-                               tid, STA_TID_NUM);
-#endif
+               ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+                      tid, STA_TID_NUM);
                return;
        }
 
@@ -638,9 +614,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
                mutex_unlock(&local->sta_mtx);
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+               ht_dbg(sdata, "Could not find station: %pM\n", ra);
                return;
        }
 
@@ -648,9 +622,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (WARN_ON(!tid_tx)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "addBA was not requested!\n");
-#endif
+               ht_dbg(sdata, "addBA was not requested!\n");
                goto unlock;
        }
 
@@ -750,25 +722,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
        trace_api_stop_tx_ba_cb(sdata, ra, tid);
 
        if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
-                               tid, STA_TID_NUM);
-#endif
+               ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
+                      tid, STA_TID_NUM);
                return;
        }
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
-              ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+       ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid);
 
        mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
+               ht_dbg(sdata, "Could not find station: %pM\n", ra);
                goto unlock;
        }
 
@@ -777,9 +742,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
+               ht_dbg(sdata, "unexpected callback to A-MPDU stop\n");
                goto unlock_sta;
        }
 
@@ -855,17 +818,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                goto out;
 
        if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif
+               ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid);
                goto out;
        }
 
        del_timer_sync(&tid_tx->addba_resp_timer);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
-#endif
+       ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid);
 
        /*
         * addba_resp_timer may have fired before we got here, and
@@ -874,11 +833,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
         */
        if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
            test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-               printk(KERN_DEBUG
+               ht_dbg(sta->sdata,
                       "got addBA resp for tid %d but we already gave up\n",
                       tid);
-#endif
                goto out;
        }
 
index 7d5108a867ad9ec5341fc5122a2b65cd792846c3..c2a2dcbfdf017abc788b58dd3744e3e7a390a18e 100644 (file)
@@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta,
 static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
        struct timespec uptime;
 
        sinfo->generation = sdata->local->sta_generation;
@@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
            (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
                sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
-               sinfo->signal = (s8)sta->last_signal;
+               if (!local->ops->get_rssi ||
+                   drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
+                       sinfo->signal = (s8)sta->last_signal;
                sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
        }
 
@@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
         * network device.
         */
 
-       rcu_read_lock();
+       mutex_lock(&local->sta_mtx);
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
@@ -546,7 +549,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                        data[i] = (u8)sinfo.signal_avg;
                i++;
        } else {
-               list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               list_for_each_entry(sta, &local->sta_list, list) {
                        /* Make sure this station belongs to the proper dev */
                        if (sta->sdata->dev != dev)
                                continue;
@@ -603,7 +606,7 @@ do_survey:
        else
                data[i++] = -1LL;
 
-       rcu_read_unlock();
+       mutex_unlock(&local->sta_mtx);
 
        if (WARN_ON(i != STA_STATS_LEN))
                return;
@@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
                                 int idx, u8 *mac, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        int ret = -ENOENT;
 
-       rcu_read_lock();
+       mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_by_idx(sdata, idx);
        if (sta) {
@@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
                sta_set_sinfo(sta, sinfo);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&local->sta_mtx);
 
        return ret;
 }
@@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        int ret = -ENOENT;
 
-       rcu_read_lock();
+       mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_bss(sdata, mac);
        if (sta) {
@@ -669,11 +674,54 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                sta_set_sinfo(sta, sinfo);
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&local->sta_mtx);
 
        return ret;
 }
 
+static int ieee80211_set_channel(struct wiphy *wiphy,
+                                struct net_device *netdev,
+                                struct ieee80211_channel *chan,
+                                enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = NULL;
+
+       if (netdev)
+               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+       switch (ieee80211_get_channel_mode(local, NULL)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel != chan ||
+                   (!sdata && local->_oper_channel_type != channel_type))
+                       return -EBUSY;
+               if (!sdata && local->_oper_channel_type == channel_type)
+                       return 0;
+               break;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
+
+       if (!ieee80211_set_channel_type(local, sdata, channel_type))
+               return -EBUSY;
+
+       local->oper_channel = chan;
+
+       /* auto-detects changes */
+       ieee80211_hw_config(local, 0);
+
+       return 0;
+}
+
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+                                        struct ieee80211_channel *chan,
+                                        enum nl80211_channel_type channel_type)
+{
+       return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
 static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
                                    const u8 *resp, size_t resp_len)
 {
@@ -788,6 +836,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
+       err = ieee80211_set_channel(wiphy, dev, params->channel,
+                                   params->channel_type);
+       if (err)
+               return err;
+
        /*
         * Apply control port protocol, this allows us to
         * not encrypt dynamic WEP control frames.
@@ -1482,7 +1535,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
        if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
                conf->dot11MeshTTL = nconf->dot11MeshTTL;
        if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
-               conf->dot11MeshTTL = nconf->element_ttl;
+               conf->element_ttl = nconf->element_ttl;
        if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
                conf->auto_open_plinks = nconf->auto_open_plinks;
        if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
@@ -1517,17 +1570,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
                 * announcements, so require this ifmsh to also be a root node
                 * */
                if (nconf->dot11MeshGateAnnouncementProtocol &&
-                   !conf->dot11MeshHWMPRootMode) {
-                       conf->dot11MeshHWMPRootMode = 1;
+                   !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) {
+                       conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN;
                        ieee80211_mesh_root_setup(ifmsh);
                }
                conf->dot11MeshGateAnnouncementProtocol =
                        nconf->dot11MeshGateAnnouncementProtocol;
        }
-       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask))
                conf->dot11MeshHWMPRannInterval =
                        nconf->dot11MeshHWMPRannInterval;
-       }
        if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask))
                conf->dot11MeshForwarding = nconf->dot11MeshForwarding;
        if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) {
@@ -1543,6 +1595,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
                sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode;
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
        }
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask))
+               conf->dot11MeshHWMPactivePathToRootTimeout =
+                       nconf->dot11MeshHWMPactivePathToRootTimeout;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask))
+               conf->dot11MeshHWMProotInterval =
+                       nconf->dot11MeshHWMProotInterval;
+       if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask))
+               conf->dot11MeshHWMPconfirmationInterval =
+                       nconf->dot11MeshHWMPconfirmationInterval;
        return 0;
 }
 
@@ -1558,6 +1619,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        err = copy_mesh_setup(ifmsh, setup);
        if (err)
                return err;
+
+       err = ieee80211_set_channel(wiphy, dev, setup->channel,
+                                   setup->channel_type);
+       if (err)
+               return err;
+
        ieee80211_start_mesh(sdata);
 
        return 0;
@@ -1677,55 +1744,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        return 0;
 }
 
-static int ieee80211_set_channel(struct wiphy *wiphy,
-                                struct net_device *netdev,
-                                struct ieee80211_channel *chan,
-                                enum nl80211_channel_type channel_type)
-{
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_sub_if_data *sdata = NULL;
-       struct ieee80211_channel *old_oper;
-       enum nl80211_channel_type old_oper_type;
-       enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
-
-       if (netdev)
-               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
-       switch (ieee80211_get_channel_mode(local, NULL)) {
-       case CHAN_MODE_HOPPING:
-               return -EBUSY;
-       case CHAN_MODE_FIXED:
-               if (local->oper_channel != chan)
-                       return -EBUSY;
-               if (!sdata && local->_oper_channel_type == channel_type)
-                       return 0;
-               break;
-       case CHAN_MODE_UNDEFINED:
-               break;
-       }
-
-       if (sdata)
-               old_vif_oper_type = sdata->vif.bss_conf.channel_type;
-       old_oper_type = local->_oper_channel_type;
-
-       if (!ieee80211_set_channel_type(local, sdata, channel_type))
-               return -EBUSY;
-
-       old_oper = local->oper_channel;
-       local->oper_channel = chan;
-
-       /* Update driver if changes were actually made. */
-       if ((old_oper != local->oper_channel) ||
-           (old_oper_type != local->_oper_channel_type))
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
-       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-           old_vif_oper_type != sdata->vif.bss_conf.channel_type)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static int ieee80211_suspend(struct wiphy *wiphy,
                             struct cfg80211_wowlan *wowlan)
@@ -2111,35 +2129,171 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
        return 0;
 }
 
-static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local,
-                                         struct net_device *dev,
-                                         struct ieee80211_channel *chan,
-                                         enum nl80211_channel_type chantype,
-                                         unsigned int duration, u64 *cookie)
+static int ieee80211_start_roc_work(struct ieee80211_local *local,
+                                   struct ieee80211_sub_if_data *sdata,
+                                   struct ieee80211_channel *channel,
+                                   enum nl80211_channel_type channel_type,
+                                   unsigned int duration, u64 *cookie,
+                                   struct sk_buff *txskb)
 {
+       struct ieee80211_roc_work *roc, *tmp;
+       bool queued = false;
        int ret;
-       u32 random_cookie;
 
        lockdep_assert_held(&local->mtx);
 
-       if (local->hw_roc_cookie)
-               return -EBUSY;
-       /* must be nonzero */
-       random_cookie = random32() | 1;
-
-       *cookie = random_cookie;
-       local->hw_roc_dev = dev;
-       local->hw_roc_cookie = random_cookie;
-       local->hw_roc_channel = chan;
-       local->hw_roc_channel_type = chantype;
-       local->hw_roc_duration = duration;
-       ret = drv_remain_on_channel(local, chan, chantype, duration);
+       roc = kzalloc(sizeof(*roc), GFP_KERNEL);
+       if (!roc)
+               return -ENOMEM;
+
+       roc->chan = channel;
+       roc->chan_type = channel_type;
+       roc->duration = duration;
+       roc->req_duration = duration;
+       roc->frame = txskb;
+       roc->mgmt_tx_cookie = (unsigned long)txskb;
+       roc->sdata = sdata;
+       INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
+       INIT_LIST_HEAD(&roc->dependents);
+
+       /* if there's one pending or we're scanning, queue this one */
+       if (!list_empty(&local->roc_list) || local->scanning)
+               goto out_check_combine;
+
+       /* if not HW assist, just queue & schedule work */
+       if (!local->ops->remain_on_channel) {
+               ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+               goto out_queue;
+       }
+
+       /* otherwise actually kick it off here (for error handling) */
+
+       /*
+        * If the duration is zero, then the driver
+        * wouldn't actually do anything. Set it to
+        * 10 for now.
+        *
+        * TODO: cancel the off-channel operation
+        *       when we get the SKB's TX status and
+        *       the wait time was zero before.
+        */
+       if (!duration)
+               duration = 10;
+
+       ret = drv_remain_on_channel(local, channel, channel_type, duration);
        if (ret) {
-               local->hw_roc_channel = NULL;
-               local->hw_roc_cookie = 0;
+               kfree(roc);
+               return ret;
        }
 
-       return ret;
+       roc->started = true;
+       goto out_queue;
+
+ out_check_combine:
+       list_for_each_entry(tmp, &local->roc_list, list) {
+               if (tmp->chan != channel || tmp->chan_type != channel_type)
+                       continue;
+
+               /*
+                * Extend this ROC if possible:
+                *
+                * If it hasn't started yet, just increase the duration
+                * and add the new one to the list of dependents.
+                */
+               if (!tmp->started) {
+                       list_add_tail(&roc->list, &tmp->dependents);
+                       tmp->duration = max(tmp->duration, roc->duration);
+                       queued = true;
+                       break;
+               }
+
+               /* If it has already started, it's more difficult ... */
+               if (local->ops->remain_on_channel) {
+                       unsigned long j = jiffies;
+
+                       /*
+                        * In the offloaded ROC case, if it hasn't begun, add
+                        * this new one to the dependent list to be handled
+                        * when the the master one begins. If it has begun,
+                        * check that there's still a minimum time left and
+                        * if so, start this one, transmitting the frame, but
+                        * add it to the list directly after this one with a
+                        * a reduced time so we'll ask the driver to execute
+                        * it right after finishing the previous one, in the
+                        * hope that it'll also be executed right afterwards,
+                        * effectively extending the old one.
+                        * If there's no minimum time left, just add it to the
+                        * normal list.
+                        */
+                       if (!tmp->hw_begun) {
+                               list_add_tail(&roc->list, &tmp->dependents);
+                               queued = true;
+                               break;
+                       }
+
+                       if (time_before(j + IEEE80211_ROC_MIN_LEFT,
+                                       tmp->hw_start_time +
+                                       msecs_to_jiffies(tmp->duration))) {
+                               int new_dur;
+
+                               ieee80211_handle_roc_started(roc);
+
+                               new_dur = roc->duration -
+                                         jiffies_to_msecs(tmp->hw_start_time +
+                                                          msecs_to_jiffies(
+                                                               tmp->duration) -
+                                                          j);
+
+                               if (new_dur > 0) {
+                                       /* add right after tmp */
+                                       list_add(&roc->list, &tmp->list);
+                               } else {
+                                       list_add_tail(&roc->list,
+                                                     &tmp->dependents);
+                               }
+                               queued = true;
+                       }
+               } else if (del_timer_sync(&tmp->work.timer)) {
+                       unsigned long new_end;
+
+                       /*
+                        * In the software ROC case, cancel the timer, if
+                        * that fails then the finish work is already
+                        * queued/pending and thus we queue the new ROC
+                        * normally, if that succeeds then we can extend
+                        * the timer duration and TX the frame (if any.)
+                        */
+
+                       list_add_tail(&roc->list, &tmp->dependents);
+                       queued = true;
+
+                       new_end = jiffies + msecs_to_jiffies(roc->duration);
+
+                       /* ok, it was started & we canceled timer */
+                       if (time_after(new_end, tmp->work.timer.expires))
+                               mod_timer(&tmp->work.timer, new_end);
+                       else
+                               add_timer(&tmp->work.timer);
+
+                       ieee80211_handle_roc_started(roc);
+               }
+               break;
+       }
+
+ out_queue:
+       if (!queued)
+               list_add_tail(&roc->list, &local->roc_list);
+
+       /*
+        * cookie is either the roc (for normal roc)
+        * or the SKB (for mgmt TX)
+        */
+       if (txskb)
+               *cookie = (unsigned long)txskb;
+       else
+               *cookie = (unsigned long)roc;
+
+       return 0;
 }
 
 static int ieee80211_remain_on_channel(struct wiphy *wiphy,
@@ -2151,86 +2305,98 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       int ret;
 
-       if (local->ops->remain_on_channel) {
-               int ret;
-
-               mutex_lock(&local->mtx);
-               ret = ieee80211_remain_on_channel_hw(local, dev,
-                                                    chan, channel_type,
-                                                    duration, cookie);
-               local->hw_roc_for_tx = false;
-               mutex_unlock(&local->mtx);
-
-               return ret;
-       }
+       mutex_lock(&local->mtx);
+       ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+                                      duration, cookie, NULL);
+       mutex_unlock(&local->mtx);
 
-       return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
-                                             duration, cookie);
+       return ret;
 }
 
-static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
-                                                u64 cookie)
+static int ieee80211_cancel_roc(struct ieee80211_local *local,
+                               u64 cookie, bool mgmt_tx)
 {
+       struct ieee80211_roc_work *roc, *tmp, *found = NULL;
        int ret;
 
-       lockdep_assert_held(&local->mtx);
+       mutex_lock(&local->mtx);
+       list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+               struct ieee80211_roc_work *dep, *tmp2;
 
-       if (local->hw_roc_cookie != cookie)
-               return -ENOENT;
+               list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) {
+                       if (!mgmt_tx && (unsigned long)dep != cookie)
+                               continue;
+                       else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)
+                               continue;
+                       /* found dependent item -- just remove it */
+                       list_del(&dep->list);
+                       mutex_unlock(&local->mtx);
 
-       ret = drv_cancel_remain_on_channel(local);
-       if (ret)
-               return ret;
+                       ieee80211_roc_notify_destroy(dep);
+                       return 0;
+               }
 
-       local->hw_roc_cookie = 0;
-       local->hw_roc_channel = NULL;
+               if (!mgmt_tx && (unsigned long)roc != cookie)
+                       continue;
+               else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
+                       continue;
 
-       ieee80211_recalc_idle(local);
+               found = roc;
+               break;
+       }
 
-       return 0;
-}
+       if (!found) {
+               mutex_unlock(&local->mtx);
+               return -ENOENT;
+       }
 
-static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
-                                             struct net_device *dev,
-                                             u64 cookie)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
+       /*
+        * We found the item to cancel, so do that. Note that it
+        * may have dependents, which we also cancel (and send
+        * the expired signal for.) Not doing so would be quite
+        * tricky here, but we may need to fix it later.
+        */
 
-       if (local->ops->cancel_remain_on_channel) {
-               int ret;
+       if (local->ops->remain_on_channel) {
+               if (found->started) {
+                       ret = drv_cancel_remain_on_channel(local);
+                       if (WARN_ON_ONCE(ret)) {
+                               mutex_unlock(&local->mtx);
+                               return ret;
+                       }
+               }
 
-               mutex_lock(&local->mtx);
-               ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
+               list_del(&found->list);
+
+               if (found->started)
+                       ieee80211_start_next_roc(local);
                mutex_unlock(&local->mtx);
 
-               return ret;
+               ieee80211_roc_notify_destroy(found);
+       } else {
+               /* work may be pending so use it all the time */
+               found->abort = true;
+               ieee80211_queue_delayed_work(&local->hw, &found->work, 0);
+
+               mutex_unlock(&local->mtx);
+
+               /* work will clean up etc */
+               flush_delayed_work(&found->work);
        }
 
-       return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
+       return 0;
 }
 
-static enum work_done_result
-ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
+static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
+                                             struct net_device *dev,
+                                             u64 cookie)
 {
-       /*
-        * Use the data embedded in the work struct for reporting
-        * here so if the driver mangled the SKB before dropping
-        * it (which is the only way we really should get here)
-        * then we don't report mangled data.
-        *
-        * If there was no wait time, then by the time we get here
-        * the driver will likely not have reported the status yet,
-        * so in that case userspace will have to deal with it.
-        */
-
-       if (wk->offchan_tx.wait && !wk->offchan_tx.status)
-               cfg80211_mgmt_tx_status(wk->sdata->dev,
-                                       (unsigned long) wk->offchan_tx.frame,
-                                       wk->data, wk->data_len, false, GFP_KERNEL);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
 
-       return WORK_DONE_DESTROY;
+       return ieee80211_cancel_roc(local, cookie, false);
 }
 
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
@@ -2244,10 +2410,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct sta_info *sta;
-       struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
+       bool need_offchan = false;
        u32 flags;
-       bool is_offchan = false;
+       int ret;
 
        if (dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
@@ -2255,33 +2421,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
                        IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       /* Check that we are on the requested channel for transmission */
-       if (chan != local->tmp_channel &&
-           chan != local->oper_channel)
-               is_offchan = true;
-       if (channel_type_valid &&
-           (channel_type != local->tmp_channel_type &&
-            channel_type != local->_oper_channel_type))
-               is_offchan = true;
-
-       if (chan == local->hw_roc_channel) {
-               /* TODO: check channel type? */
-               is_offchan = false;
-               flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
-       }
-
        if (no_cck)
                flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
 
-       if (is_offchan && !offchan)
-               return -EBUSY;
-
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_ADHOC:
+               if (!sdata->vif.bss_conf.ibss_joined)
+                       need_offchan = true;
+               /* fall through */
+#ifdef CONFIG_MAC80211_MESH
+       case NL80211_IFTYPE_MESH_POINT:
+               if (ieee80211_vif_is_mesh(&sdata->vif) &&
+                   !sdata->u.mesh.mesh_id_len)
+                       need_offchan = true;
+               /* fall through */
+#endif
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_P2P_GO:
-       case NL80211_IFTYPE_MESH_POINT:
+               if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+                   !ieee80211_vif_is_mesh(&sdata->vif) &&
+                   !rcu_access_pointer(sdata->bss->beacon))
+                       need_offchan = true;
                if (!ieee80211_is_action(mgmt->frame_control) ||
                    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
                        break;
@@ -2293,103 +2454,60 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
+               if (!sdata->u.mgd.associated)
+                       need_offchan = true;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
+       mutex_lock(&local->mtx);
+
+       /* Check if the operating channel is the requested channel */
+       if (!need_offchan) {
+               need_offchan = chan != local->oper_channel;
+               if (channel_type_valid &&
+                   channel_type != local->_oper_channel_type)
+                       need_offchan = true;
+       }
+
+       if (need_offchan && !offchan) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
-       if (!skb)
-               return -ENOMEM;
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
        memcpy(skb_put(skb, len), buf, len);
 
        IEEE80211_SKB_CB(skb)->flags = flags;
 
-       if (flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-               IEEE80211_SKB_CB(skb)->hw_queue =
-                       local->hw.offchannel_tx_hw_queue;
-
        skb->dev = sdata->dev;
 
-       *cookie = (unsigned long) skb;
-
-       if (is_offchan && local->ops->remain_on_channel) {
-               unsigned int duration;
-               int ret;
-
-               mutex_lock(&local->mtx);
-               /*
-                * If the duration is zero, then the driver
-                * wouldn't actually do anything. Set it to
-                * 100 for now.
-                *
-                * TODO: cancel the off-channel operation
-                *       when we get the SKB's TX status and
-                *       the wait time was zero before.
-                */
-               duration = 100;
-               if (wait)
-                       duration = wait;
-               ret = ieee80211_remain_on_channel_hw(local, dev, chan,
-                                                    channel_type,
-                                                    duration, cookie);
-               if (ret) {
-                       kfree_skb(skb);
-                       mutex_unlock(&local->mtx);
-                       return ret;
-               }
-
-               local->hw_roc_for_tx = true;
-               local->hw_roc_duration = wait;
-
-               /*
-                * queue up frame for transmission after
-                * ieee80211_ready_on_channel call
-                */
+       if (!need_offchan) {
+               ieee80211_tx_skb(sdata, skb);
+               ret = 0;
+               goto out_unlock;
+       }
 
-               /* modify cookie to prevent API mismatches */
-               *cookie ^= 2;
-               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
+       if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
                IEEE80211_SKB_CB(skb)->hw_queue =
                        local->hw.offchannel_tx_hw_queue;
-               local->hw_roc_skb = skb;
-               local->hw_roc_skb_for_status = skb;
-               mutex_unlock(&local->mtx);
 
-               return 0;
-       }
-
-       /*
-        * Can transmit right away if the channel was the
-        * right one and there's no wait involved... If a
-        * wait is involved, we might otherwise not be on
-        * the right channel for long enough!
-        */
-       if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
-               ieee80211_tx_skb(sdata, skb);
-               return 0;
-       }
-
-       wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
-       if (!wk) {
+       /* This will handle all kinds of coalescing and immediate TX */
+       ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+                                      wait, cookie, skb);
+       if (ret)
                kfree_skb(skb);
-               return -ENOMEM;
-       }
-
-       wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
-       wk->chan = chan;
-       wk->chan_type = channel_type;
-       wk->sdata = sdata;
-       wk->done = ieee80211_offchan_tx_done;
-       wk->offchan_tx.frame = skb;
-       wk->offchan_tx.wait = wait;
-       wk->data_len = len;
-       memcpy(wk->data, buf, len);
-
-       ieee80211_add_work(wk);
-       return 0;
+ out_unlock:
+       mutex_unlock(&local->mtx);
+       return ret;
 }
 
 static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
@@ -2398,45 +2516,8 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_work *wk;
-       int ret = -ENOENT;
-
-       mutex_lock(&local->mtx);
-
-       if (local->ops->cancel_remain_on_channel) {
-               cookie ^= 2;
-               ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
-
-               if (ret == 0) {
-                       kfree_skb(local->hw_roc_skb);
-                       local->hw_roc_skb = NULL;
-                       local->hw_roc_skb_for_status = NULL;
-               }
-
-               mutex_unlock(&local->mtx);
 
-               return ret;
-       }
-
-       list_for_each_entry(wk, &local->work_list, list) {
-               if (wk->sdata != sdata)
-                       continue;
-
-               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-                       continue;
-
-               if (cookie != (unsigned long) wk->offchan_tx.frame)
-                       continue;
-
-               wk->timeout = jiffies;
-
-               ieee80211_queue_work(&local->hw, &local->work_work);
-               ret = 0;
-               break;
-       }
-       mutex_unlock(&local->mtx);
-
-       return ret;
+       return ieee80211_cancel_roc(local, cookie, true);
 }
 
 static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
@@ -2444,16 +2525,30 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
                                          u16 frame_type, bool reg)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
-               return;
+       switch (frame_type) {
+       case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH:
+               if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+                       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 
-       if (reg)
-               local->probe_req_reg++;
-       else
-               local->probe_req_reg--;
+                       if (reg)
+                               ifibss->auth_frame_registrations++;
+                       else
+                               ifibss->auth_frame_registrations--;
+               }
+               break;
+       case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
+               if (reg)
+                       local->probe_req_reg++;
+               else
+                       local->probe_req_reg--;
 
-       ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+               ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+               break;
+       default:
+               break;
+       }
 }
 
 static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
@@ -2679,9 +2774,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
            !sdata->u.mgd.associated)
                return -EINVAL;
 
-#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
-       printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer);
-#endif
+       tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
+                action_code, peer);
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
                            max(sizeof(struct ieee80211_mgmt),
@@ -2790,9 +2884,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EINVAL;
 
-#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG
-       printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer);
-#endif
+       tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
 
        switch (oper) {
        case NL80211_TDLS_ENABLE_LINK:
@@ -2936,7 +3028,7 @@ struct cfg80211_ops mac80211_config_ops = {
 #endif
        .change_bss = ieee80211_change_bss,
        .set_txq_params = ieee80211_set_txq_params,
-       .set_channel = ieee80211_set_channel,
+       .set_monitor_channel = ieee80211_set_monitor_channel,
        .suspend = ieee80211_suspend,
        .resume = ieee80211_resume,
        .scan = ieee80211_scan,
index c76cf7230c7db06c646c4b13b14b46bf670a0afa..f0f87e5a1d354eef6a705deba7a15c21b491093f 100644 (file)
@@ -41,6 +41,10 @@ __ieee80211_get_channel_mode(struct ieee80211_local *local,
                        if (!sdata->u.ap.beacon)
                                continue;
                        break;
+               case NL80211_IFTYPE_MESH_POINT:
+                       if (!sdata->wdev.mesh_id_len)
+                               continue;
+                       break;
                default:
                        break;
                }
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
new file mode 100644 (file)
index 0000000..8f383a5
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef __MAC80211_DEBUG_H
+#define __MAC80211_DEBUG_H
+#include <net/cfg80211.h>
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+#define MAC80211_IBSS_DEBUG 1
+#else
+#define MAC80211_IBSS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_PS_DEBUG
+#define MAC80211_PS_DEBUG 1
+#else
+#define MAC80211_PS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+#define MAC80211_HT_DEBUG 1
+#else
+#define MAC80211_HT_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MPL_DEBUG
+#define MAC80211_MPL_DEBUG 1
+#else
+#define MAC80211_MPL_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MPATH_DEBUG
+#define MAC80211_MPATH_DEBUG 1
+#else
+#define MAC80211_MPATH_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MHWMP_DEBUG
+#define MAC80211_MHWMP_DEBUG 1
+#else
+#define MAC80211_MHWMP_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MESH_SYNC_DEBUG
+#define MAC80211_MESH_SYNC_DEBUG 1
+#else
+#define MAC80211_MESH_SYNC_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_TDLS_DEBUG
+#define MAC80211_TDLS_DEBUG 1
+#else
+#define MAC80211_TDLS_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_STA_DEBUG
+#define MAC80211_STA_DEBUG 1
+#else
+#define MAC80211_STA_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MLME_DEBUG
+#define MAC80211_MLME_DEBUG 1
+#else
+#define MAC80211_MLME_DEBUG 0
+#endif
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+void __sdata_info(const char *fmt, ...) __printf(1, 2);
+void __sdata_dbg(bool print, const char *fmt, ...) __printf(2, 3);
+void __sdata_err(const char *fmt, ...) __printf(1, 2);
+void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...)
+       __printf(3, 4);
+
+#define _sdata_info(sdata, fmt, ...)                                   \
+       __sdata_info("%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _sdata_dbg(print, sdata, fmt, ...)                             \
+       __sdata_dbg(print, "%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _sdata_err(sdata, fmt, ...)                                    \
+       __sdata_err("%s: " fmt, (sdata)->name, ##__VA_ARGS__)
+#define _wiphy_dbg(print, wiphy, fmt, ...)                             \
+       __wiphy_dbg(wiphy, print, fmt, ##__VA_ARGS__)
+#else
+#define _sdata_info(sdata, fmt, ...)                                   \
+do {                                                                   \
+       pr_info("%s: " fmt,                                             \
+               (sdata)->name, ##__VA_ARGS__);                          \
+} while (0)
+
+#define _sdata_dbg(print, sdata, fmt, ...)                             \
+do {                                                                   \
+       if (print)                                                      \
+               pr_debug("%s: " fmt,                                    \
+                        (sdata)->name, ##__VA_ARGS__);                 \
+} while (0)
+
+#define _sdata_err(sdata, fmt, ...)                                    \
+do {                                                                   \
+       pr_err("%s: " fmt,                                              \
+              (sdata)->name, ##__VA_ARGS__);                           \
+} while (0)
+
+#define _wiphy_dbg(print, wiphy, fmt, ...)                             \
+do {                                                                   \
+       if (print)                                                      \
+               wiphy_dbg((wiphy), fmt, ##__VA_ARGS__);                 \
+} while (0)
+#endif
+
+#define sdata_info(sdata, fmt, ...)                                    \
+       _sdata_info(sdata, fmt, ##__VA_ARGS__)
+#define sdata_err(sdata, fmt, ...)                                     \
+       _sdata_err(sdata, fmt, ##__VA_ARGS__)
+#define sdata_dbg(sdata, fmt, ...)                                     \
+       _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__)
+
+#define ht_dbg(sdata, fmt, ...)                                                \
+       _sdata_dbg(MAC80211_HT_DEBUG,                                   \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define ht_dbg_ratelimited(sdata, fmt, ...)                            \
+       _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(),                \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define ibss_dbg(sdata, fmt, ...)                                      \
+       _sdata_dbg(MAC80211_IBSS_DEBUG,                                 \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define ps_dbg(sdata, fmt, ...)                                                \
+       _sdata_dbg(MAC80211_PS_DEBUG,                                   \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define ps_dbg_hw(hw, fmt, ...)                                                \
+       _wiphy_dbg(MAC80211_PS_DEBUG,                                   \
+                  (hw)->wiphy, fmt, ##__VA_ARGS__)
+
+#define ps_dbg_ratelimited(sdata, fmt, ...)                            \
+       _sdata_dbg(MAC80211_PS_DEBUG && net_ratelimit(),                \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define mpl_dbg(sdata, fmt, ...)                                       \
+       _sdata_dbg(MAC80211_MPL_DEBUG,                                  \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define mpath_dbg(sdata, fmt, ...)                                     \
+       _sdata_dbg(MAC80211_MPATH_DEBUG,                                \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define mhwmp_dbg(sdata, fmt, ...)                                     \
+       _sdata_dbg(MAC80211_MHWMP_DEBUG,                                \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define msync_dbg(sdata, fmt, ...)                                     \
+       _sdata_dbg(MAC80211_MESH_SYNC_DEBUG,                            \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define tdls_dbg(sdata, fmt, ...)                                      \
+       _sdata_dbg(MAC80211_TDLS_DEBUG,                                 \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define sta_dbg(sdata, fmt, ...)                                       \
+       _sdata_dbg(MAC80211_STA_DEBUG,                                  \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define mlme_dbg(sdata, fmt, ...)                                      \
+       _sdata_dbg(MAC80211_MLME_DEBUG,                                 \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#define mlme_dbg_ratelimited(sdata, fmt, ...)                          \
+       _sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(),              \
+                  sdata, fmt, ##__VA_ARGS__)
+
+#endif /* __MAC80211_DEBUG_H */
index 7ed433c66d684a8c07168b7fb182d46c8b22060e..6d5aec9418ee203b43708499878864548822a2f2 100644 (file)
@@ -468,48 +468,54 @@ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
 IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
 IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
 IEEE80211_IF_FILE(dropped_frames_congestion,
-               u.mesh.mshstats.dropped_frames_congestion, DEC);
+                 u.mesh.mshstats.dropped_frames_congestion, DEC);
 IEEE80211_IF_FILE(dropped_frames_no_route,
-               u.mesh.mshstats.dropped_frames_no_route, DEC);
+                 u.mesh.mshstats.dropped_frames_no_route, DEC);
 IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
 
 /* Mesh parameters */
 IEEE80211_IF_FILE(dot11MeshMaxRetries,
-               u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
+                 u.mesh.mshcfg.dot11MeshMaxRetries, DEC);
 IEEE80211_IF_FILE(dot11MeshRetryTimeout,
-               u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
+                 u.mesh.mshcfg.dot11MeshRetryTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
-               u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
+                 u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
-               u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
+                 u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
 IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
-               u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
+                 u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout,
-               u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval,
-               u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval,
-               u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime,
-               u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries,
-               u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC);
 IEEE80211_IF_FILE(path_refresh_time,
-               u.mesh.mshcfg.path_refresh_time, DEC);
+                 u.mesh.mshcfg.path_refresh_time, DEC);
 IEEE80211_IF_FILE(min_discovery_timeout,
-               u.mesh.mshcfg.min_discovery_timeout, DEC);
+                 u.mesh.mshcfg.min_discovery_timeout, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
-               u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
 IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
-               u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
+                 u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
 IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
-               u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
+                 u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
 IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
 IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
 IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout,
+                 u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMProotInterval,
+                 u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval,
+                 u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC);
 #endif
 
 #define DEBUGFS_ADD_MODE(name, mode) \
@@ -607,9 +613,13 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
        MESHPARAMS_ADD(min_discovery_timeout);
        MESHPARAMS_ADD(dot11MeshHWMPRootMode);
        MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+       MESHPARAMS_ADD(dot11MeshForwarding);
        MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
        MESHPARAMS_ADD(rssi_threshold);
        MESHPARAMS_ADD(ht_opmode);
+       MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout);
+       MESHPARAMS_ADD(dot11MeshHWMProotInterval);
+       MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval);
 #undef MESHPARAMS_ADD
 }
 #endif
@@ -685,6 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 
        sprintf(buf, "netdev:%s", sdata->name);
        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
-               printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
-                      "dir to %s\n", buf);
+               sdata_err(sdata,
+                         "debugfs: failed to rename debugfs dir to %s\n",
+                         buf);
 }
index 6d33a0c743abe6989b4be4e4490e7c085e045a47..44e8c1242781216587b3027616a854c0c4da923b 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "driver-trace.h"
+#include "trace.h"
 
 static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
 {
@@ -845,4 +845,19 @@ drv_allow_buffered_frames(struct ieee80211_local *local,
                                                  more_data);
        trace_drv_return_void(local);
 }
+
+static inline int drv_get_rssi(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata,
+                               struct ieee80211_sta *sta,
+                               s8 *rssi_dbm)
+{
+       int ret;
+
+       might_sleep();
+
+       ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm);
+       trace_drv_get_rssi(local, sta, *rssi_dbm, ret);
+
+       return ret;
+}
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
deleted file mode 100644 (file)
index 8ed8711..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* bug in tracepoint.h, it should include this */
-#include <linux/module.h>
-
-/* sparse isn't too happy with all macros... */
-#ifndef __CHECKER__
-#include "driver-ops.h"
-#define CREATE_TRACE_POINTS
-#include "driver-trace.h"
-#endif
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
deleted file mode 100644 (file)
index 6de00b2..0000000
+++ /dev/null
@@ -1,1615 +0,0 @@
-#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
-#define __MAC80211_DRIVER_TRACE
-
-#include <linux/tracepoint.h>
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM mac80211
-
-#define MAXNAME                32
-#define LOCAL_ENTRY    __array(char, wiphy_name, 32)
-#define LOCAL_ASSIGN   strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
-#define LOCAL_PR_FMT   "%s"
-#define LOCAL_PR_ARG   __entry->wiphy_name
-
-#define STA_ENTRY      __array(char, sta_addr, ETH_ALEN)
-#define STA_ASSIGN     (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
-#define STA_PR_FMT     " sta:%pM"
-#define STA_PR_ARG     __entry->sta_addr
-
-#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata)   \
-                       __field(bool, p2p)                                              \
-                       __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata;    \
-                       __entry->p2p = sdata->vif.p2p;                                  \
-                       __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
-#define VIF_PR_FMT     " vif:%s(%d%s)"
-#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
-
-/*
- * Tracing for driver callbacks.
- */
-
-DECLARE_EVENT_CLASS(local_only_evt,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local),
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-       ),
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-       ),
-       TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
-);
-
-DECLARE_EVENT_CLASS(local_sdata_addr_evt,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __array(char, addr, 6)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               memcpy(__entry->addr, sdata->vif.addr, 6);
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
-       )
-);
-
-DECLARE_EVENT_CLASS(local_u32_evt,
-       TP_PROTO(struct ieee80211_local *local, u32 value),
-       TP_ARGS(local, value),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, value)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->value = value;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " value:%d",
-               LOCAL_PR_ARG, __entry->value
-       )
-);
-
-DECLARE_EVENT_CLASS(local_sdata_evt,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT VIF_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG
-       )
-);
-
-DEFINE_EVENT(local_only_evt, drv_return_void,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_return_int,
-       TP_PROTO(struct ieee80211_local *local, int ret),
-       TP_ARGS(local, ret),
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, ret)
-       ),
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->ret = ret;
-       ),
-       TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
-);
-
-TRACE_EVENT(drv_return_bool,
-       TP_PROTO(struct ieee80211_local *local, bool ret),
-       TP_ARGS(local, ret),
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(bool, ret)
-       ),
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->ret = ret;
-       ),
-       TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
-                 "true" : "false")
-);
-
-TRACE_EVENT(drv_return_u64,
-       TP_PROTO(struct ieee80211_local *local, u64 ret),
-       TP_ARGS(local, ret),
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u64, ret)
-       ),
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->ret = ret;
-       ),
-       TP_printk(LOCAL_PR_FMT " - %llu", LOCAL_PR_ARG, __entry->ret)
-);
-
-DEFINE_EVENT(local_only_evt, drv_start,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
-            TP_PROTO(struct ieee80211_local *local, u32 sset),
-            TP_ARGS(local, sset)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
-            TP_PROTO(struct ieee80211_local *local, u32 sset),
-            TP_ARGS(local, sset)
-);
-
-DEFINE_EVENT(local_only_evt, drv_get_et_stats,
-            TP_PROTO(struct ieee80211_local *local),
-            TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_suspend,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_resume,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_set_wakeup,
-       TP_PROTO(struct ieee80211_local *local, bool enabled),
-       TP_ARGS(local, enabled),
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(bool, enabled)
-       ),
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->enabled = enabled;
-       ),
-       TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
-);
-
-DEFINE_EVENT(local_only_evt, drv_stop,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_change_interface,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                enum nl80211_iftype type, bool p2p),
-
-       TP_ARGS(local, sdata, type, p2p),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __field(u32, new_type)
-               __field(bool, new_p2p)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               __entry->new_type = type;
-               __entry->new_p2p = p2p;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d%s",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
-               __entry->new_p2p ? "/p2p" : ""
-       )
-);
-
-DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_config,
-       TP_PROTO(struct ieee80211_local *local,
-                u32 changed),
-
-       TP_ARGS(local, changed),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, changed)
-               __field(u32, flags)
-               __field(int, power_level)
-               __field(int, dynamic_ps_timeout)
-               __field(int, max_sleep_period)
-               __field(u16, listen_interval)
-               __field(u8, long_frame_max_tx_count)
-               __field(u8, short_frame_max_tx_count)
-               __field(int, center_freq)
-               __field(int, channel_type)
-               __field(int, smps)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->changed = changed;
-               __entry->flags = local->hw.conf.flags;
-               __entry->power_level = local->hw.conf.power_level;
-               __entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
-               __entry->max_sleep_period = local->hw.conf.max_sleep_period;
-               __entry->listen_interval = local->hw.conf.listen_interval;
-               __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
-               __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
-               __entry->center_freq = local->hw.conf.channel->center_freq;
-               __entry->channel_type = local->hw.conf.channel_type;
-               __entry->smps = local->hw.conf.smps_mode;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " ch:%#x freq:%d",
-               LOCAL_PR_ARG, __entry->changed, __entry->center_freq
-       )
-);
-
-TRACE_EVENT(drv_bss_info_changed,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_bss_conf *info,
-                u32 changed),
-
-       TP_ARGS(local, sdata, info, changed),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __field(bool, assoc)
-               __field(u16, aid)
-               __field(bool, cts)
-               __field(bool, shortpre)
-               __field(bool, shortslot)
-               __field(u8, dtimper)
-               __field(u16, bcnint)
-               __field(u16, assoc_cap)
-               __field(u64, timestamp)
-               __field(u32, basic_rates)
-               __field(u32, changed)
-               __field(bool, enable_beacon)
-               __field(u16, ht_operation_mode)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               __entry->changed = changed;
-               __entry->aid = info->aid;
-               __entry->assoc = info->assoc;
-               __entry->shortpre = info->use_short_preamble;
-               __entry->cts = info->use_cts_prot;
-               __entry->shortslot = info->use_short_slot;
-               __entry->dtimper = info->dtim_period;
-               __entry->bcnint = info->beacon_int;
-               __entry->assoc_cap = info->assoc_capability;
-               __entry->timestamp = info->last_tsf;
-               __entry->basic_rates = info->basic_rates;
-               __entry->enable_beacon = info->enable_beacon;
-               __entry->ht_operation_mode = info->ht_operation_mode;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " changed:%#x",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
-       )
-);
-
-TRACE_EVENT(drv_prepare_multicast,
-       TP_PROTO(struct ieee80211_local *local, int mc_count),
-
-       TP_ARGS(local, mc_count),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, mc_count)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->mc_count = mc_count;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " prepare mc (%d)",
-               LOCAL_PR_ARG, __entry->mc_count
-       )
-);
-
-TRACE_EVENT(drv_configure_filter,
-       TP_PROTO(struct ieee80211_local *local,
-                unsigned int changed_flags,
-                unsigned int *total_flags,
-                u64 multicast),
-
-       TP_ARGS(local, changed_flags, total_flags, multicast),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(unsigned int, changed)
-               __field(unsigned int, total)
-               __field(u64, multicast)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->changed = changed_flags;
-               __entry->total = *total_flags;
-               __entry->multicast = multicast;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " changed:%#x total:%#x",
-               LOCAL_PR_ARG, __entry->changed, __entry->total
-       )
-);
-
-TRACE_EVENT(drv_set_tim,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta, bool set),
-
-       TP_ARGS(local, sta, set),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-               __field(bool, set)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               STA_ASSIGN;
-               __entry->set = set;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT STA_PR_FMT " set:%d",
-               LOCAL_PR_ARG, STA_PR_FMT, __entry->set
-       )
-);
-
-TRACE_EVENT(drv_set_key,
-       TP_PROTO(struct ieee80211_local *local,
-                enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_sta *sta,
-                struct ieee80211_key_conf *key),
-
-       TP_ARGS(local, cmd, sdata, sta, key),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-               __field(u32, cipher)
-               __field(u8, hw_key_idx)
-               __field(u8, flags)
-               __field(s8, keyidx)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->cipher = key->cipher;
-               __entry->flags = key->flags;
-               __entry->keyidx = key->keyidx;
-               __entry->hw_key_idx = key->hw_key_idx;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-       )
-);
-
-TRACE_EVENT(drv_update_tkip_key,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_key_conf *conf,
-                struct ieee80211_sta *sta, u32 iv32),
-
-       TP_ARGS(local, sdata, conf, sta, iv32),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-               __field(u32, iv32)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->iv32 = iv32;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
-               LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
-       )
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_sw_scan_complete,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_get_stats,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_low_level_stats *stats,
-                int ret),
-
-       TP_ARGS(local, stats, ret),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, ret)
-               __field(unsigned int, ackfail)
-               __field(unsigned int, rtsfail)
-               __field(unsigned int, fcserr)
-               __field(unsigned int, rtssucc)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->ret = ret;
-               __entry->ackfail = stats->dot11ACKFailureCount;
-               __entry->rtsfail = stats->dot11RTSFailureCount;
-               __entry->fcserr = stats->dot11FCSErrorCount;
-               __entry->rtssucc = stats->dot11RTSSuccessCount;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " ret:%d",
-               LOCAL_PR_ARG, __entry->ret
-       )
-);
-
-TRACE_EVENT(drv_get_tkip_seq,
-       TP_PROTO(struct ieee80211_local *local,
-                u8 hw_key_idx, u32 *iv32, u16 *iv16),
-
-       TP_ARGS(local, hw_key_idx, iv32, iv16),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u8, hw_key_idx)
-               __field(u32, iv32)
-               __field(u16, iv16)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->hw_key_idx = hw_key_idx;
-               __entry->iv32 = *iv32;
-               __entry->iv16 = *iv16;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT, LOCAL_PR_ARG
-       )
-);
-
-DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold,
-       TP_PROTO(struct ieee80211_local *local, u32 value),
-       TP_ARGS(local, value)
-);
-
-DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold,
-       TP_PROTO(struct ieee80211_local *local, u32 value),
-       TP_ARGS(local, value)
-);
-
-TRACE_EVENT(drv_set_coverage_class,
-       TP_PROTO(struct ieee80211_local *local, u8 value),
-
-       TP_ARGS(local, value),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u8, value)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->value = value;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " value:%d",
-               LOCAL_PR_ARG, __entry->value
-       )
-);
-
-TRACE_EVENT(drv_sta_notify,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                enum sta_notify_cmd cmd,
-                struct ieee80211_sta *sta),
-
-       TP_ARGS(local, sdata, cmd, sta),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-               __field(u32, cmd)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->cmd = cmd;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " cmd:%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
-       )
-);
-
-TRACE_EVENT(drv_sta_state,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_sta *sta,
-                enum ieee80211_sta_state old_state,
-                enum ieee80211_sta_state new_state),
-
-       TP_ARGS(local, sdata, sta, old_state, new_state),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-               __field(u32, old_state)
-               __field(u32, new_state)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->old_state = old_state;
-               __entry->new_state = new_state;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " state: %d->%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
-               __entry->old_state, __entry->new_state
-       )
-);
-
-TRACE_EVENT(drv_sta_rc_update,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_sta *sta,
-                u32 changed),
-
-       TP_ARGS(local, sdata, sta, changed),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-               __field(u32, changed)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->changed = changed;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
-       )
-);
-
-TRACE_EVENT(drv_sta_add,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_sta *sta),
-
-       TP_ARGS(local, sdata, sta),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-       )
-);
-
-TRACE_EVENT(drv_sta_remove,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct ieee80211_sta *sta),
-
-       TP_ARGS(local, sdata, sta),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               STA_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
-       )
-);
-
-TRACE_EVENT(drv_conf_tx,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                u16 ac, const struct ieee80211_tx_queue_params *params),
-
-       TP_ARGS(local, sdata, ac, params),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __field(u16, ac)
-               __field(u16, txop)
-               __field(u16, cw_min)
-               __field(u16, cw_max)
-               __field(u8, aifs)
-               __field(bool, uapsd)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               __entry->ac = ac;
-               __entry->txop = params->txop;
-               __entry->cw_max = params->cw_max;
-               __entry->cw_min = params->cw_min;
-               __entry->aifs = params->aifs;
-               __entry->uapsd = params->uapsd;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  " AC:%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
-       )
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-TRACE_EVENT(drv_set_tsf,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                u64 tsf),
-
-       TP_ARGS(local, sdata, tsf),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __field(u64, tsf)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               __entry->tsf = tsf;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
-               LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
-       )
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata),
-       TP_ARGS(local, sdata)
-);
-
-DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_ampdu_action,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                enum ieee80211_ampdu_mlme_action action,
-                struct ieee80211_sta *sta, u16 tid,
-                u16 *ssn, u8 buf_size),
-
-       TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-               __field(u32, action)
-               __field(u16, tid)
-               __field(u16, ssn)
-               __field(u8, buf_size)
-               VIF_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->action = action;
-               __entry->tid = tid;
-               __entry->ssn = ssn ? *ssn : 0;
-               __entry->buf_size = buf_size;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
-               __entry->tid, __entry->buf_size
-       )
-);
-
-TRACE_EVENT(drv_get_survey,
-       TP_PROTO(struct ieee80211_local *local, int idx,
-                struct survey_info *survey),
-
-       TP_ARGS(local, idx, survey),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, idx)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->idx = idx;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " idx:%d",
-               LOCAL_PR_ARG, __entry->idx
-       )
-);
-
-TRACE_EVENT(drv_flush,
-       TP_PROTO(struct ieee80211_local *local, bool drop),
-
-       TP_ARGS(local, drop),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(bool, drop)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->drop = drop;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " drop:%d",
-               LOCAL_PR_ARG, __entry->drop
-       )
-);
-
-TRACE_EVENT(drv_channel_switch,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_channel_switch *ch_switch),
-
-       TP_ARGS(local, ch_switch),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u64, timestamp)
-               __field(bool, block_tx)
-               __field(u16, freq)
-               __field(u8, count)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->timestamp = ch_switch->timestamp;
-               __entry->block_tx = ch_switch->block_tx;
-               __entry->freq = ch_switch->channel->center_freq;
-               __entry->count = ch_switch->count;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " new freq:%u count:%d",
-               LOCAL_PR_ARG, __entry->freq, __entry->count
-       )
-);
-
-TRACE_EVENT(drv_set_antenna,
-       TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
-
-       TP_ARGS(local, tx_ant, rx_ant, ret),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, tx_ant)
-               __field(u32, rx_ant)
-               __field(int, ret)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->tx_ant = tx_ant;
-               __entry->rx_ant = rx_ant;
-               __entry->ret = ret;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
-               LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
-       )
-);
-
-TRACE_EVENT(drv_get_antenna,
-       TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
-
-       TP_ARGS(local, tx_ant, rx_ant, ret),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, tx_ant)
-               __field(u32, rx_ant)
-               __field(int, ret)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->tx_ant = tx_ant;
-               __entry->rx_ant = rx_ant;
-               __entry->ret = ret;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
-               LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
-       )
-);
-
-TRACE_EVENT(drv_remain_on_channel,
-       TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
-                enum nl80211_channel_type chantype, unsigned int duration),
-
-       TP_ARGS(local, chan, chantype, duration),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, center_freq)
-               __field(int, channel_type)
-               __field(unsigned int, duration)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->center_freq = chan->center_freq;
-               __entry->channel_type = chantype;
-               __entry->duration = duration;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " freq:%dMHz duration:%dms",
-               LOCAL_PR_ARG, __entry->center_freq, __entry->duration
-       )
-);
-
-DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_offchannel_tx,
-       TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
-                struct ieee80211_channel *chan,
-                enum nl80211_channel_type channel_type,
-                unsigned int wait),
-
-       TP_ARGS(local, skb, chan, channel_type, wait),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, center_freq)
-               __field(int, channel_type)
-               __field(unsigned int, wait)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->center_freq = chan->center_freq;
-               __entry->channel_type = channel_type;
-               __entry->wait = wait;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
-               LOCAL_PR_ARG, __entry->center_freq, __entry->wait
-       )
-);
-
-TRACE_EVENT(drv_set_ringparam,
-       TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
-
-       TP_ARGS(local, tx, rx),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, tx)
-               __field(u32, rx)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->tx = tx;
-               __entry->rx = rx;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " tx:%d rx %d",
-               LOCAL_PR_ARG, __entry->tx, __entry->rx
-       )
-);
-
-TRACE_EVENT(drv_get_ringparam,
-       TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max,
-                u32 *rx, u32 *rx_max),
-
-       TP_ARGS(local, tx, tx_max, rx, rx_max),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, tx)
-               __field(u32, tx_max)
-               __field(u32, rx)
-               __field(u32, rx_max)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->tx = *tx;
-               __entry->tx_max = *tx_max;
-               __entry->rx = *rx;
-               __entry->rx_max = *rx_max;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d",
-               LOCAL_PR_ARG,
-               __entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max
-       )
-);
-
-DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(drv_set_bitrate_mask,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                const struct cfg80211_bitrate_mask *mask),
-
-       TP_ARGS(local, sdata, mask),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __field(u32, legacy_2g)
-               __field(u32, legacy_5g)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
-               __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
-               LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
-       )
-);
-
-TRACE_EVENT(drv_set_rekey_data,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sub_if_data *sdata,
-                struct cfg80211_gtk_rekey_data *data),
-
-       TP_ARGS(local, sdata, data),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               VIF_ENTRY
-               __array(u8, kek, NL80211_KEK_LEN)
-               __array(u8, kck, NL80211_KCK_LEN)
-               __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               VIF_ASSIGN;
-               memcpy(__entry->kek, data->kek, NL80211_KEK_LEN);
-               memcpy(__entry->kck, data->kck, NL80211_KCK_LEN);
-               memcpy(__entry->replay_ctr, data->replay_ctr,
-                      NL80211_REPLAY_CTR_LEN);
-       ),
-
-       TP_printk(LOCAL_PR_FMT VIF_PR_FMT,
-                 LOCAL_PR_ARG, VIF_PR_ARG)
-);
-
-TRACE_EVENT(drv_rssi_callback,
-       TP_PROTO(struct ieee80211_local *local,
-                enum ieee80211_rssi_event rssi_event),
-
-       TP_ARGS(local, rssi_event),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u32, rssi_event)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->rssi_event = rssi_event;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " rssi_event:%d",
-               LOCAL_PR_ARG, __entry->rssi_event
-       )
-);
-
-DECLARE_EVENT_CLASS(release_evt,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta,
-                u16 tids, int num_frames,
-                enum ieee80211_frame_release_type reason,
-                bool more_data),
-
-       TP_ARGS(local, sta, tids, num_frames, reason, more_data),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-               __field(u16, tids)
-               __field(int, num_frames)
-               __field(int, reason)
-               __field(bool, more_data)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               STA_ASSIGN;
-               __entry->tids = tids;
-               __entry->num_frames = num_frames;
-               __entry->reason = reason;
-               __entry->more_data = more_data;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT STA_PR_FMT
-               " TIDs:0x%.4x frames:%d reason:%d more:%d",
-               LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
-               __entry->reason, __entry->more_data
-       )
-);
-
-DEFINE_EVENT(release_evt, drv_release_buffered_frames,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta,
-                u16 tids, int num_frames,
-                enum ieee80211_frame_release_type reason,
-                bool more_data),
-
-       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
-);
-
-DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta,
-                u16 tids, int num_frames,
-                enum ieee80211_frame_release_type reason,
-                bool more_data),
-
-       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
-);
-
-/*
- * Tracing for API calls that drivers call.
- */
-
-TRACE_EVENT(api_start_tx_ba_session,
-       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
-
-       TP_ARGS(sta, tid),
-
-       TP_STRUCT__entry(
-               STA_ENTRY
-               __field(u16, tid)
-       ),
-
-       TP_fast_assign(
-               STA_ASSIGN;
-               __entry->tid = tid;
-       ),
-
-       TP_printk(
-               STA_PR_FMT " tid:%d",
-               STA_PR_ARG, __entry->tid
-       )
-);
-
-TRACE_EVENT(api_start_tx_ba_cb,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
-
-       TP_ARGS(sdata, ra, tid),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __array(u8, ra, ETH_ALEN)
-               __field(u16, tid)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               memcpy(__entry->ra, ra, ETH_ALEN);
-               __entry->tid = tid;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT " ra:%pM tid:%d",
-               VIF_PR_ARG, __entry->ra, __entry->tid
-       )
-);
-
-TRACE_EVENT(api_stop_tx_ba_session,
-       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
-
-       TP_ARGS(sta, tid),
-
-       TP_STRUCT__entry(
-               STA_ENTRY
-               __field(u16, tid)
-       ),
-
-       TP_fast_assign(
-               STA_ASSIGN;
-               __entry->tid = tid;
-       ),
-
-       TP_printk(
-               STA_PR_FMT " tid:%d",
-               STA_PR_ARG, __entry->tid
-       )
-);
-
-TRACE_EVENT(api_stop_tx_ba_cb,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
-
-       TP_ARGS(sdata, ra, tid),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __array(u8, ra, ETH_ALEN)
-               __field(u16, tid)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               memcpy(__entry->ra, ra, ETH_ALEN);
-               __entry->tid = tid;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT " ra:%pM tid:%d",
-               VIF_PR_ARG, __entry->ra, __entry->tid
-       )
-);
-
-DEFINE_EVENT(local_only_evt, api_restart_hw,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(api_beacon_loss,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata),
-
-       TP_ARGS(sdata),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT,
-               VIF_PR_ARG
-       )
-);
-
-TRACE_EVENT(api_connection_loss,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata),
-
-       TP_ARGS(sdata),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT,
-               VIF_PR_ARG
-       )
-);
-
-TRACE_EVENT(api_cqm_rssi_notify,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata,
-                enum nl80211_cqm_rssi_threshold_event rssi_event),
-
-       TP_ARGS(sdata, rssi_event),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __field(u32, rssi_event)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               __entry->rssi_event = rssi_event;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT " event:%d",
-               VIF_PR_ARG, __entry->rssi_event
-       )
-);
-
-TRACE_EVENT(api_scan_completed,
-       TP_PROTO(struct ieee80211_local *local, bool aborted),
-
-       TP_ARGS(local, aborted),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(bool, aborted)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->aborted = aborted;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " aborted:%d",
-               LOCAL_PR_ARG, __entry->aborted
-       )
-);
-
-TRACE_EVENT(api_sched_scan_results,
-       TP_PROTO(struct ieee80211_local *local),
-
-       TP_ARGS(local),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT, LOCAL_PR_ARG
-       )
-);
-
-TRACE_EVENT(api_sched_scan_stopped,
-       TP_PROTO(struct ieee80211_local *local),
-
-       TP_ARGS(local),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT, LOCAL_PR_ARG
-       )
-);
-
-TRACE_EVENT(api_sta_block_awake,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta, bool block),
-
-       TP_ARGS(local, sta, block),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-               __field(bool, block)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               STA_ASSIGN;
-               __entry->block = block;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT STA_PR_FMT " block:%d",
-               LOCAL_PR_ARG, STA_PR_FMT, __entry->block
-       )
-);
-
-TRACE_EVENT(api_chswitch_done,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
-
-       TP_ARGS(sdata, success),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __field(bool, success)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               __entry->success = success;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT " success=%d",
-               VIF_PR_ARG, __entry->success
-       )
-);
-
-DEFINE_EVENT(local_only_evt, api_ready_on_channel,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
-);
-
-TRACE_EVENT(api_gtk_rekey_notify,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata,
-                const u8 *bssid, const u8 *replay_ctr),
-
-       TP_ARGS(sdata, bssid, replay_ctr),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __array(u8, bssid, ETH_ALEN)
-               __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               memcpy(__entry->bssid, bssid, ETH_ALEN);
-               memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN);
-       ),
-
-       TP_printk(VIF_PR_FMT, VIF_PR_ARG)
-);
-
-TRACE_EVENT(api_enable_rssi_reports,
-       TP_PROTO(struct ieee80211_sub_if_data *sdata,
-                int rssi_min_thold, int rssi_max_thold),
-
-       TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
-
-       TP_STRUCT__entry(
-               VIF_ENTRY
-               __field(int, rssi_min_thold)
-               __field(int, rssi_max_thold)
-       ),
-
-       TP_fast_assign(
-               VIF_ASSIGN;
-               __entry->rssi_min_thold = rssi_min_thold;
-               __entry->rssi_max_thold = rssi_max_thold;
-       ),
-
-       TP_printk(
-               VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
-               VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
-       )
-);
-
-TRACE_EVENT(api_eosp,
-       TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_sta *sta),
-
-       TP_ARGS(local, sta),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               STA_ASSIGN;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT STA_PR_FMT,
-               LOCAL_PR_ARG, STA_PR_FMT
-       )
-);
-
-/*
- * Tracing for internal functions
- * (which may also be called in response to driver calls)
- */
-
-TRACE_EVENT(wake_queue,
-       TP_PROTO(struct ieee80211_local *local, u16 queue,
-                enum queue_stop_reason reason),
-
-       TP_ARGS(local, queue, reason),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u16, queue)
-               __field(u32, reason)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->queue = queue;
-               __entry->reason = reason;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " queue:%d, reason:%d",
-               LOCAL_PR_ARG, __entry->queue, __entry->reason
-       )
-);
-
-TRACE_EVENT(stop_queue,
-       TP_PROTO(struct ieee80211_local *local, u16 queue,
-                enum queue_stop_reason reason),
-
-       TP_ARGS(local, queue, reason),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(u16, queue)
-               __field(u32, reason)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->queue = queue;
-               __entry->reason = reason;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " queue:%d, reason:%d",
-               LOCAL_PR_ARG, __entry->queue, __entry->reason
-       )
-);
-#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
-
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_FILE driver-trace
-#include <trace/define_trace.h>
index 6f8615c54b22fe68b7b08184a4d284ac9f3d9131..4b4538d6392589897154035f6ab6305e2d3ebb28 100644 (file)
@@ -305,12 +305,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
        tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
        initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-       net_dbg_ratelimited("delba from %pM (%s) tid %d reason code %d\n",
-                           mgmt->sa, initiator ? "initiator" : "recipient",
-                           tid,
-                           le16_to_cpu(mgmt->u.action.u.delba.reason_code));
-#endif /* CONFIG_MAC80211_HT_DEBUG */
+       ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n",
+                          mgmt->sa, initiator ? "initiator" : "recipient",
+                          tid,
+                          le16_to_cpu(mgmt->u.action.u.delba.reason_code));
 
        if (initiator == WLAN_BACK_INITIATOR)
                __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
index 33d9d0c3e3d06ce70e831643473dc34ac201deed..5746d62faba1956d5a8690726417275cc4a70ff5 100644 (file)
@@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        local->oper_channel = chan;
        channel_type = ifibss->channel_type;
-       if (channel_type > NL80211_CHAN_HT20 &&
-           !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
+       if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
                channel_type = NL80211_CHAN_HT20;
        if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
                /* can only fail due to HT40+/- mismatch */
@@ -262,11 +261,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
 
        memcpy(addr, sta->sta.addr, ETH_ALEN);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(sdata->local->hw.wiphy,
-                   "Adding new IBSS station %pM (dev=%s)\n",
-                   addr, sdata->name);
-#endif
+       ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr);
 
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
        sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -280,12 +275,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
        /* If it fails, maybe we raced another insertion? */
        if (sta_info_insert_rcu(sta))
                return sta_info_get(sdata, addr);
-       if (auth) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM"
-                      "(auth_transaction=1)\n", sdata->vif.addr,
-                      sdata->u.ibss.bssid, addr);
-#endif
+       if (auth && !sdata->u.ibss.auth_frame_registrations) {
+               ibss_dbg(sdata,
+                        "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
+                        sdata->vif.addr, sdata->u.ibss.bssid, addr);
                ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
                                    addr, sdata->u.ibss.bssid, NULL, 0, 0);
        }
@@ -308,7 +301,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
         *      allow new one to be added.
         */
        if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-               net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
+               net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
                                    sdata->name, addr);
                rcu_read_lock();
                return NULL;
@@ -355,11 +348,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
 
        if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
                return;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM."
-              "(auth_transaction=%d)\n",
-              sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
-#endif
+       ibss_dbg(sdata,
+                "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
+                mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
        sta_info_destroy_addr(sdata, mgmt->sa);
        ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
        rcu_read_unlock();
@@ -422,15 +413,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                        ieee80211_mandatory_rates(local, band);
 
                                if (sta->sta.supp_rates[band] != prev_rates) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-                                       printk(KERN_DEBUG
-                                               "%s: updated supp_rates set "
-                                               "for %pM based on beacon"
-                                               "/probe_resp (0x%x -> 0x%x)\n",
-                                               sdata->name, sta->sta.addr,
-                                               prev_rates,
-                                               sta->sta.supp_rates[band]);
-#endif
+                                       ibss_dbg(sdata,
+                                                "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+                                                sta->sta.addr, prev_rates,
+                                                sta->sta.supp_rates[band]);
                                        rates_updated = true;
                                }
                        } else {
@@ -545,22 +531,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                rx_timestamp = drv_get_tsf(local, sdata);
        }
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
-              "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-              mgmt->sa, mgmt->bssid,
-              (unsigned long long)rx_timestamp,
-              (unsigned long long)beacon_timestamp,
-              (unsigned long long)(rx_timestamp - beacon_timestamp),
-              jiffies);
-#endif
+       ibss_dbg(sdata,
+                "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+                mgmt->sa, mgmt->bssid,
+                (unsigned long long)rx_timestamp,
+                (unsigned long long)beacon_timestamp,
+                (unsigned long long)(rx_timestamp - beacon_timestamp),
+                jiffies);
 
        if (beacon_timestamp > rx_timestamp) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "%s: beacon TSF higher than "
-                      "local TSF - IBSS merge with BSSID %pM\n",
-                      sdata->name, mgmt->bssid);
-#endif
+               ibss_dbg(sdata,
+                        "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
+                        mgmt->bssid);
                ieee80211_sta_join_ibss(sdata, bss);
                supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
@@ -586,7 +568,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
         *      allow new one to be added.
         */
        if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-               net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
+               net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n",
                                    sdata->name, addr);
                return;
        }
@@ -662,8 +644,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
        if (ifibss->fixed_channel)
                return;
 
-       printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-              "IBSS networks with same SSID (merge)\n", sdata->name);
+       sdata_info(sdata,
+                  "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n");
 
        ieee80211_request_internal_scan(sdata,
                        ifibss->ssid, ifibss->ssid_len, NULL);
@@ -691,8 +673,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
                bssid[0] |= 0x02;
        }
 
-       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
-              sdata->name, bssid);
+       sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid);
 
        capability = WLAN_CAPABILITY_IBSS;
 
@@ -723,10 +704,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        lockdep_assert_held(&ifibss->mtx);
 
        active_ibss = ieee80211_sta_active_ibss(sdata);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
-              sdata->name, active_ibss);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+       ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss);
 
        if (active_ibss)
                return;
@@ -749,29 +727,24 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                struct ieee80211_bss *bss;
 
                bss = (void *)cbss->priv;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-                      "%pM\n", cbss->bssid, ifibss->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-               printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
-                      " based on configured SSID\n",
-                      sdata->name, cbss->bssid);
+               ibss_dbg(sdata,
+                        "sta_find_ibss: selected %pM current %pM\n",
+                        cbss->bssid, ifibss->bssid);
+               sdata_info(sdata,
+                          "Selected IBSS BSSID %pM based on configured SSID\n",
+                          cbss->bssid);
 
                ieee80211_sta_join_ibss(sdata, bss);
                ieee80211_rx_bss_put(local, bss);
                return;
        }
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   did not try to join ibss\n");
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+       ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n");
 
        /* Selected IBSS not found in current scan results - try to scan */
        if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
-               printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-                      "join\n", sdata->name);
+               sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
                ieee80211_request_internal_scan(sdata,
                                ifibss->ssid, ifibss->ssid_len,
@@ -785,9 +758,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                                ieee80211_sta_create_ibss(sdata);
                                return;
                        }
-                       printk(KERN_DEBUG "%s: IBSS not allowed on"
-                              " %d MHz\n", sdata->name,
-                              local->hw.conf.channel->center_freq);
+                       sdata_info(sdata, "IBSS not allowed on %d MHz\n",
+                                  local->hw.conf.channel->center_freq);
 
                        /* No IBSS found - decrease scan interval and continue
                         * scanning. */
@@ -822,12 +794,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 
        tx_last_beacon = drv_tx_last_beacon(local);
 
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
-              " (tx_last_beacon=%d)\n",
-              sdata->name, mgmt->sa, mgmt->da,
-              mgmt->bssid, tx_last_beacon);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+       ibss_dbg(sdata,
+                "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n",
+                mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon);
 
        if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
                return;
@@ -840,11 +809,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        pos = mgmt->u.probe_req.variable;
        if (pos[0] != WLAN_EID_SSID ||
            pos + 2 + pos[1] > end) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-                      "from %pM\n",
-                      sdata->name, mgmt->sa);
-#endif
+               ibss_dbg(sdata, "Invalid SSID IE in ProbeReq from %pM\n",
+                        mgmt->sa);
                return;
        }
        if (pos[1] != 0 &&
@@ -861,10 +827,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 
        resp = (struct ieee80211_mgmt *) skb->data;
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
-              sdata->name, resp->da);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+       ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da);
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
 }
index 3f3cd50fff16ec637b23f3a25bdf6ed4a8146296..f834a005e1c5e0fe462d7f7e248a97d7c081d87b 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/mac80211.h>
 #include "key.h"
 #include "sta_info.h"
+#include "debug.h"
 
 struct ieee80211_local;
 
@@ -55,11 +56,14 @@ struct ieee80211_local;
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+/*
+ * Some APs experience problems when working with U-APSD. Decrease the
+ * probability of that happening by using legacy mode for all ACs but VO.
+ * The AP that caused us trouble was a Cisco 4410N. It ignores our
+ * setting, and always treats non-VO ACs as legacy.
+ */
 #define IEEE80211_DEFAULT_UAPSD_QUEUES \
-       (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |   \
-        IEEE80211_WMM_IE_STA_QOSINFO_AC_BE |   \
-        IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |   \
-        IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+       IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
 
 #define IEEE80211_DEFAULT_MAX_SP_LEN           \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@ -317,55 +321,30 @@ struct mesh_preq_queue {
        u8 flags;
 };
 
-enum ieee80211_work_type {
-       IEEE80211_WORK_ABORT,
-       IEEE80211_WORK_REMAIN_ON_CHANNEL,
-       IEEE80211_WORK_OFFCHANNEL_TX,
-};
-
-/**
- * enum work_done_result - indicates what to do after work was done
- *
- * @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
- * @WORK_DONE_REQUEUE: This work item was reset to be reused, and
- *     should be requeued.
- */
-enum work_done_result {
-       WORK_DONE_DESTROY,
-       WORK_DONE_REQUEUE,
-};
+#if HZ/100 == 0
+#define IEEE80211_ROC_MIN_LEFT 1
+#else
+#define IEEE80211_ROC_MIN_LEFT (HZ/100)
+#endif
 
-struct ieee80211_work {
+struct ieee80211_roc_work {
        struct list_head list;
+       struct list_head dependents;
 
-       struct rcu_head rcu_head;
+       struct delayed_work work;
 
        struct ieee80211_sub_if_data *sdata;
 
-       enum work_done_result (*done)(struct ieee80211_work *wk,
-                                     struct sk_buff *skb);
-
        struct ieee80211_channel *chan;
        enum nl80211_channel_type chan_type;
 
-       unsigned long timeout;
-       enum ieee80211_work_type type;
+       bool started, abort, hw_begun, notified;
 
-       bool started;
+       unsigned long hw_start_time;
 
-       union {
-               struct {
-                       u32 duration;
-               } remain;
-               struct {
-                       struct sk_buff *frame;
-                       u32 wait;
-                       bool status;
-               } offchan_tx;
-       };
-
-       size_t data_len;
-       u8 data[];
+       u32 duration, req_duration;
+       struct sk_buff *frame;
+       u64 mgmt_tx_cookie;
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -399,7 +378,6 @@ struct ieee80211_mgd_auth_data {
 struct ieee80211_mgd_assoc_data {
        struct cfg80211_bss *bss;
        const u8 *supp_rates;
-       const u8 *ht_operation_ie;
 
        unsigned long timeout;
        int tries;
@@ -414,6 +392,8 @@ struct ieee80211_mgd_assoc_data {
        bool sent_assoc;
        bool synced;
 
+       u8 ap_ht_param;
+
        size_t ie_len;
        u8 ie[];
 };
@@ -532,6 +512,7 @@ struct ieee80211_if_ibss {
        bool privacy;
 
        bool control_port;
+       unsigned int auth_frame_registrations;
 
        u8 bssid[ETH_ALEN] __aligned(2);
        u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -701,6 +682,9 @@ struct ieee80211_sub_if_data {
        /* TID bitmap for NoAck policy */
        u16 noack_map;
 
+       /* bit field of ACM bits (BIT(802.1D tag)) */
+       u8 wmm_acm;
+
        struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
        struct ieee80211_key __rcu *default_unicast_key;
        struct ieee80211_key __rcu *default_multicast_key;
@@ -846,13 +830,6 @@ struct ieee80211_local {
 
        const struct ieee80211_ops *ops;
 
-       /*
-        * work stuff, potentially off-channel (in the future)
-        */
-       struct list_head work_list;
-       struct timer_list work_timer;
-       struct work_struct work_work;
-
        /*
         * private workqueue to mac80211. mac80211 makes this accessible
         * via ieee80211_queue_work()
@@ -912,6 +889,9 @@ struct ieee80211_local {
        /* device is started */
        bool started;
 
+       /* device is during a HW reconfig */
+       bool in_reconfig;
+
        /* wowlan is enabled -- don't reconfig on resume */
        bool wowlan;
 
@@ -1050,7 +1030,6 @@ struct ieee80211_local {
        int total_ps_buffered; /* total number of all buffered unicast and
                                * multicast packets for power saving stations
                                */
-       unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
        bool pspolling;
        bool offchannel_ps_enabled;
@@ -1087,14 +1066,12 @@ struct ieee80211_local {
        } debugfs;
 #endif
 
-       struct ieee80211_channel *hw_roc_channel;
-       struct net_device *hw_roc_dev;
-       struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
+       /*
+        * Remain-on-channel support
+        */
+       struct list_head roc_list;
        struct work_struct hw_roc_start, hw_roc_done;
-       enum nl80211_channel_type hw_roc_channel_type;
-       unsigned int hw_roc_duration;
-       u32 hw_roc_cookie;
-       bool hw_roc_for_tx;
+       unsigned long hw_roc_start_time;
 
        struct idr ack_status_frames;
        spinlock_t ack_status_lock;
@@ -1290,7 +1267,12 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
                                    bool offchannel_ps_enable);
 void ieee80211_offchannel_return(struct ieee80211_local *local,
                                 bool offchannel_ps_disable);
-void ieee80211_hw_roc_setup(struct ieee80211_local *local);
+void ieee80211_roc_setup(struct ieee80211_local *local);
+void ieee80211_start_next_roc(struct ieee80211_local *local);
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_sw_roc_work(struct work_struct *work);
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
 
 /* interface handling */
 int ieee80211_iface_init(void);
@@ -1500,18 +1482,6 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
                               enum nl80211_channel_type channel_type,
                               u16 prot_mode);
 
-/* internal work items */
-void ieee80211_work_init(struct ieee80211_local *local);
-void ieee80211_add_work(struct ieee80211_work *wk);
-void free_work(struct ieee80211_work *wk);
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_channel *chan,
-                                  enum nl80211_channel_type channel_type,
-                                  unsigned int duration, u64 *cookie);
-int ieee80211_wk_cancel_remain_on_channel(
-       struct ieee80211_sub_if_data *sdata, u64 cookie);
-
 /* channel management */
 enum ieee80211_chan_mode {
        CHAN_MODE_UNDEFINED,
index 8664111d05663d47678f2088f4169a6ab80fdb96..58c2ab3d483a9878a752ab22e33e3f585c294546 100644 (file)
@@ -57,9 +57,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
                return -EINVAL;
        }
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
        dev->mtu = new_mtu;
        return 0;
 }
@@ -100,15 +97,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sub_if_data *nsdata;
-       struct net_device *dev = sdata->dev;
 
        ASSERT_RTNL();
 
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               if (ndev != dev && ieee80211_sdata_running(nsdata)) {
+               if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -127,7 +121,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
                         * The remaining checks are only performed for interfaces
                         * with the same MAC address.
                         */
-                       if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr))
+                       if (!ether_addr_equal(sdata->vif.addr,
+                                             nsdata->vif.addr))
                                continue;
 
                        /*
@@ -528,10 +523,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
         */
        netif_tx_stop_all_queues(sdata->dev);
 
-       /*
-        * Purge work for this interface.
-        */
-       ieee80211_work_purge(sdata);
+       ieee80211_roc_purge(sdata);
 
        /*
         * Remove all stations associated with this interface.
@@ -637,18 +629,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                ieee80211_configure_filter(local);
                break;
        default:
-               mutex_lock(&local->mtx);
-               if (local->hw_roc_dev == sdata->dev &&
-                   local->hw_roc_channel) {
-                       /* ignore return value since this is racy */
-                       drv_cancel_remain_on_channel(local);
-                       ieee80211_queue_work(&local->hw, &local->hw_roc_done);
-               }
-               mutex_unlock(&local->mtx);
-
-               flush_work(&local->hw_roc_start);
-               flush_work(&local->hw_roc_done);
-
                flush_work(&sdata->work);
                /*
                 * When we get here, the interface is marked down.
@@ -823,7 +803,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
 
        hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
 
-       return ieee80211_select_queue_80211(local, skb, hdr);
+       return ieee80211_select_queue_80211(sdata, skb, hdr);
 }
 
 static const struct net_device_ops ieee80211_monitorif_ops = {
@@ -1238,7 +1218,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
 
                if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
                        /* not a contiguous mask ... not handled now! */
-                       printk(KERN_DEBUG "not contiguous\n");
+                       pr_info("not contiguous\n");
                        break;
                }
 
@@ -1364,6 +1344,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                        sdata->u.mgd.use_4addr = params->use_4addr;
        }
 
+       ndev->features |= local->hw.netdev_features;
+
        ret = register_netdevice(ndev);
        if (ret)
                goto fail;
@@ -1427,10 +1409,6 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
        if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
                return 0;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
-#endif
-
        local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
        return IEEE80211_CONF_CHANGE_IDLE;
 }
@@ -1440,10 +1418,6 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
        if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
                return 0;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "device now idle\n");
-#endif
-
        drv_flush(local, false);
 
        local->hw.conf.flags |= IEEE80211_CONF_IDLE;
@@ -1454,9 +1428,9 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
        int count = 0;
-       bool working = false, scanning = false, hw_roc = false;
-       struct ieee80211_work *wk;
+       bool working = false, scanning = false;
        unsigned int led_trig_start = 0, led_trig_stop = 0;
+       struct ieee80211_roc_work *roc;
 
 #ifdef CONFIG_PROVE_LOCKING
        WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
@@ -1491,9 +1465,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                count++;
        }
 
-       list_for_each_entry(wk, &local->work_list, list) {
-               working = true;
-               wk->sdata->vif.bss_conf.idle = false;
+       if (!local->ops->remain_on_channel) {
+               list_for_each_entry(roc, &local->roc_list, list) {
+                       working = true;
+                       roc->sdata->vif.bss_conf.idle = false;
+               }
        }
 
        if (local->scan_sdata &&
@@ -1502,9 +1478,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                local->scan_sdata->vif.bss_conf.idle = false;
        }
 
-       if (local->hw_roc_channel)
-               hw_roc = true;
-
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
                    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -1516,7 +1489,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
        }
 
-       if (working || scanning || hw_roc)
+       if (working || scanning)
                led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
        else
                led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
@@ -1528,8 +1501,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 
        ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
 
-       if (hw_roc)
-               return ieee80211_idle_off(local, "hw remain-on-channel");
        if (working)
                return ieee80211_idle_off(local, "working");
        if (scanning)
index 5bb600d93d77b4cf2ec9c0196c002b7ab46538df..b3b7e526e245cdb7cb925e9c39146ec6189bd359 100644 (file)
@@ -139,7 +139,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
        }
 
        if (ret != -ENOSPC && ret != -EOPNOTSUPP)
-               wiphy_err(key->local->hw.wiphy,
+               sdata_err(sdata,
                          "failed to set key (%d, %pM) to hardware (%d)\n",
                          key->conf.keyidx,
                          sta ? sta->sta.addr : bcast_addr, ret);
@@ -186,7 +186,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          sta ? &sta->sta : NULL, &key->conf);
 
        if (ret)
-               wiphy_err(key->local->hw.wiphy,
+               sdata_err(sdata,
                          "failed to remove key (%d, %pM) from hardware (%d)\n",
                          key->conf.keyidx,
                          sta ? sta->sta.addr : bcast_addr, ret);
index f5548e953259e6f517ed19a77286e8d7e0e1e531..0b040fb73673f9e2de6ad7336879907a840945d0 100644 (file)
@@ -345,6 +345,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
+       /*
+        * Stop all Rx during the reconfig. We don't want state changes
+        * or driver callbacks while this is in progress.
+        */
+       local->in_reconfig = true;
+       barrier();
+
        schedule_work(&local->restart_work);
 }
 EXPORT_SYMBOL(ieee80211_restart_hw);
@@ -455,7 +462,9 @@ static const struct ieee80211_txrx_stypes
 ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_ADHOC] = {
                .tx = 0xffff,
-               .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4),
        },
        [NL80211_IFTYPE_STATION] = {
                .tx = 0xffff,
@@ -625,8 +634,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
-       ieee80211_work_init(local);
-
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
@@ -669,7 +676,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        ieee80211_led_names(local);
 
-       ieee80211_hw_roc_setup(local);
+       ieee80211_roc_setup(local);
 
        return &local->hw;
 }
@@ -682,6 +689,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        enum ieee80211_band band;
        int channels, max_bitrates;
        bool supp_ht;
+       netdev_features_t feature_whitelist;
        static const u32 cipher_suites[] = {
                /* keep WEP first, it may be removed below */
                WLAN_CIPHER_SUITE_WEP40,
@@ -708,6 +716,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
                return -EINVAL;
 
+       /* Only HW csum features are currently compatible with mac80211 */
+       feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                           NETIF_F_HW_CSUM;
+       if (WARN_ON(hw->netdev_features & ~feature_whitelist))
+               return -EINVAL;
+
        if (hw->max_report_rates == 0)
                hw->max_report_rates = hw->max_rates;
 
@@ -1009,12 +1023,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
-       /*
-        * Now all work items will be gone, but the
-        * timer might still be armed, so delete it
-        */
-       del_timer_sync(&local->work_timer);
-
        cancel_work_sync(&local->restart_work);
        cancel_work_sync(&local->reconfig_filter);
 
index 2913113c5833f220c5708af7d8686ab4196c3d50..764593d65fc3a4023f234b1671b3766ad76349e6 100644 (file)
@@ -443,7 +443,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
 {
-       if (ifmsh->mshcfg.dot11MeshHWMPRootMode)
+       if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)
                set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
        else {
                clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
@@ -523,11 +523,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 {
        bool free_plinks;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: running mesh housekeeping\n",
-              sdata->name);
-#endif
-
        ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
        mesh_path_expire(sdata);
 
@@ -542,11 +537,17 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       u32 interval;
 
        mesh_path_tx_root_frame(sdata);
+
+       if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN)
+               interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+       else
+               interval = ifmsh->mshcfg.dot11MeshHWMProotInterval;
+
        mod_timer(&ifmsh->mesh_path_root_timer,
-                 round_jiffies(TU_TO_EXP_TIME(
-                                 ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
+                 round_jiffies(TU_TO_EXP_TIME(interval)));
 }
 
 #ifdef CONFIG_PM
index e3642756f8f41dd4a6b9911523a2126fb02541da..faaa39bcfd109b783c2f297fdda6aa3585587026 100644 (file)
@@ -104,6 +104,7 @@ enum mesh_deferred_task_flags {
  * an mpath to a hash bucket on a path table.
  * @rann_snd_addr: the RANN sender address
  * @rann_metric: the aggregated path metric towards the root node
+ * @last_preq_to_root: Timestamp of last PREQ sent to root
  * @is_root: the destination station of this path is a root node
  * @is_gate: the destination station of this path is a mesh gate
  *
@@ -131,6 +132,7 @@ struct mesh_path {
        spinlock_t state_lock;
        u8 rann_snd_addr[ETH_ALEN];
        u32 rann_metric;
+       unsigned long last_preq_to_root;
        bool is_root;
        bool is_gate;
 };
@@ -245,7 +247,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
 void ieee80211s_update_metric(struct ieee80211_local *local,
-               struct sta_info *stainfo, struct sk_buff *skb);
+               struct sta_info *sta, struct sk_buff *skb);
 void ieee80211s_stop(void);
 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
index 9b59658e865094ffc3b8aafd29b777205a1a81de..fb7b6a11d0ba9e32ea0fbb45b26eb6c177c5494b 100644 (file)
 #include "wme.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...) \
-       printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
-#else
-#define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
-#endif
-
 #define TEST_FRAME_LEN 8192
 #define MAX_METRIC     0xffffffff
 #define ARITH_SHIFT    8
@@ -98,6 +91,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
 #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
 #define disc_timeout_jiff(s) \
        msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
+#define root_path_confirmation_jiffies(s) \
+       msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval)
 
 enum mpath_frame_type {
        MPATH_PREQ = 0,
@@ -142,19 +137,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 
        switch (action) {
        case MPATH_PREQ:
-               mhwmp_dbg("sending PREQ to %pM", target);
+               mhwmp_dbg(sdata, "sending PREQ to %pM\n", target);
                ie_len = 37;
                pos = skb_put(skb, 2 + ie_len);
                *pos++ = WLAN_EID_PREQ;
                break;
        case MPATH_PREP:
-               mhwmp_dbg("sending PREP to %pM", target);
+               mhwmp_dbg(sdata, "sending PREP to %pM\n", target);
                ie_len = 31;
                pos = skb_put(skb, 2 + ie_len);
                *pos++ = WLAN_EID_PREP;
                break;
        case MPATH_RANN:
-               mhwmp_dbg("sending RANN from %pM", orig_addr);
+               mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr);
                ie_len = sizeof(struct ieee80211_rann_ie);
                pos = skb_put(skb, 2 + ie_len);
                *pos++ = WLAN_EID_RANN;
@@ -303,7 +298,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 }
 
 void ieee80211s_update_metric(struct ieee80211_local *local,
-               struct sta_info *stainfo, struct sk_buff *skb)
+               struct sta_info *sta, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -315,15 +310,14 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
        failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
 
        /* moving average, scaled to 100 */
-       stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed);
-       if (stainfo->fail_avg > 95)
-               mesh_plink_broken(stainfo);
+       sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed);
+       if (sta->fail_avg > 95)
+               mesh_plink_broken(sta);
 }
 
 static u32 airtime_link_metric_get(struct ieee80211_local *local,
                                   struct sta_info *sta)
 {
-       struct ieee80211_supported_band *sband;
        struct rate_info rinfo;
        /* This should be adjusted for each device */
        int device_constant = 1 << ARITH_SHIFT;
@@ -333,8 +327,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
        u32 tx_time, estimated_retx;
        u64 result;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
        if (sta->fail_avg >= 100)
                return MAX_METRIC;
 
@@ -519,10 +511,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
        struct mesh_path *mpath = NULL;
        u8 *target_addr, *orig_addr;
        const u8 *da;
-       u8 target_flags, ttl;
-       u32 orig_sn, target_sn, lifetime;
+       u8 target_flags, ttl, flags;
+       u32 orig_sn, target_sn, lifetime, orig_metric;
        bool reply = false;
        bool forward = true;
+       bool root_is_gate;
 
        /* Update target SN, if present */
        target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
@@ -530,11 +523,15 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
        target_sn = PREQ_IE_TARGET_SN(preq_elem);
        orig_sn = PREQ_IE_ORIG_SN(preq_elem);
        target_flags = PREQ_IE_TARGET_F(preq_elem);
+       orig_metric = metric;
+       /* Proactive PREQ gate announcements */
+       flags = PREQ_IE_FLAGS(preq_elem);
+       root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
 
-       mhwmp_dbg("received PREQ from %pM", orig_addr);
+       mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr);
 
        if (ether_addr_equal(target_addr, sdata->vif.addr)) {
-               mhwmp_dbg("PREQ is for us");
+               mhwmp_dbg(sdata, "PREQ is for us\n");
                forward = false;
                reply = true;
                metric = 0;
@@ -544,6 +541,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                        target_sn = ++ifmsh->sn;
                        ifmsh->last_sn_update = jiffies;
                }
+       } else if (is_broadcast_ether_addr(target_addr) &&
+                  (target_flags & IEEE80211_PREQ_TO_FLAG)) {
+               rcu_read_lock();
+               mpath = mesh_path_lookup(orig_addr, sdata);
+               if (mpath) {
+                       if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+                               reply = true;
+                               target_addr = sdata->vif.addr;
+                               target_sn = ++ifmsh->sn;
+                               metric = 0;
+                               ifmsh->last_sn_update = jiffies;
+                       }
+                       if (root_is_gate)
+                               mesh_path_add_gate(mpath);
+               }
+               rcu_read_unlock();
        } else {
                rcu_read_lock();
                mpath = mesh_path_lookup(target_addr, sdata);
@@ -570,19 +583,20 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                lifetime = PREQ_IE_LIFETIME(preq_elem);
                ttl = ifmsh->mshcfg.element_ttl;
                if (ttl != 0) {
-                       mhwmp_dbg("replying to the PREQ");
+                       mhwmp_dbg(sdata, "replying to the PREQ\n");
                        mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
                                cpu_to_le32(orig_sn), 0, target_addr,
                                cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
                                cpu_to_le32(lifetime), cpu_to_le32(metric),
                                0, sdata);
-               } else
+               } else {
                        ifmsh->mshstats.dropped_frames_ttl++;
+               }
        }
 
        if (forward && ifmsh->mshcfg.dot11MeshForwarding) {
                u32 preq_id;
-               u8 hopcount, flags;
+               u8 hopcount;
 
                ttl = PREQ_IE_TTL(preq_elem);
                lifetime = PREQ_IE_LIFETIME(preq_elem);
@@ -590,13 +604,19 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                        ifmsh->mshstats.dropped_frames_ttl++;
                        return;
                }
-               mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
+               mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr);
                --ttl;
-               flags = PREQ_IE_FLAGS(preq_elem);
                preq_id = PREQ_IE_PREQ_ID(preq_elem);
                hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
                da = (mpath && mpath->is_root) ?
                        mpath->rann_snd_addr : broadcast_addr;
+
+               if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
+                       target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
+                       target_sn = PREQ_IE_TARGET_SN(preq_elem);
+                       metric = orig_metric;
+               }
+
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
                                cpu_to_le32(orig_sn), target_flags, target_addr,
                                cpu_to_le32(target_sn), da,
@@ -631,7 +651,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        u8 next_hop[ETH_ALEN];
        u32 target_sn, orig_sn, lifetime;
 
-       mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
+       mhwmp_dbg(sdata, "received PREP from %pM\n",
+                 PREP_IE_ORIG_ADDR(prep_elem));
 
        orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
        if (ether_addr_equal(orig_addr, sdata->vif.addr))
@@ -744,11 +765,6 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
        bool root_is_gate;
 
        ttl = rann->rann_ttl;
-       if (ttl <= 1) {
-               ifmsh->mshstats.dropped_frames_ttl++;
-               return;
-       }
-       ttl--;
        flags = rann->rann_flags;
        root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
        orig_addr = rann->rann_addr;
@@ -762,8 +778,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
        if (ether_addr_equal(orig_addr, sdata->vif.addr))
                return;
 
-       mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)",
-                       orig_addr, mgmt->sa, root_is_gate);
+       mhwmp_dbg(sdata,
+                 "received RANN from %pM via neighbour %pM (is_gate=%d)\n",
+                 orig_addr, mgmt->sa, root_is_gate);
 
        rcu_read_lock();
        sta = sta_info_get(sdata, mgmt->sa);
@@ -785,34 +802,50 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       if (!(SN_LT(mpath->sn, orig_sn)) &&
+           !(mpath->sn == orig_sn && metric < mpath->rann_metric)) {
+               rcu_read_unlock();
+               return;
+       }
+
        if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
-            time_after(jiffies, mpath->exp_time - 1*HZ)) &&
-            !(mpath->flags & MESH_PATH_FIXED)) {
-               mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
-                                                              orig_addr);
+            (time_after(jiffies, mpath->last_preq_to_root +
+                                 root_path_confirmation_jiffies(sdata)) ||
+            time_before(jiffies, mpath->last_preq_to_root))) &&
+            !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) {
+               mhwmp_dbg(sdata,
+                         "time to refresh root mpath %pM\n",
+                         orig_addr);
                mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+               mpath->last_preq_to_root = jiffies;
+       }
+
+       mpath->sn = orig_sn;
+       mpath->rann_metric = metric + metric_txsta;
+       mpath->is_root = true;
+       /* Recording RANNs sender address to send individually
+        * addressed PREQs destined for root mesh STA */
+       memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
+
+       if (root_is_gate)
+               mesh_path_add_gate(mpath);
+
+       if (ttl <= 1) {
+               ifmsh->mshstats.dropped_frames_ttl++;
+               rcu_read_unlock();
+               return;
        }
+       ttl--;
 
-       if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn &&
-          metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) {
+       if (ifmsh->mshcfg.dot11MeshForwarding) {
                mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
                                       cpu_to_le32(orig_sn),
                                       0, NULL, 0, broadcast_addr,
                                       hopcount, ttl, cpu_to_le32(interval),
                                       cpu_to_le32(metric + metric_txsta),
                                       0, sdata);
-               mpath->sn = orig_sn;
-               mpath->rann_metric = metric + metric_txsta;
-               /* Recording RANNs sender address to send individually
-                * addressed PREQs destined for root mesh STA */
-               memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
        }
 
-       mpath->is_root = true;
-
-       if (root_is_gate)
-               mesh_path_add_gate(mpath);
-
        rcu_read_unlock();
 }
 
@@ -889,7 +922,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 
        preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
        if (!preq_node) {
-               mhwmp_dbg("could not allocate PREQ node");
+               mhwmp_dbg(sdata, "could not allocate PREQ node\n");
                return;
        }
 
@@ -898,7 +931,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
                spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
                kfree(preq_node);
                if (printk_ratelimit())
-                       mhwmp_dbg("PREQ node queue full");
+                       mhwmp_dbg(sdata, "PREQ node queue full\n");
                return;
        }
 
@@ -1146,7 +1179,7 @@ void mesh_path_timer(unsigned long data)
                if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
                        ret = mesh_path_send_to_gates(mpath);
                        if (ret)
-                               mhwmp_dbg("no gate was reachable");
+                               mhwmp_dbg(sdata, "no gate was reachable\n");
                } else
                        mesh_path_flush_pending(mpath);
        }
@@ -1157,13 +1190,34 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
-       u8 flags;
+       u8 flags, target_flags = 0;
 
        flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
                        ? RANN_FLAG_IS_GATE : 0;
-       mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
+
+       switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
+       case IEEE80211_PROACTIVE_RANN:
+               mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
                               cpu_to_le32(++ifmsh->sn),
                               0, NULL, 0, broadcast_addr,
-                              0, sdata->u.mesh.mshcfg.element_ttl,
+                              0, ifmsh->mshcfg.element_ttl,
                               cpu_to_le32(interval), 0, 0, sdata);
+               break;
+       case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
+               flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
+       case IEEE80211_PROACTIVE_PREQ_NO_PREP:
+               interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout;
+               target_flags |= IEEE80211_PREQ_TO_FLAG |
+                               IEEE80211_PREQ_USN_FLAG;
+               mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
+                               cpu_to_le32(++ifmsh->sn), target_flags,
+                               (u8 *) broadcast_addr, 0, broadcast_addr,
+                               0, ifmsh->mshcfg.element_ttl,
+                               cpu_to_le32(interval),
+                               0, cpu_to_le32(ifmsh->preq_id++), sdata);
+               break;
+       default:
+               mhwmp_dbg(sdata, "Proactive mechanism not supported\n");
+               return;
+       }
 }
index b39224d8255cb17701c19dbde7f80c00430abfc5..c9ae931dd693735e96ea03ecefc02f1882d2d9cc 100644 (file)
 #include "ieee80211_i.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
-#define mpath_dbg(fmt, args...)        printk(KERN_DEBUG fmt, ##args)
-#else
-#define mpath_dbg(fmt, args...)        do { (void)(0); } while (0)
-#endif
-
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
 #define INIT_PATHS_SIZE_ORDER  2
 
@@ -322,9 +316,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
 
        spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
        skb_queue_splice(&gateq, &gate_mpath->frame_queue);
-       mpath_dbg("Mpath queue for gate %pM has %d frames\n",
-                       gate_mpath->dst,
-                       skb_queue_len(&gate_mpath->frame_queue));
+       mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n",
+                 gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue));
        spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
 
        if (!copy)
@@ -446,9 +439,9 @@ int mesh_path_add_gate(struct mesh_path *mpath)
        hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
        spin_unlock_bh(&tbl->gates_lock);
        rcu_read_unlock();
-       mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n",
-                 mpath->sdata->name, mpath->dst,
-                 mpath->sdata->u.mesh.num_gates);
+       mpath_dbg(mpath->sdata,
+                 "Mesh path: Recorded new gate: %pM. %d known gates\n",
+                 mpath->dst, mpath->sdata->u.mesh.num_gates);
        return 0;
 err_rcu:
        rcu_read_unlock();
@@ -477,8 +470,8 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
                        spin_unlock_bh(&tbl->gates_lock);
                        mpath->sdata->u.mesh.num_gates--;
                        mpath->is_gate = false;
-                       mpath_dbg("Mesh path (%s): Deleted gate: %pM. "
-                                 "%d known gates\n", mpath->sdata->name,
+                       mpath_dbg(mpath->sdata,
+                                 "Mesh path: Deleted gate: %pM. %d known gates\n",
                                  mpath->dst, mpath->sdata->u.mesh.num_gates);
                        break;
                }
@@ -946,19 +939,20 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
                        continue;
 
                if (gate->mpath->flags & MESH_PATH_ACTIVE) {
-                       mpath_dbg("Forwarding to %pM\n", gate->mpath->dst);
+                       mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst);
                        mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
                        from_mpath = gate->mpath;
                        copy = true;
                } else {
-                       mpath_dbg("Not forwarding %p\n", gate->mpath);
-                       mpath_dbg("flags %x\n", gate->mpath->flags);
+                       mpath_dbg(sdata,
+                                 "Not forwarding %p (flags %#x)\n",
+                                 gate->mpath, gate->mpath->flags);
                }
        }
 
        hlist_for_each_entry_rcu(gate, n, known_gates, list)
                if (gate->mpath->sdata == sdata) {
-                       mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+                       mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
                        mesh_path_tx_pending(gate->mpath);
                }
 
index 60ef235c9d9bd139d061301e49540003f8188a57..a1dbd15402768aedcab66ab698a53d70176d14a2 100644 (file)
 #include "rate.h"
 #include "mesh.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
-#define mpl_dbg(fmt, args...)  printk(KERN_DEBUG fmt, ##args)
-#else
-#define mpl_dbg(fmt, args...)  do { (void)(0); } while (0)
-#endif
-
 #define PLINK_GET_LLID(p) (p + 2)
 #define PLINK_GET_PLID(p) (p + 4)
 
@@ -134,12 +128,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
 
                switch (sta->ch_type) {
                case NL80211_CHAN_NO_HT:
-                       mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
+                       mpl_dbg(sdata,
+                               "mesh_plink %pM: nonHT sta (%pM) is present\n",
                                sdata->vif.addr, sta->sta.addr);
                        non_ht_sta = true;
                        goto out;
                case NL80211_CHAN_HT20:
-                       mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
+                       mpl_dbg(sdata,
+                               "mesh_plink %pM: HT20 sta (%pM) is present\n",
                                sdata->vif.addr, sta->sta.addr);
                        ht20_sta = true;
                default:
@@ -160,7 +156,8 @@ out:
                sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
                sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
                changed = BSS_CHANGED_HT;
-               mpl_dbg("mesh_plink %pM: protection mode changed to %d",
+               mpl_dbg(sdata,
+                       "mesh_plink %pM: protection mode changed to %d\n",
                        sdata->vif.addr, ht_opmode);
        }
 
@@ -437,7 +434,8 @@ static void mesh_plink_timer(unsigned long data)
                spin_unlock_bh(&sta->lock);
                return;
        }
-       mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
+       mpl_dbg(sta->sdata,
+               "Mesh plink timer for %pM fired on state %d\n",
                sta->sta.addr, sta->plink_state);
        reason = 0;
        llid = sta->llid;
@@ -450,7 +448,8 @@ static void mesh_plink_timer(unsigned long data)
                /* retry timer */
                if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
                        u32 rand;
-                       mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
+                       mpl_dbg(sta->sdata,
+                               "Mesh plink for %pM (retry, timeout): %d %d\n",
                                sta->sta.addr, sta->plink_retries,
                                sta->plink_timeout);
                        get_random_bytes(&rand, sizeof(u32));
@@ -530,7 +529,8 @@ int mesh_plink_open(struct sta_info *sta)
        sta->plink_state = NL80211_PLINK_OPN_SNT;
        mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
        spin_unlock_bh(&sta->lock);
-       mpl_dbg("Mesh plink: starting establishment with %pM\n",
+       mpl_dbg(sdata,
+               "Mesh plink: starting establishment with %pM\n",
                sta->sta.addr);
 
        return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
@@ -565,7 +565,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
        u8 *baseaddr;
        u32 changed = 0;
        __le16 plid, llid, reason;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
        static const char *mplstates[] = {
                [NL80211_PLINK_LISTEN] = "LISTEN",
                [NL80211_PLINK_OPN_SNT] = "OPN-SNT",
@@ -575,14 +574,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                [NL80211_PLINK_HOLDING] = "HOLDING",
                [NL80211_PLINK_BLOCKED] = "BLOCKED"
        };
-#endif
 
        /* need action_code, aux */
        if (len < IEEE80211_MIN_ACTION_SIZE + 3)
                return;
 
        if (is_multicast_ether_addr(mgmt->da)) {
-               mpl_dbg("Mesh plink: ignore frame from multicast address");
+               mpl_dbg(sdata,
+                       "Mesh plink: ignore frame from multicast address\n");
                return;
        }
 
@@ -595,12 +594,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
        }
        ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
        if (!elems.peering) {
-               mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+               mpl_dbg(sdata,
+                       "Mesh plink: missing necessary peer link ie\n");
                return;
        }
        if (elems.rsn_len &&
                        sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
-               mpl_dbg("Mesh plink: can't establish link with secure peer\n");
+               mpl_dbg(sdata,
+                       "Mesh plink: can't establish link with secure peer\n");
                return;
        }
 
@@ -610,14 +611,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
            (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
            (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
                                                        && ie_len != 8)) {
-               mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
-                   ftype, ie_len);
+               mpl_dbg(sdata,
+                       "Mesh plink: incorrect plink ie length %d %d\n",
+                       ftype, ie_len);
                return;
        }
 
        if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
                                (!elems.mesh_id || !elems.mesh_config)) {
-               mpl_dbg("Mesh plink: missing necessary ie\n");
+               mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
                return;
        }
        /* Note the lines below are correct, the llid in the frame is the plid
@@ -632,21 +634,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
        sta = sta_info_get(sdata, mgmt->sa);
        if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
-               mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+               mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
                rcu_read_unlock();
                return;
        }
 
        if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
            !rssi_threshold_check(sta, sdata)) {
-               mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n",
+               mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
                        mgmt->sa);
                rcu_read_unlock();
                return;
        }
 
        if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
-               mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
+               mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
                rcu_read_unlock();
                return;
        }
@@ -683,7 +685,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
        } else if (!sta) {
                /* ftype == WLAN_SP_MESH_PEERING_OPEN */
                if (!mesh_plink_free_count(sdata)) {
-                       mpl_dbg("Mesh plink error: no more free plinks\n");
+                       mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
                        rcu_read_unlock();
                        return;
                }
@@ -724,7 +726,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                                event = CLS_ACPT;
                        break;
                default:
-                       mpl_dbg("Mesh plink: unknown frame subtype\n");
+                       mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
                        rcu_read_unlock();
                        return;
                }
@@ -734,13 +736,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                /* allocate sta entry if necessary and update info */
                sta = mesh_peer_init(sdata, mgmt->sa, &elems);
                if (!sta) {
-                       mpl_dbg("Mesh plink: failed to init peer!\n");
+                       mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
                        rcu_read_unlock();
                        return;
                }
        }
 
-       mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
+       mpl_dbg(sdata,
+               "Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
                mgmt->sa, mplstates[sta->plink_state],
                le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
                event);
@@ -851,7 +854,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        mesh_plink_inc_estab_count(sdata);
                        changed |= mesh_set_ht_prot_mode(sdata);
                        changed |= BSS_CHANGED_BEACON;
-                       mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        break;
                default:
@@ -887,7 +890,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        mesh_plink_inc_estab_count(sdata);
                        changed |= mesh_set_ht_prot_mode(sdata);
                        changed |= BSS_CHANGED_BEACON;
-                       mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        mesh_plink_frame_tx(sdata,
                                            WLAN_SP_MESH_PEERING_CONFIRM,
index 38d30e8ce6dc08f647777b6da179cc7dee56141b..accfa00ffcdf0ee9cc9cc0046d977130888faccf 100644 (file)
 #include "mesh.h"
 #include "driver-ops.h"
 
-#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
-#define msync_dbg(fmt, args...) \
-       printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
-#else
-#define msync_dbg(fmt, args...)   do { (void)(0); } while (0)
-#endif
-
 /* This is not in the standard.  It represents a tolerable tbtt drift below
  * which we do no TSF adjustment.
  */
@@ -65,14 +58,14 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
        spin_lock_bh(&ifmsh->sync_offset_lock);
 
        if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
-               msync_dbg("TBTT : max clockdrift=%lld; adjusting",
-                       (long long) ifmsh->sync_offset_clockdrift_max);
+               msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n",
+                         (long long) ifmsh->sync_offset_clockdrift_max);
                tsfdelta = -ifmsh->sync_offset_clockdrift_max;
                ifmsh->sync_offset_clockdrift_max = 0;
        } else {
-               msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu",
-                       (long long) ifmsh->sync_offset_clockdrift_max,
-                       (unsigned long long) beacon_int_fraction);
+               msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n",
+                         (long long) ifmsh->sync_offset_clockdrift_max,
+                         (unsigned long long) beacon_int_fraction);
                tsfdelta = -beacon_int_fraction;
                ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;
        }
@@ -120,7 +113,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
        if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
                clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
-               msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr);
+               msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr);
                goto no_sync;
        }
 
@@ -169,7 +162,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
                s64 t_clockdrift = sta->t_offset_setpoint
                                   - sta->t_offset;
-               msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld",
+               msync_dbg(sdata,
+                         "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n",
                          sta->sta.addr,
                          (long long) sta->t_offset,
                          (long long)
@@ -178,7 +172,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
                if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
                        t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
-                       msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset",
+                       msync_dbg(sdata,
+                                 "STA %pM : t_clockdrift=%lld too large, setpoint reset\n",
                                  sta->sta.addr,
                                  (long long) t_clockdrift);
                        clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
@@ -197,8 +192,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        } else {
                sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;
                set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
-               msync_dbg("STA %pM : offset was invalid, "
-                         " sta->t_offset=%lld",
+               msync_dbg(sdata,
+                         "STA %pM : offset was invalid, sta->t_offset=%lld\n",
                          sta->sta.addr,
                          (long long) sta->t_offset);
                rcu_read_unlock();
@@ -226,17 +221,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
                 * to the driver tsf setter, we punt
                 * the tsf adjustment to the mesh tasklet
                 */
-               msync_dbg("TBTT : kicking off TBTT "
-                         "adjustment with "
-                         "clockdrift_max=%lld",
-                 ifmsh->sync_offset_clockdrift_max);
+               msync_dbg(sdata,
+                         "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n",
+                         ifmsh->sync_offset_clockdrift_max);
                set_bit(MESH_WORK_DRIFT_ADJUST,
                        &ifmsh->wrkq_flags);
        } else {
-               msync_dbg("TBTT : max clockdrift=%lld; "
-                         "too small to adjust",
-                         (long long)
-                      ifmsh->sync_offset_clockdrift_max);
+               msync_dbg(sdata,
+                         "TBTT : max clockdrift=%lld; too small to adjust\n",
+                         (long long)ifmsh->sync_offset_clockdrift_max);
                ifmsh->sync_offset_clockdrift_max = 0;
        }
        spin_unlock_bh(&ifmsh->sync_offset_lock);
@@ -268,7 +261,7 @@ static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        const u8 *oui;
 
        WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-       msync_dbg("called mesh_sync_vendor_rx_bcn_presp");
+       msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n");
        oui = mesh_get_vendor_oui(sdata);
        /*  here you would implement the vendor offset tracking for this oui */
 }
@@ -278,7 +271,7 @@ static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
        const u8 *oui;
 
        WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
-       msync_dbg("called mesh_sync_vendor_adjust_tbtt");
+       msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n");
        oui = mesh_get_vendor_oui(sdata);
        /*  here you would implement the vendor tsf adjustment for this oui */
 }
index 0db5d34a06b69c8c72798a8a7d4e6c4f642f7560..aa69a331f374bceb37258c76bd681f247508f863 100644 (file)
@@ -258,12 +258,11 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
 }
 
 static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
-                               struct sk_buff *skb, const u8 *ht_oper_ie,
+                               struct sk_buff *skb, u8 ap_ht_param,
                                struct ieee80211_supported_band *sband,
                                struct ieee80211_channel *channel,
                                enum ieee80211_smps_mode smps)
 {
-       struct ieee80211_ht_operation *ht_oper;
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap;
@@ -271,21 +270,13 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
 
        BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
 
-       if (!ht_oper_ie)
-               return;
-
-       if (ht_oper_ie[1] < sizeof(struct ieee80211_ht_operation))
-               return;
-
        memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
        ieee80211_apply_htcap_overrides(sdata, &ht_cap);
 
-       ht_oper = (struct ieee80211_ht_operation *)(ht_oper_ie + 2);
-
        /* determine capability flags */
        cap = ht_cap.cap;
 
-       switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+       switch (ap_ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
                        cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -509,7 +500,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
-               ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_operation_ie,
+               ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
                                    sband, local->oper_channel, ifmgd->ap_smps);
 
        /* if present, add any custom non-vendor IEs that go after HT */
@@ -939,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                return;
        }
 
-       if (!list_empty(&local->work_list)) {
-               local->ps_sdata = NULL;
-               goto change;
-       }
-
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
@@ -1016,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                local->ps_sdata = NULL;
        }
 
- change:
        ieee80211_change_ps(local);
 }
 
@@ -1156,7 +1141,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 
        memset(&params, 0, sizeof(params));
 
-       local->wmm_acm = 0;
+       sdata->wmm_acm = 0;
        for (; left >= 4; left -= 4, pos += 4) {
                int aci = (pos[0] >> 5) & 0x03;
                int acm = (pos[0] >> 4) & 0x01;
@@ -1167,21 +1152,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                case 1: /* AC_BK */
                        queue = 3;
                        if (acm)
-                               local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
+                               sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
                        if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
                                uapsd = true;
                        break;
                case 2: /* AC_VI */
                        queue = 1;
                        if (acm)
-                               local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
+                               sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
                        if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
                                uapsd = true;
                        break;
                case 3: /* AC_VO */
                        queue = 0;
                        if (acm)
-                               local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
+                               sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
                        if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
                                uapsd = true;
                        break;
@@ -1189,7 +1174,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                default:
                        queue = 2;
                        if (acm)
-                               local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
+                               sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
                        if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
                                uapsd = true;
                        break;
@@ -1201,19 +1186,16 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                params.txop = get_unaligned_le16(pos + 2);
                params.uapsd = uapsd;
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               wiphy_debug(local->hw.wiphy,
-                           "WMM queue=%d aci=%d acm=%d aifs=%d "
-                           "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
-                           queue, aci, acm,
-                           params.aifs, params.cw_min, params.cw_max,
-                           params.txop, params.uapsd);
-#endif
+               mlme_dbg(sdata,
+                        "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+                        queue, aci, acm,
+                        params.aifs, params.cw_min, params.cw_max,
+                        params.txop, params.uapsd);
                sdata->tx_conf[queue] = params;
                if (drv_conf_tx(local, sdata, queue, &params))
-                       wiphy_debug(local->hw.wiphy,
-                                   "failed to set TX queue parameters for queue %d\n",
-                                   queue);
+                       sdata_err(sdata,
+                                 "failed to set TX queue parameters for queue %d\n",
+                                 queue);
        }
 
        /* enable WMM or activate new settings */
@@ -1290,7 +1272,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        bss_info_changed |= BSS_CHANGED_BEACON_INT;
        bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-               cbss->capability, bss->has_erp_value, bss->erp_value);
+               bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
 
        sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
                IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
@@ -1581,11 +1563,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (beacon)
-               net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n",
-                                   sdata->name);
-#endif
+               mlme_dbg_ratelimited(sdata,
+                                    "detected beacon loss from AP - sending probe request\n");
+
+       ieee80211_cqm_rssi_notify(&sdata->vif,
+               NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
 
        /*
         * The driver/our work has already reported this event or the
@@ -1668,8 +1651,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
 
        memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
-       printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n",
-              sdata->name, bssid);
+       sdata_info(sdata, "Connection to AP %pM lost\n", bssid);
 
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
@@ -1803,9 +1785,10 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                return RX_MGMT_NONE;
 
        if (status_code != WLAN_STATUS_SUCCESS) {
-               printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
-                      sdata->name, mgmt->sa, status_code);
-               goto out;
+               sdata_info(sdata, "%pM denied authentication (status %d)\n",
+                          mgmt->sa, status_code);
+               ieee80211_destroy_auth_data(sdata, false);
+               return RX_MGMT_CFG80211_RX_AUTH;
        }
 
        switch (ifmgd->auth_data->algorithm) {
@@ -1826,8 +1809,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                return RX_MGMT_NONE;
        }
 
-       printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
- out:
+       sdata_info(sdata, "authenticated\n");
        ifmgd->auth_data->done = true;
        ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
        run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -1840,8 +1822,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                goto out_err;
        }
        if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) {
-               printk(KERN_DEBUG "%s: failed moving %pM to auth\n",
-                      sdata->name, bssid);
+               sdata_info(sdata, "failed moving %pM to auth\n", bssid);
                goto out_err;
        }
        mutex_unlock(&sdata->local->sta_mtx);
@@ -1875,8 +1856,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
-                       sdata->name, bssid, reason_code);
+       sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n",
+                  bssid, reason_code);
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
@@ -1906,8 +1887,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
-                       sdata->name, mgmt->sa, reason_code);
+       sdata_info(sdata, "disassociated from %pM (Reason: %u)\n",
+                  mgmt->sa, reason_code);
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
@@ -1999,17 +1980,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 
        if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-               printk(KERN_DEBUG
-                      "%s: invalid AID value 0x%x; bits 15:14 not set\n",
-                      sdata->name, aid);
+               sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n",
+                          aid);
        aid &= ~(BIT(15) | BIT(14));
 
        ifmgd->broken_ap = false;
 
        if (aid == 0 || aid > IEEE80211_MAX_AID) {
-               printk(KERN_DEBUG
-                      "%s: invalid AID value %d (out of range), turn off PS\n",
-                      sdata->name, aid);
+               sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n",
+                          aid);
                aid = 0;
                ifmgd->broken_ap = true;
        }
@@ -2018,8 +1997,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 
        if (!elems.supp_rates) {
-               printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-                      sdata->name);
+               sdata_info(sdata, "no SuppRates element in AssocResp\n");
                return false;
        }
 
@@ -2059,9 +2037,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
                err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
        if (err) {
-               printk(KERN_DEBUG
-                      "%s: failed to move station %pM to desired state\n",
-                      sdata->name, sta->sta.addr);
+               sdata_info(sdata,
+                          "failed to move station %pM to desired state\n",
+                          sta->sta.addr);
                WARN_ON(__sta_info_destroy(sta));
                mutex_unlock(&sdata->local->sta_mtx);
                return false;
@@ -2144,10 +2122,10 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
        aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
 
-       printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
-              "status=%d aid=%d)\n",
-              sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
-              capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+       sdata_info(sdata,
+                  "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
+                  reassoc ? "Rea" : "A", mgmt->sa,
+                  capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
 
        pos = mgmt->u.assoc_resp.variable;
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
@@ -2158,9 +2136,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                u32 tu, ms;
                tu = get_unaligned_le32(elems.timeout_int + 1);
                ms = tu * 1024 / 1000;
-               printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
-                      "comeback duration %u TU (%u ms)\n",
-                      sdata->name, mgmt->sa, tu, ms);
+               sdata_info(sdata,
+                          "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
+                          mgmt->sa, tu, ms);
                assoc_data->timeout = jiffies + msecs_to_jiffies(ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
                        run_again(ifmgd, assoc_data->timeout);
@@ -2170,8 +2148,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        *bss = assoc_data->bss;
 
        if (status_code != WLAN_STATUS_SUCCESS) {
-               printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
-                      sdata->name, mgmt->sa, status_code);
+               sdata_info(sdata, "%pM denied association (code=%d)\n",
+                          mgmt->sa, status_code);
                ieee80211_destroy_assoc_data(sdata, false);
        } else {
                if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
@@ -2180,7 +2158,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                        cfg80211_put_bss(*bss);
                        return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
                }
-               printk(KERN_DEBUG "%s: associated\n", sdata->name);
+               sdata_info(sdata, "associated\n");
 
                /*
                 * destroy assoc_data afterwards, as otherwise an idle
@@ -2280,7 +2258,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
            ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
                /* got probe response, continue with auth */
-               printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
+               sdata_info(sdata, "direct probe responded\n");
                ifmgd->auth_data->tries = 0;
                ifmgd->auth_data->timeout = jiffies;
                run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -2416,10 +2394,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        }
 
        if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n",
-                                   sdata->name);
-#endif
+               mlme_dbg_ratelimited(sdata,
+                                    "cancelling probereq poll due to a received beacon\n");
                mutex_lock(&local->mtx);
                ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
                ieee80211_run_deferred_scan(local);
@@ -2642,8 +2618,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        auth_data->tries++;
 
        if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: authentication with %pM timed out\n",
-                      sdata->name, auth_data->bss->bssid);
+               sdata_info(sdata, "authentication with %pM timed out\n",
+                          auth_data->bss->bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
@@ -2655,9 +2631,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        }
 
        if (auth_data->bss->proberesp_ies) {
-               printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n",
-                      sdata->name, auth_data->bss->bssid, auth_data->tries,
-                      IEEE80211_AUTH_MAX_TRIES);
+               sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
+                          auth_data->bss->bssid, auth_data->tries,
+                          IEEE80211_AUTH_MAX_TRIES);
 
                auth_data->expected_transaction = 2;
                ieee80211_send_auth(sdata, 1, auth_data->algorithm,
@@ -2667,9 +2643,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
        } else {
                const u8 *ssidie;
 
-               printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
-                      sdata->name, auth_data->bss->bssid, auth_data->tries,
-                      IEEE80211_AUTH_MAX_TRIES);
+               sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
+                          auth_data->bss->bssid, auth_data->tries,
+                          IEEE80211_AUTH_MAX_TRIES);
 
                ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
                if (!ssidie)
@@ -2697,8 +2673,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
 
        assoc_data->tries++;
        if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: association with %pM timed out\n",
-                      sdata->name, assoc_data->bss->bssid);
+               sdata_info(sdata, "association with %pM timed out\n",
+                          assoc_data->bss->bssid);
 
                /*
                 * Most likely AP is not in the range so remove the
@@ -2709,9 +2685,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
                return -ETIMEDOUT;
        }
 
-       printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n",
-              sdata->name, assoc_data->bss->bssid, assoc_data->tries,
-              IEEE80211_ASSOC_MAX_TRIES);
+       sdata_info(sdata, "associate with %pM (try %d/%d)\n",
+                  assoc_data->bss->bssid, assoc_data->tries,
+                  IEEE80211_ASSOC_MAX_TRIES);
        ieee80211_send_assoc(sdata);
 
        assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
@@ -2784,45 +2760,31 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                        ieee80211_reset_ap_probe(sdata);
                else if (ifmgd->nullfunc_failed) {
                        if (ifmgd->probe_send_count < max_tries) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                               wiphy_debug(local->hw.wiphy,
-                                           "%s: No ack for nullfunc frame to"
-                                           " AP %pM, try %d/%i\n",
-                                           sdata->name, bssid,
-                                           ifmgd->probe_send_count, max_tries);
-#endif
+                               mlme_dbg(sdata,
+                                        "No ack for nullfunc frame to AP %pM, try %d/%i\n",
+                                        bssid, ifmgd->probe_send_count,
+                                        max_tries);
                                ieee80211_mgd_probe_ap_send(sdata);
                        } else {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                               wiphy_debug(local->hw.wiphy,
-                                           "%s: No ack for nullfunc frame to"
-                                           " AP %pM, disconnecting.\n",
-                                           sdata->name, bssid);
-#endif
+                               mlme_dbg(sdata,
+                                        "No ack for nullfunc frame to AP %pM, disconnecting.\n",
+                                        bssid);
                                ieee80211_sta_connection_lost(sdata, bssid,
                                        WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                        }
                } else if (time_is_after_jiffies(ifmgd->probe_timeout))
                        run_again(ifmgd, ifmgd->probe_timeout);
                else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       wiphy_debug(local->hw.wiphy,
-                                   "%s: Failed to send nullfunc to AP %pM"
-                                   " after %dms, disconnecting.\n",
-                                   sdata->name,
-                                   bssid, probe_wait_ms);
-#endif
+                       mlme_dbg(sdata,
+                                "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
+                                bssid, probe_wait_ms);
                        ieee80211_sta_connection_lost(sdata, bssid,
                                WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                } else if (ifmgd->probe_send_count < max_tries) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       wiphy_debug(local->hw.wiphy,
-                                   "%s: No probe response from AP %pM"
-                                   " after %dms, try %d/%i\n",
-                                   sdata->name,
-                                   bssid, probe_wait_ms,
-                                   ifmgd->probe_send_count, max_tries);
-#endif
+                       mlme_dbg(sdata,
+                                "No probe response from AP %pM after %dms, try %d/%i\n",
+                                bssid, probe_wait_ms,
+                                ifmgd->probe_send_count, max_tries);
                        ieee80211_mgd_probe_ap_send(sdata);
                } else {
                        /*
@@ -2937,11 +2899,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
                sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
                mutex_lock(&ifmgd->mtx);
                if (ifmgd->associated) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       wiphy_debug(sdata->local->hw.wiphy,
-                                   "%s: driver requested disconnect after resume.\n",
-                                   sdata->name);
-#endif
+                       mlme_dbg(sdata,
+                                "driver requested disconnect after resume\n");
                        ieee80211_sta_connection_lost(sdata,
                                ifmgd->associated->bssid,
                                WLAN_REASON_UNSPECIFIED);
@@ -3029,7 +2988,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss *bss = (void *)cbss->priv;
-       struct sta_info *sta;
+       struct sta_info *sta = NULL;
        bool have_sta = false;
        int err;
        int ht_cfreq;
@@ -3082,13 +3041,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                         * since we look at probe response/beacon data here
                         * it should be OK.
                         */
-                       printk(KERN_DEBUG
-                              "%s: Wrong control channel: center-freq: %d"
-                              " ht-cfreq: %d ht->primary_chan: %d"
-                              " band: %d. Disabling HT.\n",
-                              sdata->name, cbss->channel->center_freq,
-                              ht_cfreq, ht_oper->primary_chan,
-                              cbss->channel->band);
+                       sdata_info(sdata,
+                                  "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
+                                  cbss->channel->center_freq,
+                                  ht_cfreq, ht_oper->primary_chan,
+                                  cbss->channel->band);
                        ht_oper = NULL;
                }
        }
@@ -3112,9 +3069,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
                /* can only fail due to HT40+/- mismatch */
                channel_type = NL80211_CHAN_HT20;
-               printk(KERN_DEBUG
-                      "%s: disabling 40 MHz due to multi-vif mismatch\n",
-                      sdata->name);
+               sdata_info(sdata,
+                          "disabling 40 MHz due to multi-vif mismatch\n");
                ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
                WARN_ON(!ieee80211_set_channel_type(local, sdata,
                                                    channel_type));
@@ -3123,7 +3079,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        local->oper_channel = cbss->channel;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-       if (!have_sta) {
+       if (sta) {
                u32 rates = 0, basic_rates = 0;
                bool have_higher_than_11mbit;
                int min_rate = INT_MAX, min_rate_index = -1;
@@ -3143,9 +3099,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                 * we can connect -- with a warning.
                 */
                if (!basic_rates && min_rate_index >= 0) {
-                       printk(KERN_DEBUG
-                              "%s: No basic rates, using min rate instead.\n",
-                              sdata->name);
+                       sdata_info(sdata,
+                                  "No basic rates, using min rate instead\n");
                        basic_rates = BIT(min_rate_index);
                }
 
@@ -3171,9 +3126,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                err = sta_info_insert(sta);
                sta = NULL;
                if (err) {
-                       printk(KERN_DEBUG
-                              "%s: failed to insert STA entry for the AP (error %d)\n",
-                              sdata->name, err);
+                       sdata_info(sdata,
+                                  "failed to insert STA entry for the AP (error %d)\n",
+                                  err);
                        return err;
                }
        } else
@@ -3251,8 +3206,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->associated)
                ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-       printk(KERN_DEBUG "%s: authenticate with %pM\n",
-              sdata->name, req->bss->bssid);
+       sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
 
        err = ieee80211_prep_connection(sdata, req->bss, false);
        if (err)
@@ -3287,7 +3241,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_bss *bss = (void *)req->bss->priv;
        struct ieee80211_mgd_assoc_data *assoc_data;
        struct ieee80211_supported_band *sband;
-       const u8 *ssidie;
+       const u8 *ssidie, *ht_ie;
        int i, err;
 
        ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
@@ -3335,11 +3289,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
         * We can set this to true for non-11n hardware, that'll be checked
         * separately along with the peer capabilities.
         */
-       for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+       for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) {
                if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
-                   req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+                   req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
                        ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+                       netdev_info(sdata->dev,
+                                   "disabling HT due to WEP/TKIP use\n");
+               }
+       }
 
        if (req->flags & ASSOC_REQ_DISABLE_HT)
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
@@ -3347,8 +3305,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
-           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
+           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+               netdev_info(sdata->dev,
+                           "disabling HT as WMM/QoS is not supported\n");
+       }
 
        memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
        memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
@@ -3374,8 +3335,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                          (local->hw.queues >= IEEE80211_NUM_ACS);
        assoc_data->supp_rates = bss->supp_rates;
        assoc_data->supp_rates_len = bss->supp_rates_len;
-       assoc_data->ht_operation_ie =
-               ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+
+       ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION);
+       if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation))
+               assoc_data->ap_ht_param =
+                       ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
+       else
+               ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 
        if (bss->wmm_used && bss->uapsd_supported &&
            (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
@@ -3422,8 +3388,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                 * Wait up to one beacon interval ...
                 * should this be more if we miss one?
                 */
-               printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
-                      sdata->name, ifmgd->bssid);
+               sdata_info(sdata, "waiting for beacon from %pM\n",
+                          ifmgd->bssid);
                assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
        } else {
                assoc_data->have_beacon = true;
@@ -3442,8 +3408,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                                corrupt_type = "beacon";
                } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
                        corrupt_type = "probe response";
-               printk(KERN_DEBUG "%s: associating with AP with corrupt %s\n",
-                      sdata->name, corrupt_type);
+               sdata_info(sdata, "associating with AP with corrupt %s\n",
+                          corrupt_type);
        }
 
        err = 0;
@@ -3472,9 +3438,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                return 0;
        }
 
-       printk(KERN_DEBUG
-              "%s: deauthenticating from %pM by local choice (reason=%d)\n",
-              sdata->name, req->bssid, req->reason_code);
+       sdata_info(sdata,
+                  "deauthenticating from %pM by local choice (reason=%d)\n",
+                  req->bssid, req->reason_code);
 
        if (ifmgd->associated &&
            ether_addr_equal(ifmgd->associated->bssid, req->bssid))
@@ -3516,8 +3482,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                return -ENOLINK;
        }
 
-       printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
-              sdata->name, req->bss->bssid, req->reason_code);
+       sdata_info(sdata,
+                  "disassociating from %pM by local choice (reason=%d)\n",
+                  req->bss->bssid, req->reason_code);
 
        memcpy(bssid, req->bss->bssid, ETH_ALEN);
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC,
@@ -3558,10 +3525,3 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
-
-unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif)
-{
-       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-       return sdata->dev->operstate;
-}
-EXPORT_SYMBOL(ieee80211_get_operstate);
index 935aa4b6deee0220737ee4c1cebad69472dea343..b0fb6a2b89ad751cd1a47d594942913582e556f7 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/export.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-#include "driver-trace.h"
+#include "driver-ops.h"
 
 /*
  * Tell our hardware to disable PS.
@@ -24,8 +24,7 @@
  * because we *may* be doing work on-operating channel, and want our
  * hardware unconditionally awake, but still let the AP send us normal frames.
  */
-static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
-                                          bool tell_ap)
+static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -46,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata,
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
        }
 
-       if (tell_ap && (!local->offchannel_ps_enabled ||
-                       !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)))
+       if (!local->offchannel_ps_enabled ||
+           !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
                /*
                 * If power save was enabled, no need to send a nullfunc
                 * frame because AP knows that we are sleeping. But if the
@@ -132,7 +131,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
                        if (offchannel_ps_enable &&
                            (sdata->vif.type == NL80211_IFTYPE_STATION) &&
                            sdata->u.mgd.associated)
-                               ieee80211_offchannel_ps_enable(sdata, true);
+                               ieee80211_offchannel_ps_enable(sdata);
                }
        }
        mutex_unlock(&local->iflist_mtx);
@@ -181,34 +180,58 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
        mutex_unlock(&local->iflist_mtx);
 }
 
+void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
+{
+       if (roc->notified)
+               return;
+
+       if (roc->mgmt_tx_cookie) {
+               if (!WARN_ON(!roc->frame)) {
+                       ieee80211_tx_skb(roc->sdata, roc->frame);
+                       roc->frame = NULL;
+               }
+       } else {
+               cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc,
+                                         roc->chan, roc->chan_type,
+                                         roc->req_duration, GFP_KERNEL);
+       }
+
+       roc->notified = true;
+}
+
 static void ieee80211_hw_roc_start(struct work_struct *work)
 {
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, hw_roc_start);
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_roc_work *roc, *dep, *tmp;
 
        mutex_lock(&local->mtx);
 
-       if (!local->hw_roc_channel) {
-               mutex_unlock(&local->mtx);
-               return;
-       }
+       if (list_empty(&local->roc_list))
+               goto out_unlock;
 
-       if (local->hw_roc_skb) {
-               sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
-               ieee80211_tx_skb(sdata, local->hw_roc_skb);
-               local->hw_roc_skb = NULL;
-       } else {
-               cfg80211_ready_on_channel(local->hw_roc_dev,
-                                         local->hw_roc_cookie,
-                                         local->hw_roc_channel,
-                                         local->hw_roc_channel_type,
-                                         local->hw_roc_duration,
-                                         GFP_KERNEL);
-       }
+       roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+                              list);
+
+       if (!roc->started)
+               goto out_unlock;
 
-       ieee80211_recalc_idle(local);
+       roc->hw_begun = true;
+       roc->hw_start_time = local->hw_roc_start_time;
 
+       ieee80211_handle_roc_started(roc);
+       list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
+               ieee80211_handle_roc_started(dep);
+
+               if (dep->duration > roc->duration) {
+                       u32 dur = dep->duration;
+                       dep->duration = dur - roc->duration;
+                       roc->duration = dur;
+                       list_del(&dep->list);
+                       list_add(&dep->list, &roc->list);
+               }
+       }
+ out_unlock:
        mutex_unlock(&local->mtx);
 }
 
@@ -216,52 +239,179 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
+       local->hw_roc_start_time = jiffies;
+
        trace_api_ready_on_channel(local);
 
        ieee80211_queue_work(hw, &local->hw_roc_start);
 }
 EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
 
-static void ieee80211_hw_roc_done(struct work_struct *work)
+void ieee80211_start_next_roc(struct ieee80211_local *local)
 {
-       struct ieee80211_local *local =
-               container_of(work, struct ieee80211_local, hw_roc_done);
+       struct ieee80211_roc_work *roc;
 
-       mutex_lock(&local->mtx);
+       lockdep_assert_held(&local->mtx);
 
-       if (!local->hw_roc_channel) {
-               mutex_unlock(&local->mtx);
+       if (list_empty(&local->roc_list)) {
+               ieee80211_run_deferred_scan(local);
                return;
        }
 
-       /* was never transmitted */
-       if (local->hw_roc_skb) {
-               u64 cookie;
+       roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+                              list);
 
-               cookie = local->hw_roc_cookie ^ 2;
+       if (WARN_ON_ONCE(roc->started))
+               return;
+
+       if (local->ops->remain_on_channel) {
+               int ret, duration = roc->duration;
+
+               /* XXX: duplicated, see ieee80211_start_roc_work() */
+               if (!duration)
+                       duration = 10;
+
+               ret = drv_remain_on_channel(local, roc->chan,
+                                           roc->chan_type,
+                                           duration);
+
+               roc->started = true;
+
+               if (ret) {
+                       wiphy_warn(local->hw.wiphy,
+                                  "failed to start next HW ROC (%d)\n", ret);
+                       /*
+                        * queue the work struct again to avoid recursion
+                        * when multiple failures occur
+                        */
+                       ieee80211_remain_on_channel_expired(&local->hw);
+               }
+       } else {
+               /* delay it a bit */
+               ieee80211_queue_delayed_work(&local->hw, &roc->work,
+                                            round_jiffies_relative(HZ/2));
+       }
+}
 
-               cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
-                                       local->hw_roc_skb->data,
-                                       local->hw_roc_skb->len, false,
-                                       GFP_KERNEL);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+{
+       struct ieee80211_roc_work *dep, *tmp;
 
-               kfree_skb(local->hw_roc_skb);
-               local->hw_roc_skb = NULL;
-               local->hw_roc_skb_for_status = NULL;
+       /* was never transmitted */
+       if (roc->frame) {
+               cfg80211_mgmt_tx_status(roc->sdata->dev,
+                                       (unsigned long)roc->frame,
+                                       roc->frame->data, roc->frame->len,
+                                       false, GFP_KERNEL);
+               kfree_skb(roc->frame);
        }
 
-       if (!local->hw_roc_for_tx)
-               cfg80211_remain_on_channel_expired(local->hw_roc_dev,
-                                                  local->hw_roc_cookie,
-                                                  local->hw_roc_channel,
-                                                  local->hw_roc_channel_type,
+       if (!roc->mgmt_tx_cookie)
+               cfg80211_remain_on_channel_expired(roc->sdata->dev,
+                                                  (unsigned long)roc,
+                                                  roc->chan, roc->chan_type,
                                                   GFP_KERNEL);
 
-       local->hw_roc_channel = NULL;
-       local->hw_roc_cookie = 0;
+       list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
+               ieee80211_roc_notify_destroy(dep);
+
+       kfree(roc);
+}
+
+void ieee80211_sw_roc_work(struct work_struct *work)
+{
+       struct ieee80211_roc_work *roc =
+               container_of(work, struct ieee80211_roc_work, work.work);
+       struct ieee80211_sub_if_data *sdata = roc->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       mutex_lock(&local->mtx);
+
+       if (roc->abort)
+               goto finish;
+
+       if (WARN_ON(list_empty(&local->roc_list)))
+               goto out_unlock;
+
+       if (WARN_ON(roc != list_first_entry(&local->roc_list,
+                                           struct ieee80211_roc_work,
+                                           list)))
+               goto out_unlock;
 
-       ieee80211_recalc_idle(local);
+       if (!roc->started) {
+               struct ieee80211_roc_work *dep;
 
+               /* start this ROC */
+
+               /* switch channel etc */
+               ieee80211_recalc_idle(local);
+
+               local->tmp_channel = roc->chan;
+               local->tmp_channel_type = roc->chan_type;
+               ieee80211_hw_config(local, 0);
+
+               /* tell userspace or send frame */
+               ieee80211_handle_roc_started(roc);
+               list_for_each_entry(dep, &roc->dependents, list)
+                       ieee80211_handle_roc_started(dep);
+
+               /* if it was pure TX, just finish right away */
+               if (!roc->duration)
+                       goto finish;
+
+               roc->started = true;
+               ieee80211_queue_delayed_work(&local->hw, &roc->work,
+                                            msecs_to_jiffies(roc->duration));
+       } else {
+               /* finish this ROC */
+ finish:
+               list_del(&roc->list);
+               ieee80211_roc_notify_destroy(roc);
+
+               if (roc->started) {
+                       drv_flush(local, false);
+
+                       local->tmp_channel = NULL;
+                       ieee80211_hw_config(local, 0);
+
+                       ieee80211_offchannel_return(local, true);
+               }
+
+               ieee80211_recalc_idle(local);
+
+               if (roc->started)
+                       ieee80211_start_next_roc(local);
+       }
+
+ out_unlock:
+       mutex_unlock(&local->mtx);
+}
+
+static void ieee80211_hw_roc_done(struct work_struct *work)
+{
+       struct ieee80211_local *local =
+               container_of(work, struct ieee80211_local, hw_roc_done);
+       struct ieee80211_roc_work *roc;
+
+       mutex_lock(&local->mtx);
+
+       if (list_empty(&local->roc_list))
+               goto out_unlock;
+
+       roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
+                              list);
+
+       if (!roc->started)
+               goto out_unlock;
+
+       list_del(&roc->list);
+
+       ieee80211_roc_notify_destroy(roc);
+
+       /* if there's another roc, start it now */
+       ieee80211_start_next_roc(local);
+
+ out_unlock:
        mutex_unlock(&local->mtx);
 }
 
@@ -275,8 +425,47 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
 
-void ieee80211_hw_roc_setup(struct ieee80211_local *local)
+void ieee80211_roc_setup(struct ieee80211_local *local)
 {
        INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
        INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
+       INIT_LIST_HEAD(&local->roc_list);
+}
+
+void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_roc_work *roc, *tmp;
+       LIST_HEAD(tmp_list);
+
+       mutex_lock(&local->mtx);
+       list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
+               if (roc->sdata != sdata)
+                       continue;
+
+               if (roc->started && local->ops->remain_on_channel) {
+                       /* can race, so ignore return value */
+                       drv_cancel_remain_on_channel(local);
+               }
+
+               list_move_tail(&roc->list, &tmp_list);
+               roc->abort = true;
+       }
+
+       ieee80211_start_next_roc(local);
+       mutex_unlock(&local->mtx);
+
+       list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
+               if (local->ops->remain_on_channel) {
+                       list_del(&roc->list);
+                       ieee80211_roc_notify_destroy(roc);
+               } else {
+                       ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
+
+                       /* work will clean up etc */
+                       flush_delayed_work(&roc->work);
+               }
+       }
+
+       WARN_ON_ONCE(!list_empty(&tmp_list));
 }
index af1c4e26e9657ead3f75d9e622ae472170a15b07..5c572e7a1a71dc76949b993f9f57e79223533f49 100644 (file)
@@ -77,6 +77,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                int err = drv_suspend(local, wowlan);
                if (err < 0) {
                        local->quiescing = false;
+                       local->wowlan = false;
+                       if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+                               mutex_lock(&local->sta_mtx);
+                               list_for_each_entry(sta,
+                                                   &local->sta_list, list) {
+                                       clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
+                               }
+                               mutex_unlock(&local->sta_mtx);
+                       }
+                       ieee80211_wake_queues_by_reason(hw,
+                                       IEEE80211_QUEUE_STOP_REASON_SUSPEND);
                        return err;
                } else if (err > 0) {
                        WARN_ON(err != 1);
index 965e6ec0adb6c12393ced183a44463a63e09a9ff..839cac8fab57425e70623fe85da8107d957c0dac 100644 (file)
@@ -554,11 +554,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
 }
 
 
-static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
+static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
                                            struct tid_ampdu_rx *tid_agg_rx,
                                            int index)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
        struct ieee80211_rx_status *status;
 
@@ -578,7 +578,7 @@ no_frame:
        tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
 }
 
-static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
                                             struct tid_ampdu_rx *tid_agg_rx,
                                             u16 head_seq_num)
 {
@@ -589,7 +589,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
        while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
-               ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+               ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
        }
 }
 
@@ -604,7 +604,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
  */
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
-static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
+static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                                          struct tid_ampdu_rx *tid_agg_rx)
 {
        int index, j;
@@ -632,12 +632,9 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
                                        HT_RX_REORDER_BUF_TIMEOUT))
                                goto set_release_timer;
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-                       if (net_ratelimit())
-                               wiphy_debug(hw->wiphy,
-                                           "release an RX reorder frame due to timeout on earlier frames\n");
-#endif
-                       ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
+                       ht_dbg_ratelimited(sdata,
+                                          "release an RX reorder frame due to timeout on earlier frames\n");
+                       ieee80211_release_reorder_frame(sdata, tid_agg_rx, j);
 
                        /*
                         * Increment the head seq# also for the skipped slots.
@@ -647,7 +644,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
                        skipped = 0;
                }
        } else while (tid_agg_rx->reorder_buf[index]) {
-               ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+               ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
        }
@@ -677,7 +674,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
  * rcu_read_lock protection. It returns false if the frame
  * can be processed immediately, true if it was consumed.
  */
-static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
                                             struct tid_ampdu_rx *tid_agg_rx,
                                             struct sk_buff *skb)
 {
@@ -706,7 +703,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
                head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
                /* release stored frames up to new head to stack */
-               ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
+               ieee80211_release_reorder_frames(sdata, tid_agg_rx,
+                                                head_seq_num);
        }
 
        /* Now the new frame is always in the range of the reordering buffer */
@@ -736,7 +734,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        tid_agg_rx->reorder_buf[index] = skb;
        tid_agg_rx->reorder_time[index] = jiffies;
        tid_agg_rx->stored_mpdu_num++;
-       ieee80211_sta_reorder_release(hw, tid_agg_rx);
+       ieee80211_sta_reorder_release(sdata, tid_agg_rx);
 
  out:
        spin_unlock(&tid_agg_rx->reorder_lock);
@@ -751,7 +749,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
 {
        struct sk_buff *skb = rx->skb;
        struct ieee80211_local *local = rx->local;
-       struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
@@ -813,7 +810,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
         * sure that we cannot get to it any more before doing
         * anything with it.
         */
-       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb))
+       if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb))
                return;
 
  dont_reorder:
@@ -1136,24 +1133,18 @@ static void ap_sta_ps_start(struct sta_info *sta)
        set_sta_flag(sta, WLAN_STA_PS_STA);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
-              sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+       ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
+              sta->sta.addr, sta->sta.aid);
 }
 
 static void ap_sta_ps_end(struct sta_info *sta)
 {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
-              sta->sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+       ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
+              sta->sta.addr, sta->sta.aid);
 
        if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
-                      sta->sdata->name, sta->sta.addr, sta->sta.aid);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+               ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
+                      sta->sta.addr, sta->sta.aid);
                return;
        }
 
@@ -1383,19 +1374,8 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
        if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
                sdata->fragment_next = 0;
 
-       if (!skb_queue_empty(&entry->skb_list)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) entry->skb_list.next->data;
-               printk(KERN_DEBUG "%s: RX reassembly removed oldest "
-                      "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
-                      "addr1=%pM addr2=%pM\n",
-                      sdata->name, idx,
-                      jiffies - entry->first_frag_time, entry->seq,
-                      entry->last_frag, hdr->addr1, hdr->addr2);
-#endif
+       if (!skb_queue_empty(&entry->skb_list))
                __skb_queue_purge(&entry->skb_list);
-       }
 
        __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
        *skb = NULL;
@@ -1753,7 +1733,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                         */
                        xmit_skb = skb_copy(skb, GFP_ATOMIC);
                        if (!xmit_skb)
-                               net_dbg_ratelimited("%s: failed to clone multicast frame\n",
+                               net_info_ratelimited("%s: failed to clone multicast frame\n",
                                                    dev->name);
                } else {
                        dsta = sta_info_get(sdata, skb->data);
@@ -1937,7 +1917,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            ether_addr_equal(sdata->vif.addr, hdr->addr3))
                return RX_CONTINUE;
 
-       q = ieee80211_select_queue_80211(local, skb, hdr);
+       q = ieee80211_select_queue_80211(sdata, skb, hdr);
        if (ieee80211_queue_stopped(&local->hw, q)) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
                return RX_DROP_MONITOR;
@@ -1957,7 +1937,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        fwd_skb = skb_copy(skb, GFP_ATOMIC);
        if (!fwd_skb) {
-               net_dbg_ratelimited("%s: failed to clone mesh frame\n",
+               net_info_ratelimited("%s: failed to clone mesh frame\n",
                                    sdata->name);
                goto out;
        }
@@ -2060,8 +2040,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_local *local = rx->local;
-       struct ieee80211_hw *hw = &local->hw;
        struct sk_buff *skb = rx->skb;
        struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
        struct tid_ampdu_rx *tid_agg_rx;
@@ -2098,7 +2076,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 
                spin_lock(&tid_agg_rx->reorder_lock);
                /* release stored frames up to start of BAR */
-               ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
+               ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
+                                                start_seq_num);
                spin_unlock(&tid_agg_rx->reorder_lock);
 
                kfree_skb(skb);
@@ -2752,7 +2731,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                return;
 
        spin_lock(&tid_agg_rx->reorder_lock);
-       ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx);
+       ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx);
        spin_unlock(&tid_agg_rx->reorder_lock);
 
        ieee80211_rx_handlers(&rx);
@@ -3032,6 +3011,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (unlikely(local->quiescing || local->suspended))
                goto drop;
 
+       /* We might be during a HW reconfig, prevent Rx for the same reason */
+       if (unlikely(local->in_reconfig))
+               goto drop;
+
        /*
         * The same happens when we're not even started,
         * but that's worth a warning.
index 169da0742c817507e09a0119f1d1105077784231..379f178eab5f162a7c77f7f1ff66315b901f0f0b 100644 (file)
@@ -323,7 +323,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        ieee80211_mlme_notify_scan_completed(local);
        ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
-       ieee80211_queue_work(&local->hw, &local->work_work);
+       ieee80211_start_next_roc(local);
 }
 
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -376,7 +376,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 static bool ieee80211_can_scan(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata)
 {
-       if (!list_empty(&local->work_list))
+       if (!list_empty(&local->roc_list))
                return false;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
index de455f8bbb91c0ffbedd2c911623380946d07d0b..06fa75ceb0251e6064d90661bf7b5e61f979b72c 100644 (file)
@@ -169,9 +169,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
        if (sta->rate_ctrl)
                rate_control_free_sta(sta);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
 
        kfree(sta);
 }
@@ -278,9 +276,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
 #ifdef CONFIG_MAC80211_MESH
        sta->plink_state = NL80211_PLINK_LISTEN;
@@ -333,9 +329,9 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local,
        }
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               printk(KERN_DEBUG
-                      "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n",
-                      sdata->name, sta->sta.addr, state + 1, err);
+               sdata_info(sdata,
+                          "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n",
+                          sta->sta.addr, state + 1, err);
                err = 0;
        }
 
@@ -390,9 +386,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        sinfo.generation = local->sta_generation;
        cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
        /* move reference to rcu-protected */
        rcu_read_lock();
@@ -618,10 +612,8 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
                        break;
 
                local->total_ps_buffered--;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
+               ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
                       sta->sta.addr);
-#endif
                dev_kfree_skb(skb);
        }
 
@@ -747,9 +739,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
                mesh_accept_plinks_update(sdata);
 #endif
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
+
        cancel_work_sync(&sta->drv_unblock_wk);
 
        cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
@@ -889,10 +880,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                        continue;
 
                if (time_after(jiffies, sta->last_rx + exp_time)) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-                       printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
-                              sdata->name, sta->sta.addr);
-#endif
+                       ibss_dbg(sdata, "expiring inactive STA %pM\n",
+                                sta->sta.addr);
                        WARN_ON(__sta_info_destroy(sta));
                }
        }
@@ -990,11 +979,9 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
        sta_info_recalc_tim(sta);
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
-              "since STA not sleeping anymore\n", sdata->name,
+       ps_dbg(sdata,
+              "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
               sta->sta.addr, sta->sta.aid, filtered, buffered);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
 static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
@@ -1384,10 +1371,8 @@ int sta_info_move_state(struct sta_info *sta,
                return -EINVAL;
        }
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
-               sta->sdata->name, sta->sta.addr, new_state);
-#endif
+       sta_dbg(sta->sdata, "moving STA %pM to state %d\n",
+               sta->sta.addr, new_state);
 
        /*
         * notify the driver before the actual changes so it can
index 28cfa981cfb13cfca0307687e3c3a144c5ed2d77..2ed2f27fe8a7db82e02905f4214c55ed23d631bd 100644 (file)
@@ -155,13 +155,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       if (net_ratelimit())
-               wiphy_debug(local->hw.wiphy,
-                           "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
-                           skb_queue_len(&sta->tx_filtered[ac]),
-                           !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
-#endif
+       ps_dbg_ratelimited(sta->sdata,
+                          "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
+                          skb_queue_len(&sta->tx_filtered[ac]),
+                          !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
        dev_kfree_skb(skb);
 }
 
@@ -520,36 +517,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
                u64 cookie = (unsigned long)skb;
+               acked = info->flags & IEEE80211_TX_STAT_ACK;
 
                if (ieee80211_is_nullfunc(hdr->frame_control) ||
-                   ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-                       acked = info->flags & IEEE80211_TX_STAT_ACK;
-
+                   ieee80211_is_qos_nullfunc(hdr->frame_control))
                        cfg80211_probe_status(skb->dev, hdr->addr1,
                                              cookie, acked, GFP_ATOMIC);
-               } else {
-                       struct ieee80211_work *wk;
-
-                       rcu_read_lock();
-                       list_for_each_entry_rcu(wk, &local->work_list, list) {
-                               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-                                       continue;
-                               if (wk->offchan_tx.frame != skb)
-                                       continue;
-                               wk->offchan_tx.status = true;
-                               break;
-                       }
-                       rcu_read_unlock();
-                       if (local->hw_roc_skb_for_status == skb) {
-                               cookie = local->hw_roc_cookie ^ 2;
-                               local->hw_roc_skb_for_status = NULL;
-                       }
-
+               else
                        cfg80211_mgmt_tx_status(
                                skb->dev, cookie, skb->data, skb->len,
-                               !!(info->flags & IEEE80211_TX_STAT_ACK),
-                               GFP_ATOMIC);
-               }
+                               acked, GFP_ATOMIC);
        }
 
        if (unlikely(info->ack_frame_id)) {
@@ -589,7 +566,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        /* send frame to monitor interfaces now */
        rtap_len = ieee80211_tx_radiotap_len(info);
        if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
-               printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+               pr_err("ieee80211_tx_status: headroom too small\n");
                dev_kfree_skb(skb);
                return;
        }
index 51077a956a83cdb025955bbfe367237a6784d136..57e14d59e12f76d062e5c10183a83ef61a337cb3 100644 (file)
@@ -260,17 +260,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
        keyid = pos[3];
        iv32 = get_unaligned_le32(pos + 4);
        pos += 8;
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-       {
-               int i;
-               printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
-               for (i = 0; i < payload_len; i++)
-                       printk(" %02x", payload[i]);
-               printk("\n");
-               printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
-                      iv16, iv32);
-       }
-#endif
 
        if (!(keyid & (1 << 5)))
                return TKIP_DECRYPT_NO_EXT_IV;
@@ -281,16 +270,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
        if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
            (iv32 < key->u.tkip.rx[queue].iv32 ||
             (iv32 == key->u.tkip.rx[queue].iv32 &&
-             iv16 <= key->u.tkip.rx[queue].iv16))) {
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-               printk(KERN_DEBUG "TKIP replay detected for RX frame from "
-                      "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
-                      ta,
-                      iv32, iv16, key->u.tkip.rx[queue].iv32,
-                      key->u.tkip.rx[queue].iv16);
-#endif
+             iv16 <= key->u.tkip.rx[queue].iv16)))
                return TKIP_DECRYPT_REPLAY;
-       }
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
@@ -302,22 +283,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
            key->u.tkip.rx[queue].iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
                tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-               {
-                       int i;
-                       u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY;
-                       printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM"
-                              " TK=", ta);
-                       for (i = 0; i < 16; i++)
-                               printk("%02x ",
-                                      key->conf.key[key_offset + i]);
-                       printk("\n");
-                       printk(KERN_DEBUG "TKIP decrypt: P1K=");
-                       for (i = 0; i < 5; i++)
-                               printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
-                       printk("\n");
-               }
-#endif
        }
        if (key->local->ops->update_tkip_key &&
            key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
@@ -333,15 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
        }
 
        tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-       {
-               int i;
-               printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
-               for (i = 0; i < 16; i++)
-                       printk("%02x ", rc4key[i]);
-               printk("\n");
-       }
-#endif
 
        res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
diff --git a/net/mac80211/trace.c b/net/mac80211/trace.c
new file mode 100644 (file)
index 0000000..386e45d
--- /dev/null
@@ -0,0 +1,75 @@
+/* bug in tracepoint.h, it should include this */
+#include <linux/module.h>
+
+/* sparse isn't too happy with all macros... */
+#ifndef __CHECKER__
+#include <net/cfg80211.h>
+#include "driver-ops.h"
+#include "debug.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+void __sdata_info(const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+
+       pr_info("%pV", &vaf);
+       trace_mac80211_info(&vaf);
+       va_end(args);
+}
+
+void __sdata_dbg(bool print, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+
+       if (print)
+               pr_debug("%pV", &vaf);
+       trace_mac80211_dbg(&vaf);
+       va_end(args);
+}
+
+void __sdata_err(const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+
+       pr_err("%pV", &vaf);
+       trace_mac80211_err(&vaf);
+       va_end(args);
+}
+
+void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+
+       if (print)
+               wiphy_dbg(wiphy, "%pV", &vaf);
+       trace_mac80211_dbg(&vaf);
+       va_end(args);
+}
+#endif
+#endif
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
new file mode 100644 (file)
index 0000000..2e60f4a
--- /dev/null
@@ -0,0 +1,1680 @@
+#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __MAC80211_DRIVER_TRACE
+
+#include <linux/tracepoint.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211
+
+#define MAXNAME                32
+#define LOCAL_ENTRY    __array(char, wiphy_name, 32)
+#define LOCAL_ASSIGN   strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME)
+#define LOCAL_PR_FMT   "%s"
+#define LOCAL_PR_ARG   __entry->wiphy_name
+
+#define STA_ENTRY      __array(char, sta_addr, ETH_ALEN)
+#define STA_ASSIGN     (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN))
+#define STA_PR_FMT     " sta:%pM"
+#define STA_PR_ARG     __entry->sta_addr
+
+#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata)   \
+                       __field(bool, p2p)                                              \
+                       __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata;    \
+                       __entry->p2p = sdata->vif.p2p;                                  \
+                       __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_PR_FMT     " vif:%s(%d%s)"
+#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
+
+/*
+ * Tracing for driver callbacks.
+ */
+
+DECLARE_EVENT_CLASS(local_only_evt,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local),
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+       TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
+);
+
+DECLARE_EVENT_CLASS(local_sdata_addr_evt,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __array(char, addr, 6)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               memcpy(__entry->addr, sdata->vif.addr, 6);
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " addr:%pM",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+       )
+);
+
+DECLARE_EVENT_CLASS(local_u32_evt,
+       TP_PROTO(struct ieee80211_local *local, u32 value),
+       TP_ARGS(local, value),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, value)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->value = value;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " value:%d",
+               LOCAL_PR_ARG, __entry->value
+       )
+);
+
+DECLARE_EVENT_CLASS(local_sdata_evt,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_only_evt, drv_return_void,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_return_int,
+       TP_PROTO(struct ieee80211_local *local, int ret),
+       TP_ARGS(local, ret),
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+       ),
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret)
+);
+
+TRACE_EVENT(drv_return_bool,
+       TP_PROTO(struct ieee80211_local *local, bool ret),
+       TP_ARGS(local, ret),
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, ret)
+       ),
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ?
+                 "true" : "false")
+);
+
+TRACE_EVENT(drv_return_u64,
+       TP_PROTO(struct ieee80211_local *local, u64 ret),
+       TP_ARGS(local, ret),
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, ret)
+       ),
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+       ),
+       TP_printk(LOCAL_PR_FMT " - %llu", LOCAL_PR_ARG, __entry->ret)
+);
+
+DEFINE_EVENT(local_only_evt, drv_start,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_get_et_strings,
+            TP_PROTO(struct ieee80211_local *local, u32 sset),
+            TP_ARGS(local, sset)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_get_et_sset_count,
+            TP_PROTO(struct ieee80211_local *local, u32 sset),
+            TP_ARGS(local, sset)
+);
+
+DEFINE_EVENT(local_only_evt, drv_get_et_stats,
+            TP_PROTO(struct ieee80211_local *local),
+            TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_suspend,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_resume,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_set_wakeup,
+       TP_PROTO(struct ieee80211_local *local, bool enabled),
+       TP_ARGS(local, enabled),
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, enabled)
+       ),
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->enabled = enabled;
+       ),
+       TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
+);
+
+DEFINE_EVENT(local_only_evt, drv_stop,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_change_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                enum nl80211_iftype type, bool p2p),
+
+       TP_ARGS(local, sdata, type, p2p),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u32, new_type)
+               __field(bool, new_p2p)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->new_type = type;
+               __entry->new_p2p = p2p;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d%s",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type,
+               __entry->new_p2p ? "/p2p" : ""
+       )
+);
+
+DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_config,
+       TP_PROTO(struct ieee80211_local *local,
+                u32 changed),
+
+       TP_ARGS(local, changed),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, changed)
+               __field(u32, flags)
+               __field(int, power_level)
+               __field(int, dynamic_ps_timeout)
+               __field(int, max_sleep_period)
+               __field(u16, listen_interval)
+               __field(u8, long_frame_max_tx_count)
+               __field(u8, short_frame_max_tx_count)
+               __field(int, center_freq)
+               __field(int, channel_type)
+               __field(int, smps)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->changed = changed;
+               __entry->flags = local->hw.conf.flags;
+               __entry->power_level = local->hw.conf.power_level;
+               __entry->dynamic_ps_timeout = local->hw.conf.dynamic_ps_timeout;
+               __entry->max_sleep_period = local->hw.conf.max_sleep_period;
+               __entry->listen_interval = local->hw.conf.listen_interval;
+               __entry->long_frame_max_tx_count = local->hw.conf.long_frame_max_tx_count;
+               __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
+               __entry->center_freq = local->hw.conf.channel->center_freq;
+               __entry->channel_type = local->hw.conf.channel_type;
+               __entry->smps = local->hw.conf.smps_mode;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ch:%#x freq:%d",
+               LOCAL_PR_ARG, __entry->changed, __entry->center_freq
+       )
+);
+
+TRACE_EVENT(drv_bss_info_changed,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_bss_conf *info,
+                u32 changed),
+
+       TP_ARGS(local, sdata, info, changed),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(bool, assoc)
+               __field(u16, aid)
+               __field(bool, cts)
+               __field(bool, shortpre)
+               __field(bool, shortslot)
+               __field(u8, dtimper)
+               __field(u16, bcnint)
+               __field(u16, assoc_cap)
+               __field(u64, timestamp)
+               __field(u32, basic_rates)
+               __field(u32, changed)
+               __field(bool, enable_beacon)
+               __field(u16, ht_operation_mode)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->changed = changed;
+               __entry->aid = info->aid;
+               __entry->assoc = info->assoc;
+               __entry->shortpre = info->use_short_preamble;
+               __entry->cts = info->use_cts_prot;
+               __entry->shortslot = info->use_short_slot;
+               __entry->dtimper = info->dtim_period;
+               __entry->bcnint = info->beacon_int;
+               __entry->assoc_cap = info->assoc_capability;
+               __entry->timestamp = info->last_tsf;
+               __entry->basic_rates = info->basic_rates;
+               __entry->enable_beacon = info->enable_beacon;
+               __entry->ht_operation_mode = info->ht_operation_mode;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " changed:%#x",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed
+       )
+);
+
+TRACE_EVENT(drv_prepare_multicast,
+       TP_PROTO(struct ieee80211_local *local, int mc_count),
+
+       TP_ARGS(local, mc_count),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, mc_count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->mc_count = mc_count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " prepare mc (%d)",
+               LOCAL_PR_ARG, __entry->mc_count
+       )
+);
+
+TRACE_EVENT(drv_configure_filter,
+       TP_PROTO(struct ieee80211_local *local,
+                unsigned int changed_flags,
+                unsigned int *total_flags,
+                u64 multicast),
+
+       TP_ARGS(local, changed_flags, total_flags, multicast),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(unsigned int, changed)
+               __field(unsigned int, total)
+               __field(u64, multicast)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->changed = changed_flags;
+               __entry->total = *total_flags;
+               __entry->multicast = multicast;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " changed:%#x total:%#x",
+               LOCAL_PR_ARG, __entry->changed, __entry->total
+       )
+);
+
+TRACE_EVENT(drv_set_tim,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta, bool set),
+
+       TP_ARGS(local, sta, set),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(bool, set)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->set = set;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " set:%d",
+               LOCAL_PR_ARG, STA_PR_FMT, __entry->set
+       )
+);
+
+TRACE_EVENT(drv_set_key,
+       TP_PROTO(struct ieee80211_local *local,
+                enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta,
+                struct ieee80211_key_conf *key),
+
+       TP_ARGS(local, cmd, sdata, sta, key),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, cipher)
+               __field(u8, hw_key_idx)
+               __field(u8, flags)
+               __field(s8, keyidx)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->cipher = key->cipher;
+               __entry->flags = key->flags;
+               __entry->keyidx = key->keyidx;
+               __entry->hw_key_idx = key->hw_key_idx;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_update_tkip_key,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_key_conf *conf,
+                struct ieee80211_sta *sta, u32 iv32),
+
+       TP_ARGS(local, sdata, conf, sta, iv32),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, iv32)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->iv32 = iv32;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
+               LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_cancel_hw_scan,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_sw_scan_complete,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_get_stats,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_low_level_stats *stats,
+                int ret),
+
+       TP_ARGS(local, stats, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, ret)
+               __field(unsigned int, ackfail)
+               __field(unsigned int, rtsfail)
+               __field(unsigned int, fcserr)
+               __field(unsigned int, rtssucc)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+               __entry->ackfail = stats->dot11ACKFailureCount;
+               __entry->rtsfail = stats->dot11RTSFailureCount;
+               __entry->fcserr = stats->dot11FCSErrorCount;
+               __entry->rtssucc = stats->dot11RTSSuccessCount;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " ret:%d",
+               LOCAL_PR_ARG, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_get_tkip_seq,
+       TP_PROTO(struct ieee80211_local *local,
+                u8 hw_key_idx, u32 *iv32, u16 *iv16),
+
+       TP_ARGS(local, hw_key_idx, iv32, iv16),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u8, hw_key_idx)
+               __field(u32, iv32)
+               __field(u16, iv16)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->hw_key_idx = hw_key_idx;
+               __entry->iv32 = *iv32;
+               __entry->iv16 = *iv16;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold,
+       TP_PROTO(struct ieee80211_local *local, u32 value),
+       TP_ARGS(local, value)
+);
+
+DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold,
+       TP_PROTO(struct ieee80211_local *local, u32 value),
+       TP_ARGS(local, value)
+);
+
+TRACE_EVENT(drv_set_coverage_class,
+       TP_PROTO(struct ieee80211_local *local, u8 value),
+
+       TP_ARGS(local, value),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u8, value)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->value = value;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " value:%d",
+               LOCAL_PR_ARG, __entry->value
+       )
+);
+
+TRACE_EVENT(drv_sta_notify,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                enum sta_notify_cmd cmd,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, sdata, cmd, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, cmd)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->cmd = cmd;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " cmd:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd
+       )
+);
+
+TRACE_EVENT(drv_sta_state,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta,
+                enum ieee80211_sta_state old_state,
+                enum ieee80211_sta_state new_state),
+
+       TP_ARGS(local, sdata, sta, old_state, new_state),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, old_state)
+               __field(u32, new_state)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->old_state = old_state;
+               __entry->new_state = new_state;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " state: %d->%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
+               __entry->old_state, __entry->new_state
+       )
+);
+
+TRACE_EVENT(drv_sta_rc_update,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta,
+                u32 changed),
+
+       TP_ARGS(local, sdata, sta, changed),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+               __field(u32, changed)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->changed = changed;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " changed: 0x%x",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+       )
+);
+
+TRACE_EVENT(drv_sta_add,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, sdata, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_sta_remove,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, sdata, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               STA_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+       )
+);
+
+TRACE_EVENT(drv_conf_tx,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u16 ac, const struct ieee80211_tx_queue_params *params),
+
+       TP_ARGS(local, sdata, ac, params),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u16, ac)
+               __field(u16, txop)
+               __field(u16, cw_min)
+               __field(u16, cw_max)
+               __field(u8, aifs)
+               __field(bool, uapsd)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->ac = ac;
+               __entry->txop = params->txop;
+               __entry->cw_max = params->cw_max;
+               __entry->cw_min = params->cw_min;
+               __entry->aifs = params->aifs;
+               __entry->uapsd = params->uapsd;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  " AC:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->ac
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_set_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u64 tsf),
+
+       TP_ARGS(local, sdata, tsf),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u64, tsf)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->tsf = tsf;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
+               LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_ampdu_action,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                enum ieee80211_ampdu_mlme_action action,
+                struct ieee80211_sta *sta, u16 tid,
+                u16 *ssn, u8 buf_size),
+
+       TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(u32, action)
+               __field(u16, tid)
+               __field(u16, ssn)
+               __field(u8, buf_size)
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               STA_ASSIGN;
+               __entry->action = action;
+               __entry->tid = tid;
+               __entry->ssn = ssn ? *ssn : 0;
+               __entry->buf_size = buf_size;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
+               __entry->tid, __entry->buf_size
+       )
+);
+
+TRACE_EVENT(drv_get_survey,
+       TP_PROTO(struct ieee80211_local *local, int idx,
+                struct survey_info *survey),
+
+       TP_ARGS(local, idx, survey),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, idx)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->idx = idx;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " idx:%d",
+               LOCAL_PR_ARG, __entry->idx
+       )
+);
+
+TRACE_EVENT(drv_flush,
+       TP_PROTO(struct ieee80211_local *local, bool drop),
+
+       TP_ARGS(local, drop),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, drop)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->drop = drop;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " drop:%d",
+               LOCAL_PR_ARG, __entry->drop
+       )
+);
+
+TRACE_EVENT(drv_channel_switch,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_channel_switch *ch_switch),
+
+       TP_ARGS(local, ch_switch),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, timestamp)
+               __field(bool, block_tx)
+               __field(u16, freq)
+               __field(u8, count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->timestamp = ch_switch->timestamp;
+               __entry->block_tx = ch_switch->block_tx;
+               __entry->freq = ch_switch->channel->center_freq;
+               __entry->count = ch_switch->count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " new freq:%u count:%d",
+               LOCAL_PR_ARG, __entry->freq, __entry->count
+       )
+);
+
+TRACE_EVENT(drv_set_antenna,
+       TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
+
+       TP_ARGS(local, tx_ant, rx_ant, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, tx_ant)
+               __field(u32, rx_ant)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->tx_ant = tx_ant;
+               __entry->rx_ant = rx_ant;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
+               LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_get_antenna,
+       TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret),
+
+       TP_ARGS(local, tx_ant, rx_ant, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, tx_ant)
+               __field(u32, rx_ant)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->tx_ant = tx_ant;
+               __entry->rx_ant = rx_ant;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d",
+               LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret
+       )
+);
+
+TRACE_EVENT(drv_remain_on_channel,
+       TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
+                enum nl80211_channel_type chantype, unsigned int duration),
+
+       TP_ARGS(local, chan, chantype, duration),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, center_freq)
+               __field(int, channel_type)
+               __field(unsigned int, duration)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->center_freq = chan->center_freq;
+               __entry->channel_type = chantype;
+               __entry->duration = duration;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " freq:%dMHz duration:%dms",
+               LOCAL_PR_ARG, __entry->center_freq, __entry->duration
+       )
+);
+
+DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_offchannel_tx,
+       TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
+                struct ieee80211_channel *chan,
+                enum nl80211_channel_type channel_type,
+                unsigned int wait),
+
+       TP_ARGS(local, skb, chan, channel_type, wait),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(int, center_freq)
+               __field(int, channel_type)
+               __field(unsigned int, wait)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->center_freq = chan->center_freq;
+               __entry->channel_type = channel_type;
+               __entry->wait = wait;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
+               LOCAL_PR_ARG, __entry->center_freq, __entry->wait
+       )
+);
+
+TRACE_EVENT(drv_set_ringparam,
+       TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
+
+       TP_ARGS(local, tx, rx),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, tx)
+               __field(u32, rx)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->tx = tx;
+               __entry->rx = rx;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " tx:%d rx %d",
+               LOCAL_PR_ARG, __entry->tx, __entry->rx
+       )
+);
+
+TRACE_EVENT(drv_get_ringparam,
+       TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max,
+                u32 *rx, u32 *rx_max),
+
+       TP_ARGS(local, tx, tx_max, rx, rx_max),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, tx)
+               __field(u32, tx_max)
+               __field(u32, rx)
+               __field(u32, rx_max)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->tx = *tx;
+               __entry->tx_max = *tx_max;
+               __entry->rx = *rx;
+               __entry->rx_max = *rx_max;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d",
+               LOCAL_PR_ARG,
+               __entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max
+       )
+);
+
+DEFINE_EVENT(local_only_evt, drv_tx_frames_pending,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(drv_set_bitrate_mask,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                const struct cfg80211_bitrate_mask *mask),
+
+       TP_ARGS(local, sdata, mask),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u32, legacy_2g)
+               __field(u32, legacy_5g)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
+               __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
+       )
+);
+
+TRACE_EVENT(drv_set_rekey_data,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct cfg80211_gtk_rekey_data *data),
+
+       TP_ARGS(local, sdata, data),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __array(u8, kek, NL80211_KEK_LEN)
+               __array(u8, kck, NL80211_KCK_LEN)
+               __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               memcpy(__entry->kek, data->kek, NL80211_KEK_LEN);
+               memcpy(__entry->kck, data->kck, NL80211_KCK_LEN);
+               memcpy(__entry->replay_ctr, data->replay_ctr,
+                      NL80211_REPLAY_CTR_LEN);
+       ),
+
+       TP_printk(LOCAL_PR_FMT VIF_PR_FMT,
+                 LOCAL_PR_ARG, VIF_PR_ARG)
+);
+
+TRACE_EVENT(drv_rssi_callback,
+       TP_PROTO(struct ieee80211_local *local,
+                enum ieee80211_rssi_event rssi_event),
+
+       TP_ARGS(local, rssi_event),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, rssi_event)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " rssi_event:%d",
+               LOCAL_PR_ARG, __entry->rssi_event
+       )
+);
+
+DECLARE_EVENT_CLASS(release_evt,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(u16, tids)
+               __field(int, num_frames)
+               __field(int, reason)
+               __field(bool, more_data)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->tids = tids;
+               __entry->num_frames = num_frames;
+               __entry->reason = reason;
+               __entry->more_data = more_data;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT
+               " TIDs:0x%.4x frames:%d reason:%d more:%d",
+               LOCAL_PR_ARG, STA_PR_ARG, __entry->tids, __entry->num_frames,
+               __entry->reason, __entry->more_data
+       )
+);
+
+DEFINE_EVENT(release_evt, drv_release_buffered_frames,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta,
+                u16 tids, int num_frames,
+                enum ieee80211_frame_release_type reason,
+                bool more_data),
+
+       TP_ARGS(local, sta, tids, num_frames, reason, more_data)
+);
+
+TRACE_EVENT(drv_get_rssi,
+       TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta,
+                s8 rssi, int ret),
+
+       TP_ARGS(local, sta, rssi, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(s8, rssi)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->rssi = rssi;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d",
+               LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret
+       )
+);
+
+/*
+ * Tracing for API calls that drivers call.
+ */
+
+TRACE_EVENT(api_start_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+       TP_ARGS(sta, tid),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d",
+               STA_PR_ARG, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_start_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+       TP_ARGS(sta, tid),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d",
+               STA_PR_ARG, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+DEFINE_EVENT(local_only_evt, api_restart_hw,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(api_beacon_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_connection_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_cqm_rssi_notify,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                enum nl80211_cqm_rssi_threshold_event rssi_event),
+
+       TP_ARGS(sdata, rssi_event),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(u32, rssi_event)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " event:%d",
+               VIF_PR_ARG, __entry->rssi_event
+       )
+);
+
+TRACE_EVENT(api_scan_completed,
+       TP_PROTO(struct ieee80211_local *local, bool aborted),
+
+       TP_ARGS(local, aborted),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, aborted)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->aborted = aborted;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " aborted:%d",
+               LOCAL_PR_ARG, __entry->aborted
+       )
+);
+
+TRACE_EVENT(api_sched_scan_results,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_sched_scan_stopped,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT, LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_sta_block_awake,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta, bool block),
+
+       TP_ARGS(local, sta, block),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(bool, block)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->block = block;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " block:%d",
+               LOCAL_PR_ARG, STA_PR_FMT, __entry->block
+       )
+);
+
+TRACE_EVENT(api_chswitch_done,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+
+       TP_ARGS(sdata, success),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(bool, success)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->success = success;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " success=%d",
+               VIF_PR_ARG, __entry->success
+       )
+);
+
+DEFINE_EVENT(local_only_evt, api_ready_on_channel,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
+TRACE_EVENT(api_gtk_rekey_notify,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                const u8 *bssid, const u8 *replay_ctr),
+
+       TP_ARGS(sdata, bssid, replay_ctr),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, bssid, ETH_ALEN)
+               __array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->bssid, bssid, ETH_ALEN);
+               memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN);
+       ),
+
+       TP_printk(VIF_PR_FMT, VIF_PR_ARG)
+);
+
+TRACE_EVENT(api_enable_rssi_reports,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                int rssi_min_thold, int rssi_max_thold),
+
+       TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(int, rssi_min_thold)
+               __field(int, rssi_max_thold)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->rssi_min_thold = rssi_min_thold;
+               __entry->rssi_max_thold = rssi_max_thold;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
+               VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
+       )
+);
+
+TRACE_EVENT(api_eosp,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta),
+
+       TP_ARGS(local, sta),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT,
+               LOCAL_PR_ARG, STA_PR_FMT
+       )
+);
+
+/*
+ * Tracing for internal functions
+ * (which may also be called in response to driver calls)
+ */
+
+TRACE_EVENT(wake_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
+
+TRACE_EVENT(stop_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
+
+#ifdef CONFIG_MAC80211_MESSAGE_TRACING
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mac80211_msg
+
+#define MAX_MSG_LEN    100
+
+DECLARE_EVENT_CLASS(mac80211_msg_event,
+       TP_PROTO(struct va_format *vaf),
+
+       TP_ARGS(vaf),
+
+       TP_STRUCT__entry(
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+
+       TP_fast_assign(
+               WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+                                      MAX_MSG_LEN, vaf->fmt,
+                                      *vaf->va) >= MAX_MSG_LEN);
+       ),
+
+       TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(mac80211_msg_event, mac80211_info,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+DEFINE_EVENT(mac80211_msg_event, mac80211_dbg,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+DEFINE_EVENT(mac80211_msg_event, mac80211_err,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+#endif
+
+#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
index e453212fa17f741bc380b2cbdabe59ee4f6df5d7..ec8f534673745f61eae34cb7fa922498d7693874 100644 (file)
@@ -175,12 +175,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
        return cpu_to_le16(dur);
 }
 
-static inline int is_ieee80211_device(struct ieee80211_local *local,
-                                     struct net_device *dev)
-{
-       return local == wdev_priv(dev->ieee80211_ptr);
-}
-
 /* tx handlers */
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
@@ -297,10 +291,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
                if (unlikely(!assoc &&
                             ieee80211_is_data(hdr->frame_control))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-                       printk(KERN_DEBUG "%s: dropped data frame to not "
-                              "associated station %pM\n",
-                              tx->sdata->name, hdr->addr1);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+                       sdata_info(tx->sdata,
+                                  "dropped data frame to not associated station %pM\n",
+                                  hdr->addr1);
+#endif
                        I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
                        return TX_DROP;
                }
@@ -367,10 +361,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
        rcu_read_unlock();
 
        local->total_ps_buffered = total;
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
-                   purged);
-#endif
+       ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
 }
 
 static ieee80211_tx_result
@@ -412,10 +403,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
                purge_old_ps_buffers(tx->local);
 
        if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               net_dbg_ratelimited("%s: BC TX buffer full - dropping the oldest frame\n",
-                                   tx->sdata->name);
-#endif
+               ps_dbg(tx->sdata,
+                      "BC TX buffer full - dropping the oldest frame\n");
                dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
        } else
                tx->local->total_ps_buffered++;
@@ -466,18 +455,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        return TX_CONTINUE;
                }
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
+               ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
                        purge_old_ps_buffers(tx->local);
                if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
                        struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-                       net_dbg_ratelimited("%s: STA %pM TX buffer for AC %d full - dropping oldest frame\n",
-                                           tx->sdata->name, sta->sta.addr, ac);
-#endif
+                       ps_dbg(tx->sdata,
+                              "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
+                              sta->sta.addr, ac);
                        dev_kfree_skb(old);
                } else
                        tx->local->total_ps_buffered++;
@@ -499,14 +485,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                sta_info_recalc_tim(sta);
 
                return TX_QUEUED;
+       } else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
+               ps_dbg(tx->sdata,
+                      "STA %pM in PS mode, but polling/in SP -> send frame\n",
+                      sta->sta.addr);
        }
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
-               printk(KERN_DEBUG
-                      "%s: STA %pM in PS mode, but polling/in SP -> send frame\n",
-                      tx->sdata->name, sta->sta.addr);
-       }
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        return TX_CONTINUE;
 }
@@ -1965,7 +1948,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                     (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
                      !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               net_dbg_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
+               net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n",
                                    dev->name, hdr.addr1);
 #endif
 
index 8dd4712620ff53832a212a3d69791e13cd59905f..242ecde381f605429f05d427b32f6f54ab9983d1 100644 (file)
@@ -804,7 +804,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_queue_params qparam;
        int ac;
-       bool use_11b;
+       bool use_11b, enable_qos;
        int aCWmin, aCWmax;
 
        if (!local->ops->conf_tx)
@@ -818,6 +818,13 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
                 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 
+       /*
+        * By default disable QoS in STA mode for old access points, which do
+        * not support 802.11e. New APs will provide proper queue parameters,
+        * that we will configure later.
+        */
+       enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
+
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                /* Set defaults according to 802.11-2007 Table 7-37 */
                aCWmax = 1023;
@@ -826,38 +833,47 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                else
                        aCWmin = 15;
 
-               switch (ac) {
-               case IEEE80211_AC_BK:
-                       qparam.cw_max = aCWmax;
-                       qparam.cw_min = aCWmin;
-                       qparam.txop = 0;
-                       qparam.aifs = 7;
-                       break;
-               default: /* never happens but let's not leave undefined */
-               case IEEE80211_AC_BE:
+               if (enable_qos) {
+                       switch (ac) {
+                       case IEEE80211_AC_BK:
+                               qparam.cw_max = aCWmax;
+                               qparam.cw_min = aCWmin;
+                               qparam.txop = 0;
+                               qparam.aifs = 7;
+                               break;
+                       /* never happens but let's not leave undefined */
+                       default:
+                       case IEEE80211_AC_BE:
+                               qparam.cw_max = aCWmax;
+                               qparam.cw_min = aCWmin;
+                               qparam.txop = 0;
+                               qparam.aifs = 3;
+                               break;
+                       case IEEE80211_AC_VI:
+                               qparam.cw_max = aCWmin;
+                               qparam.cw_min = (aCWmin + 1) / 2 - 1;
+                               if (use_11b)
+                                       qparam.txop = 6016/32;
+                               else
+                                       qparam.txop = 3008/32;
+                               qparam.aifs = 2;
+                               break;
+                       case IEEE80211_AC_VO:
+                               qparam.cw_max = (aCWmin + 1) / 2 - 1;
+                               qparam.cw_min = (aCWmin + 1) / 4 - 1;
+                               if (use_11b)
+                                       qparam.txop = 3264/32;
+                               else
+                                       qparam.txop = 1504/32;
+                               qparam.aifs = 2;
+                               break;
+                       }
+               } else {
+                       /* Confiure old 802.11b/g medium access rules. */
                        qparam.cw_max = aCWmax;
                        qparam.cw_min = aCWmin;
                        qparam.txop = 0;
-                       qparam.aifs = 3;
-                       break;
-               case IEEE80211_AC_VI:
-                       qparam.cw_max = aCWmin;
-                       qparam.cw_min = (aCWmin + 1) / 2 - 1;
-                       if (use_11b)
-                               qparam.txop = 6016/32;
-                       else
-                               qparam.txop = 3008/32;
-                       qparam.aifs = 2;
-                       break;
-               case IEEE80211_AC_VO:
-                       qparam.cw_max = (aCWmin + 1) / 2 - 1;
-                       qparam.cw_min = (aCWmin + 1) / 4 - 1;
-                       if (use_11b)
-                               qparam.txop = 3264/32;
-                       else
-                               qparam.txop = 1504/32;
                        qparam.aifs = 2;
-                       break;
                }
 
                qparam.uapsd = false;
@@ -866,12 +882,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                drv_conf_tx(local, sdata, ac, &qparam);
        }
 
-       /* after reinitialize QoS TX queues setting to default,
-        * disable QoS at all */
-
        if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
-               sdata->vif.bss_conf.qos =
-                       sdata->vif.type != NL80211_IFTYPE_STATION;
+               sdata->vif.bss_conf.qos = enable_qos;
                if (bss_notify)
                        ieee80211_bss_info_change_notify(sdata,
                                                         BSS_CHANGED_QOS);
@@ -1267,14 +1279,19 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        /* add STAs back */
        mutex_lock(&local->sta_mtx);
        list_for_each_entry(sta, &local->sta_list, list) {
-               if (sta->uploaded) {
-                       enum ieee80211_sta_state state;
+               enum ieee80211_sta_state state;
 
-                       for (state = IEEE80211_STA_NOTEXIST;
-                            state < sta->sta_state; state++)
-                               WARN_ON(drv_sta_state(local, sta->sdata, sta,
-                                                     state, state + 1));
-               }
+               if (!sta->uploaded)
+                       continue;
+
+               /* AP-mode stations will be added later */
+               if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
+                       continue;
+
+               for (state = IEEE80211_STA_NOTEXIST;
+                    state < sta->sta_state; state++)
+                       WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+                                             state + 1));
        }
        mutex_unlock(&local->sta_mtx);
 
@@ -1371,11 +1388,32 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                }
        }
 
+       /* APs are now beaconing, add back stations */
+       mutex_lock(&local->sta_mtx);
+       list_for_each_entry(sta, &local->sta_list, list) {
+               enum ieee80211_sta_state state;
+
+               if (!sta->uploaded)
+                       continue;
+
+               if (sta->sdata->vif.type != NL80211_IFTYPE_AP)
+                       continue;
+
+               for (state = IEEE80211_STA_NOTEXIST;
+                    state < sta->sta_state; state++)
+                       WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+                                             state + 1));
+       }
+       mutex_unlock(&local->sta_mtx);
+
        /* add back keys */
        list_for_each_entry(sdata, &local->interfaces, list)
                if (ieee80211_sdata_running(sdata))
                        ieee80211_enable_keys(sdata);
 
+       local->in_reconfig = false;
+       barrier();
+
  wake_up:
        /*
         * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
index c3d643a6536cb848dbb2642265d851dfeae7c3ae..cea06e9f26f480b48a58747fc98f5665a3ead21c 100644 (file)
@@ -52,11 +52,11 @@ static int wme_downgrade_ac(struct sk_buff *skb)
        }
 }
 
-static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
+static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
                                     struct sk_buff *skb)
 {
        /* in case we are a client verify acm is not set for this ac */
-       while (unlikely(local->wmm_acm & BIT(skb->priority))) {
+       while (unlikely(sdata->wmm_acm & BIT(skb->priority))) {
                if (wme_downgrade_ac(skb)) {
                        /*
                         * This should not really happen. The AP has marked all
@@ -73,10 +73,11 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
 }
 
 /* Indicate which queue to use for this fully formed 802.11 frame */
-u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb,
                                 struct ieee80211_hdr *hdr)
 {
+       struct ieee80211_local *local = sdata->local;
        u8 *p;
 
        if (local->hw.queues < IEEE80211_NUM_ACS)
@@ -94,7 +95,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
        p = ieee80211_get_qos_ctl(hdr);
        skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-       return ieee80211_downgrade_queue(local, skb);
+       return ieee80211_downgrade_queue(sdata, skb);
 }
 
 /* Indicate which queue to use. */
@@ -156,7 +157,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
         * data frame has */
        skb->priority = cfg80211_classify8021d(skb);
 
-       return ieee80211_downgrade_queue(local, skb);
+       return ieee80211_downgrade_queue(sdata, skb);
 }
 
 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
index ca80818b7b66ed42c9f7c7b32b5e9ffc57360ea4..7fea4bb8acbc4985934ee265ade2546ab8e950ef 100644 (file)
@@ -15,7 +15,7 @@
 
 extern const int ieee802_1d_to_ac[8];
 
-u16 ieee80211_select_queue_80211(struct ieee80211_local *local,
+u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb,
                                 struct ieee80211_hdr *hdr);
 u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
deleted file mode 100644 (file)
index b2650a9..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * mac80211 work implementation
- *
- * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
- * Copyright 2004, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
- * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
- *
- * 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.
- */
-
-#include <linux/delay.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#include <net/mac80211.h>
-#include <asm/unaligned.h>
-
-#include "ieee80211_i.h"
-#include "rate.h"
-#include "driver-ops.h"
-
-enum work_action {
-       WORK_ACT_NONE,
-       WORK_ACT_TIMEOUT,
-};
-
-
-/* utils */
-static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
-{
-       lockdep_assert_held(&local->mtx);
-}
-
-/*
- * We can have multiple work items (and connection probing)
- * scheduling this timer, but we need to take care to only
- * reschedule it when it should fire _earlier_ than it was
- * asked for before, or if it's not pending right now. This
- * function ensures that. Note that it then is required to
- * run this function for all timeouts after the first one
- * has happened -- the work that runs from this timer will
- * do that.
- */
-static void run_again(struct ieee80211_local *local,
-                     unsigned long timeout)
-{
-       ASSERT_WORK_MTX(local);
-
-       if (!timer_pending(&local->work_timer) ||
-           time_before(timeout, local->work_timer.expires))
-               mod_timer(&local->work_timer, timeout);
-}
-
-void free_work(struct ieee80211_work *wk)
-{
-       kfree_rcu(wk, rcu_head);
-}
-
-static enum work_action __must_check
-ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
-{
-       /*
-        * First time we run, do nothing -- the generic code will
-        * have switched to the right channel etc.
-        */
-       if (!wk->started) {
-               wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
-
-               cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
-                                         wk->chan, wk->chan_type,
-                                         wk->remain.duration, GFP_KERNEL);
-
-               return WORK_ACT_NONE;
-       }
-
-       return WORK_ACT_TIMEOUT;
-}
-
-static enum work_action __must_check
-ieee80211_offchannel_tx(struct ieee80211_work *wk)
-{
-       if (!wk->started) {
-               wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
-
-               /*
-                * After this, offchan_tx.frame remains but now is no
-                * longer a valid pointer -- we still need it as the
-                * cookie for canceling this work/status matching.
-                */
-               ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
-
-               return WORK_ACT_NONE;
-       }
-
-       return WORK_ACT_TIMEOUT;
-}
-
-static void ieee80211_work_timer(unsigned long data)
-{
-       struct ieee80211_local *local = (void *) data;
-
-       if (local->quiescing)
-               return;
-
-       ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-static void ieee80211_work_work(struct work_struct *work)
-{
-       struct ieee80211_local *local =
-               container_of(work, struct ieee80211_local, work_work);
-       struct ieee80211_work *wk, *tmp;
-       LIST_HEAD(free_work);
-       enum work_action rma;
-       bool remain_off_channel = false;
-
-       /*
-        * ieee80211_queue_work() should have picked up most cases,
-        * here we'll pick the rest.
-        */
-       if (WARN(local->suspended, "work scheduled while going to suspend\n"))
-               return;
-
-       mutex_lock(&local->mtx);
-
-       if (local->scanning) {
-               mutex_unlock(&local->mtx);
-               return;
-       }
-
-       ieee80211_recalc_idle(local);
-
-       list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
-               bool started = wk->started;
-
-               /* mark work as started if it's on the current off-channel */
-               if (!started && local->tmp_channel &&
-                   wk->chan == local->tmp_channel &&
-                   wk->chan_type == local->tmp_channel_type) {
-                       started = true;
-                       wk->timeout = jiffies;
-               }
-
-               if (!started && !local->tmp_channel) {
-                       ieee80211_offchannel_stop_vifs(local, true);
-
-                       local->tmp_channel = wk->chan;
-                       local->tmp_channel_type = wk->chan_type;
-
-                       ieee80211_hw_config(local, 0);
-
-                       started = true;
-                       wk->timeout = jiffies;
-               }
-
-               /* don't try to work with items that aren't started */
-               if (!started)
-                       continue;
-
-               if (time_is_after_jiffies(wk->timeout)) {
-                       /*
-                        * This work item isn't supposed to be worked on
-                        * right now, but take care to adjust the timer
-                        * properly.
-                        */
-                       run_again(local, wk->timeout);
-                       continue;
-               }
-
-               switch (wk->type) {
-               default:
-                       WARN_ON(1);
-                       /* nothing */
-                       rma = WORK_ACT_NONE;
-                       break;
-               case IEEE80211_WORK_ABORT:
-                       rma = WORK_ACT_TIMEOUT;
-                       break;
-               case IEEE80211_WORK_REMAIN_ON_CHANNEL:
-                       rma = ieee80211_remain_on_channel_timeout(wk);
-                       break;
-               case IEEE80211_WORK_OFFCHANNEL_TX:
-                       rma = ieee80211_offchannel_tx(wk);
-                       break;
-               }
-
-               wk->started = started;
-
-               switch (rma) {
-               case WORK_ACT_NONE:
-                       /* might have changed the timeout */
-                       run_again(local, wk->timeout);
-                       break;
-               case WORK_ACT_TIMEOUT:
-                       list_del_rcu(&wk->list);
-                       synchronize_rcu();
-                       list_add(&wk->list, &free_work);
-                       break;
-               default:
-                       WARN(1, "unexpected: %d", rma);
-               }
-       }
-
-       list_for_each_entry(wk, &local->work_list, list) {
-               if (!wk->started)
-                       continue;
-               if (wk->chan != local->tmp_channel ||
-                   wk->chan_type != local->tmp_channel_type)
-                       continue;
-               remain_off_channel = true;
-       }
-
-       if (!remain_off_channel && local->tmp_channel) {
-               local->tmp_channel = NULL;
-               ieee80211_hw_config(local, 0);
-
-               ieee80211_offchannel_return(local, true);
-
-               /* give connection some time to breathe */
-               run_again(local, jiffies + HZ/2);
-       }
-
-       ieee80211_recalc_idle(local);
-       ieee80211_run_deferred_scan(local);
-
-       mutex_unlock(&local->mtx);
-
-       list_for_each_entry_safe(wk, tmp, &free_work, list) {
-               wk->done(wk, NULL);
-               list_del(&wk->list);
-               kfree(wk);
-       }
-}
-
-void ieee80211_add_work(struct ieee80211_work *wk)
-{
-       struct ieee80211_local *local;
-
-       if (WARN_ON(!wk->chan))
-               return;
-
-       if (WARN_ON(!wk->sdata))
-               return;
-
-       if (WARN_ON(!wk->done))
-               return;
-
-       if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
-               return;
-
-       wk->started = false;
-
-       local = wk->sdata->local;
-       mutex_lock(&local->mtx);
-       list_add_tail(&wk->list, &local->work_list);
-       mutex_unlock(&local->mtx);
-
-       ieee80211_queue_work(&local->hw, &local->work_work);
-}
-
-void ieee80211_work_init(struct ieee80211_local *local)
-{
-       INIT_LIST_HEAD(&local->work_list);
-       setup_timer(&local->work_timer, ieee80211_work_timer,
-                   (unsigned long)local);
-       INIT_WORK(&local->work_work, ieee80211_work_work);
-}
-
-void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_work *wk;
-       bool cleanup = false;
-
-       mutex_lock(&local->mtx);
-       list_for_each_entry(wk, &local->work_list, list) {
-               if (wk->sdata != sdata)
-                       continue;
-               cleanup = true;
-               wk->type = IEEE80211_WORK_ABORT;
-               wk->started = true;
-               wk->timeout = jiffies;
-       }
-       mutex_unlock(&local->mtx);
-
-       /* run cleanups etc. */
-       if (cleanup)
-               ieee80211_work_work(&local->work_work);
-
-       mutex_lock(&local->mtx);
-       list_for_each_entry(wk, &local->work_list, list) {
-               if (wk->sdata != sdata)
-                       continue;
-               WARN_ON(1);
-               break;
-       }
-       mutex_unlock(&local->mtx);
-}
-
-static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
-                                                  struct sk_buff *skb)
-{
-       /*
-        * We are done serving the remain-on-channel command.
-        */
-       cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
-                                          wk->chan, wk->chan_type,
-                                          GFP_KERNEL);
-
-       return WORK_DONE_DESTROY;
-}
-
-int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_channel *chan,
-                                  enum nl80211_channel_type channel_type,
-                                  unsigned int duration, u64 *cookie)
-{
-       struct ieee80211_work *wk;
-
-       wk = kzalloc(sizeof(*wk), GFP_KERNEL);
-       if (!wk)
-               return -ENOMEM;
-
-       wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
-       wk->chan = chan;
-       wk->chan_type = channel_type;
-       wk->sdata = sdata;
-       wk->done = ieee80211_remain_done;
-
-       wk->remain.duration = duration;
-
-       *cookie = (unsigned long) wk;
-
-       ieee80211_add_work(wk);
-
-       return 0;
-}
-
-int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
-                                         u64 cookie)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_work *wk, *tmp;
-       bool found = false;
-
-       mutex_lock(&local->mtx);
-       list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
-               if ((unsigned long) wk == cookie) {
-                       wk->timeout = jiffies;
-                       found = true;
-                       break;
-               }
-       }
-       mutex_unlock(&local->mtx);
-
-       if (!found)
-               return -ENOENT;
-
-       ieee80211_queue_work(&local->hw, &local->work_work);
-
-       return 0;
-}
index 9f6ce011d35d17135dc0780e75da036e520f7288..4177bb5104b9185f416bf4e549a304a0930069d6 100644 (file)
@@ -121,14 +121,14 @@ error:
  * The device remains polling for targets until a target is found or
  * the nfc_stop_poll function is called.
  */
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
 {
        int rc;
 
-       pr_debug("dev_name=%s protocols=0x%x\n",
-                dev_name(&dev->dev), protocols);
+       pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n",
+                dev_name(&dev->dev), im_protocols, tm_protocols);
 
-       if (!protocols)
+       if (!im_protocols && !tm_protocols)
                return -EINVAL;
 
        device_lock(&dev->dev);
@@ -143,9 +143,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
                goto error;
        }
 
-       rc = dev->ops->start_poll(dev, protocols);
-       if (!rc)
+       rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
+       if (!rc) {
                dev->polling = true;
+               dev->rf_mode = NFC_RF_NONE;
+       }
 
 error:
        device_unlock(&dev->dev);
@@ -235,8 +237,10 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
        }
 
        rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
-       if (!rc)
+       if (!rc) {
                dev->active_target = target;
+               dev->rf_mode = NFC_RF_INITIATOR;
+       }
 
 error:
        device_unlock(&dev->dev);
@@ -264,11 +268,6 @@ int nfc_dep_link_down(struct nfc_dev *dev)
                goto error;
        }
 
-       if (dev->dep_rf_mode == NFC_RF_TARGET) {
-               rc = -EOPNOTSUPP;
-               goto error;
-       }
-
        rc = dev->ops->dep_link_down(dev);
        if (!rc) {
                dev->dep_link_up = false;
@@ -286,7 +285,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
                       u8 comm_mode, u8 rf_mode)
 {
        dev->dep_link_up = true;
-       dev->dep_rf_mode = rf_mode;
 
        nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
 
@@ -330,6 +328,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
        rc = dev->ops->activate_target(dev, target, protocol);
        if (!rc) {
                dev->active_target = target;
+               dev->rf_mode = NFC_RF_INITIATOR;
 
                if (dev->ops->check_presence)
                        mod_timer(&dev->check_pres_timer, jiffies +
@@ -409,27 +408,30 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
                goto error;
        }
 
-       if (dev->active_target == NULL) {
-               rc = -ENOTCONN;
-               kfree_skb(skb);
-               goto error;
-       }
+       if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
+               if (dev->active_target->idx != target_idx) {
+                       rc = -EADDRNOTAVAIL;
+                       kfree_skb(skb);
+                       goto error;
+               }
 
-       if (dev->active_target->idx != target_idx) {
-               rc = -EADDRNOTAVAIL;
+               if (dev->ops->check_presence)
+                       del_timer_sync(&dev->check_pres_timer);
+
+               rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
+                                            cb_context);
+
+               if (!rc && dev->ops->check_presence)
+                       mod_timer(&dev->check_pres_timer, jiffies +
+                                 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+       } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
+               rc = dev->ops->tm_send(dev, skb);
+       } else {
+               rc = -ENOTCONN;
                kfree_skb(skb);
                goto error;
        }
 
-       if (dev->ops->check_presence)
-               del_timer_sync(&dev->check_pres_timer);
-
-       rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb,
-                                    cb_context);
-
-       if (!rc && dev->ops->check_presence)
-               mod_timer(&dev->check_pres_timer, jiffies +
-                         msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
 
 error:
        device_unlock(&dev->dev);
@@ -447,6 +449,63 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
 }
 EXPORT_SYMBOL(nfc_set_remote_general_bytes);
 
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
+{
+       pr_debug("dev_name=%s\n", dev_name(&dev->dev));
+
+       return nfc_llcp_general_bytes(dev, gb_len);
+}
+EXPORT_SYMBOL(nfc_get_local_general_bytes);
+
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+       /* Only LLCP target mode for now */
+       if (dev->dep_link_up == false) {
+               kfree_skb(skb);
+               return -ENOLINK;
+       }
+
+       return nfc_llcp_data_received(dev, skb);
+}
+EXPORT_SYMBOL(nfc_tm_data_received);
+
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+                    u8 *gb, size_t gb_len)
+{
+       int rc;
+
+       device_lock(&dev->dev);
+
+       dev->polling = false;
+
+       if (gb != NULL) {
+               rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
+               if (rc < 0)
+                       goto out;
+       }
+
+       dev->rf_mode = NFC_RF_TARGET;
+
+       if (protocol == NFC_PROTO_NFC_DEP_MASK)
+               nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
+
+       rc = nfc_genl_tm_activated(dev, protocol);
+
+out:
+       device_unlock(&dev->dev);
+
+       return rc;
+}
+EXPORT_SYMBOL(nfc_tm_activated);
+
+int nfc_tm_deactivated(struct nfc_dev *dev)
+{
+       dev->dep_link_up = false;
+
+       return nfc_genl_tm_deactivated(dev);
+}
+EXPORT_SYMBOL(nfc_tm_deactivated);
+
 /**
  * nfc_alloc_send_skb - allocate a skb for data exchange responses
  *
@@ -678,7 +737,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
        struct nfc_dev *dev;
 
        if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
-           !ops->deactivate_target || !ops->data_exchange)
+           !ops->deactivate_target || !ops->im_transceive)
                return NULL;
 
        if (!supported_protocols)
index e1a640d2b588eedbe4f0a32b8f24cbfb74b1ff64..a8b0b71e8f86456db556cffdb60069ea21b76f7b 100644 (file)
@@ -481,12 +481,13 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
        return 0;
 }
 
-static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static int hci_start_poll(struct nfc_dev *nfc_dev,
+                         u32 im_protocols, u32 tm_protocols)
 {
        struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 
        if (hdev->ops->start_poll)
-               return hdev->ops->start_poll(hdev, protocols);
+               return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
        else
                return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
                                       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
@@ -511,9 +512,9 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev,
 {
 }
 
-static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
-                            struct sk_buff *skb, data_exchange_cb_t cb,
-                            void *cb_context)
+static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+                         struct sk_buff *skb, data_exchange_cb_t cb,
+                         void *cb_context)
 {
        struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
        int r;
@@ -579,7 +580,7 @@ static struct nfc_ops hci_nfc_ops = {
        .stop_poll = hci_stop_poll,
        .activate_target = hci_activate_target,
        .deactivate_target = hci_deactivate_target,
-       .data_exchange = hci_data_exchange,
+       .im_transceive = hci_transceive,
        .check_presence = hci_check_presence,
 };
 
index 5665dc6d893a0800048abeba14d996c4f82b6d98..6b836e6242b7f91205331fb169e6da2e3c4db2e9 100644 (file)
@@ -765,14 +765,16 @@ static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
        return 0;
 }
 
-static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, u32 protocols)
+static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev,
+                               u32 im_protocols, u32 tm_protocols)
 {
        struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
 
        pr_debug("\n");
 
        if (shdlc->ops->start_poll)
-               return shdlc->ops->start_poll(shdlc, protocols);
+               return shdlc->ops->start_poll(shdlc,
+                                             im_protocols, tm_protocols);
 
        return 0;
 }
index bf8ae4f0b90c933d9dc3dbda70416498df2e97fa..b982b5b890d73da30a315567851d5d91e7ec9285 100644 (file)
@@ -51,7 +51,7 @@ static u8 llcp_tlv8(u8 *tlv, u8 type)
        return tlv[2];
 }
 
-static u8 llcp_tlv16(u8 *tlv, u8 type)
+static u16 llcp_tlv16(u8 *tlv, u8 type)
 {
        if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
                return 0;
@@ -67,7 +67,7 @@ static u8 llcp_tlv_version(u8 *tlv)
 
 static u16 llcp_tlv_miux(u8 *tlv)
 {
-       return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7f;
+       return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7ff;
 }
 
 static u16 llcp_tlv_wks(u8 *tlv)
@@ -117,8 +117,8 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
        return tlv;
 }
 
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-                      u8 *tlv_array, u16 tlv_array_len)
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+                         u8 *tlv_array, u16 tlv_array_len)
 {
        u8 *tlv = tlv_array, type, length, offset = 0;
 
@@ -149,8 +149,45 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
                case LLCP_TLV_OPT:
                        local->remote_opt = llcp_tlv_opt(tlv);
                        break;
+               default:
+                       pr_err("Invalid gt tlv value 0x%x\n", type);
+                       break;
+               }
+
+               offset += length + 2;
+               tlv += length + 2;
+       }
+
+       pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x\n",
+                local->remote_version, local->remote_miu,
+                local->remote_lto, local->remote_opt,
+                local->remote_wks);
+
+       return 0;
+}
+
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+                                 u8 *tlv_array, u16 tlv_array_len)
+{
+       u8 *tlv = tlv_array, type, length, offset = 0;
+
+       pr_debug("TLV array length %d\n", tlv_array_len);
+
+       if (sock == NULL)
+               return -ENOTCONN;
+
+       while (offset < tlv_array_len) {
+               type = tlv[0];
+               length = tlv[1];
+
+               pr_debug("type 0x%x length %d\n", type, length);
+
+               switch (type) {
+               case LLCP_TLV_MIUX:
+                       sock->miu = llcp_tlv_miux(tlv) + 128;
+                       break;
                case LLCP_TLV_RW:
-                       local->remote_rw = llcp_tlv_rw(tlv);
+                       sock->rw = llcp_tlv_rw(tlv);
                        break;
                case LLCP_TLV_SN:
                        break;
@@ -163,10 +200,7 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
                tlv += length + 2;
        }
 
-       pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n",
-                local->remote_version, local->remote_miu,
-                local->remote_lto, local->remote_opt,
-                local->remote_wks, local->remote_rw);
+       pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
 
        return 0;
 }
@@ -474,7 +508,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
        while (remaining_len > 0) {
 
-               frag_len = min_t(size_t, local->remote_miu, remaining_len);
+               frag_len = min_t(size_t, sock->miu, remaining_len);
 
                pr_debug("Fragment %zd bytes remaining %zd",
                         frag_len, remaining_len);
index 42994fac26d6c697671075eb86ed8321bfc75711..5d503eeb15a1a3f85732b289a5ff04e9f54ac887 100644 (file)
@@ -31,47 +31,41 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
 
 static struct list_head llcp_devices;
 
-static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
 {
-       struct nfc_llcp_sock *parent, *s, *n;
-       struct sock *sk, *parent_sk;
-       int i;
-
-       mutex_lock(&local->socket_lock);
-
-       for (i = 0; i < LLCP_MAX_SAP; i++) {
-               parent = local->sockets[i];
-               if (parent == NULL)
-                       continue;
-
-               /* Release all child sockets */
-               list_for_each_entry_safe(s, n, &parent->list, list) {
-                       list_del_init(&s->list);
-                       sk = &s->sk;
-
-                       lock_sock(sk);
-
-                       if (sk->sk_state == LLCP_CONNECTED)
-                               nfc_put_device(s->dev);
+       write_lock(&l->lock);
+       sk_add_node(sk, &l->head);
+       write_unlock(&l->lock);
+}
 
-                       sk->sk_state = LLCP_CLOSED;
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
+{
+       write_lock(&l->lock);
+       sk_del_node_init(sk);
+       write_unlock(&l->lock);
+}
 
-                       release_sock(sk);
+static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+{
+       struct sock *sk;
+       struct hlist_node *node, *tmp;
+       struct nfc_llcp_sock *llcp_sock;
 
-                       sock_orphan(sk);
+       write_lock(&local->sockets.lock);
 
-                       s->local = NULL;
-               }
+       sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
+               llcp_sock = nfc_llcp_sock(sk);
 
-               parent_sk = &parent->sk;
+               lock_sock(sk);
 
-               lock_sock(parent_sk);
+               if (sk->sk_state == LLCP_CONNECTED)
+                       nfc_put_device(llcp_sock->dev);
 
-               if (parent_sk->sk_state == LLCP_LISTEN) {
+               if (sk->sk_state == LLCP_LISTEN) {
                        struct nfc_llcp_sock *lsk, *n;
                        struct sock *accept_sk;
 
-                       list_for_each_entry_safe(lsk, n, &parent->accept_queue,
+                       list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
                                                 accept_queue) {
                                accept_sk = &lsk->sk;
                                lock_sock(accept_sk);
@@ -83,24 +77,53 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
                                release_sock(accept_sk);
 
                                sock_orphan(accept_sk);
-
-                               lsk->local = NULL;
                        }
                }
 
-               if (parent_sk->sk_state == LLCP_CONNECTED)
-                       nfc_put_device(parent->dev);
-
-               parent_sk->sk_state = LLCP_CLOSED;
+               sk->sk_state = LLCP_CLOSED;
 
-               release_sock(parent_sk);
+               release_sock(sk);
 
-               sock_orphan(parent_sk);
+               sock_orphan(sk);
 
-               parent->local = NULL;
+               sk_del_node_init(sk);
        }
 
-       mutex_unlock(&local->socket_lock);
+       write_unlock(&local->sockets.lock);
+}
+
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
+{
+       kref_get(&local->ref);
+
+       return local;
+}
+
+static void local_release(struct kref *ref)
+{
+       struct nfc_llcp_local *local;
+
+       local = container_of(ref, struct nfc_llcp_local, ref);
+
+       list_del(&local->list);
+       nfc_llcp_socket_release(local);
+       del_timer_sync(&local->link_timer);
+       skb_queue_purge(&local->tx_queue);
+       destroy_workqueue(local->tx_wq);
+       destroy_workqueue(local->rx_wq);
+       destroy_workqueue(local->timeout_wq);
+       kfree_skb(local->rx_pending);
+       kfree(local);
+}
+
+int nfc_llcp_local_put(struct nfc_llcp_local *local)
+{
+       WARN_ON(local == NULL);
+
+       if (local == NULL)
+               return 0;
+
+       return kref_put(&local->ref, local_release);
 }
 
 static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local)
@@ -384,31 +407,9 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
                return -EINVAL;
        }
 
-       return nfc_llcp_parse_tlv(local,
-                                 &local->remote_gb[3],
-                                 local->remote_gb_len - 3);
-}
-
-static void nfc_llcp_tx_work(struct work_struct *work)
-{
-       struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-                                                   tx_work);
-       struct sk_buff *skb;
-
-       skb = skb_dequeue(&local->tx_queue);
-       if (skb != NULL) {
-               pr_debug("Sending pending skb\n");
-               print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET,
-                              16, 1, skb->data, skb->len, true);
-
-               nfc_data_exchange(local->dev, local->target_idx,
-                                 skb, nfc_llcp_recv, local);
-       } else {
-               nfc_llcp_send_symm(local->dev);
-       }
-
-       mod_timer(&local->link_timer,
-                 jiffies + msecs_to_jiffies(local->remote_lto));
+       return nfc_llcp_parse_gb_tlv(local,
+                                    &local->remote_gb[3],
+                                    local->remote_gb_len - 3);
 }
 
 static u8 nfc_llcp_dsap(struct sk_buff *pdu)
@@ -443,46 +444,146 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
        sock->recv_ack_n = (sock->recv_n - 1) % 16;
 }
 
+static void nfc_llcp_tx_work(struct work_struct *work)
+{
+       struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+                                                   tx_work);
+       struct sk_buff *skb;
+       struct sock *sk;
+       struct nfc_llcp_sock *llcp_sock;
+
+       skb = skb_dequeue(&local->tx_queue);
+       if (skb != NULL) {
+               sk = skb->sk;
+               llcp_sock = nfc_llcp_sock(sk);
+               if (llcp_sock != NULL) {
+                       int ret;
+
+                       pr_debug("Sending pending skb\n");
+                       print_hex_dump(KERN_DEBUG, "LLCP Tx: ",
+                                      DUMP_PREFIX_OFFSET, 16, 1,
+                                      skb->data, skb->len, true);
+
+                       ret = nfc_data_exchange(local->dev, local->target_idx,
+                                               skb, nfc_llcp_recv, local);
+
+                       if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
+                               skb = skb_get(skb);
+                               skb_queue_tail(&llcp_sock->tx_pending_queue,
+                                              skb);
+                       }
+               } else {
+                       nfc_llcp_send_symm(local->dev);
+               }
+       } else {
+               nfc_llcp_send_symm(local->dev);
+       }
+
+       mod_timer(&local->link_timer,
+                 jiffies + msecs_to_jiffies(2 * local->remote_lto));
+}
+
+static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local,
+                                                         u8 ssap)
+{
+       struct sock *sk;
+       struct nfc_llcp_sock *llcp_sock;
+       struct hlist_node *node;
+
+       read_lock(&local->connecting_sockets.lock);
+
+       sk_for_each(sk, node, &local->connecting_sockets.head) {
+               llcp_sock = nfc_llcp_sock(sk);
+
+               if (llcp_sock->ssap == ssap) {
+                       sock_hold(&llcp_sock->sk);
+                       goto out;
+               }
+       }
+
+       llcp_sock = NULL;
+
+out:
+       read_unlock(&local->connecting_sockets.lock);
+
+       return llcp_sock;
+}
+
 static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
                                               u8 ssap, u8 dsap)
 {
-       struct nfc_llcp_sock *sock, *llcp_sock, *n;
+       struct sock *sk;
+       struct hlist_node *node;
+       struct nfc_llcp_sock *llcp_sock;
 
        pr_debug("ssap dsap %d %d\n", ssap, dsap);
 
        if (ssap == 0 && dsap == 0)
                return NULL;
 
-       mutex_lock(&local->socket_lock);
-       sock = local->sockets[ssap];
-       if (sock == NULL) {
-               mutex_unlock(&local->socket_lock);
-               return NULL;
-       }
+       read_lock(&local->sockets.lock);
 
-       pr_debug("root dsap %d (%d)\n", sock->dsap, dsap);
+       llcp_sock = NULL;
 
-       if (sock->dsap == dsap) {
-               sock_hold(&sock->sk);
-               mutex_unlock(&local->socket_lock);
-               return sock;
+       sk_for_each(sk, node, &local->sockets.head) {
+               llcp_sock = nfc_llcp_sock(sk);
+
+               if (llcp_sock->ssap == ssap &&
+                   llcp_sock->dsap == dsap)
+                       break;
        }
 
-       list_for_each_entry_safe(llcp_sock, n, &sock->list, list) {
-               pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock,
-                        &llcp_sock->sk, llcp_sock->dsap);
-               if (llcp_sock->dsap == dsap) {
-                       sock_hold(&llcp_sock->sk);
-                       mutex_unlock(&local->socket_lock);
-                       return llcp_sock;
-               }
+       read_unlock(&local->sockets.lock);
+
+       if (llcp_sock == NULL)
+               return NULL;
+
+       sock_hold(&llcp_sock->sk);
+
+       return llcp_sock;
+}
+
+static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local,
+                                                 u8 *sn, size_t sn_len)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+       struct nfc_llcp_sock *llcp_sock;
+
+       pr_debug("sn %zd\n", sn_len);
+
+       if (sn == NULL || sn_len == 0)
+               return NULL;
+
+       read_lock(&local->sockets.lock);
+
+       llcp_sock = NULL;
+
+       sk_for_each(sk, node, &local->sockets.head) {
+               llcp_sock = nfc_llcp_sock(sk);
+
+               if (llcp_sock->sk.sk_state != LLCP_LISTEN)
+                       continue;
+
+               if (llcp_sock->service_name == NULL ||
+                   llcp_sock->service_name_len == 0)
+                       continue;
+
+               if (llcp_sock->service_name_len != sn_len)
+                       continue;
+
+               if (memcmp(sn, llcp_sock->service_name, sn_len) == 0)
+                       break;
        }
 
-       pr_err("Could not find socket for %d %d\n", ssap, dsap);
+       read_unlock(&local->sockets.lock);
 
-       mutex_unlock(&local->socket_lock);
+       if (llcp_sock == NULL)
+               return NULL;
 
-       return NULL;
+       sock_hold(&llcp_sock->sk);
+
+       return llcp_sock;
 }
 
 static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
@@ -518,35 +619,19 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 {
        struct sock *new_sk, *parent;
        struct nfc_llcp_sock *sock, *new_sock;
-       u8 dsap, ssap, bound_sap, reason;
+       u8 dsap, ssap, reason;
 
        dsap = nfc_llcp_dsap(skb);
        ssap = nfc_llcp_ssap(skb);
 
        pr_debug("%d %d\n", dsap, ssap);
 
-       nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-                          skb->len - LLCP_HEADER_SIZE);
-
        if (dsap != LLCP_SAP_SDP) {
-               bound_sap = dsap;
-
-               mutex_lock(&local->socket_lock);
-               sock = local->sockets[dsap];
-               if (sock == NULL) {
-                       mutex_unlock(&local->socket_lock);
+               sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
+               if (sock == NULL || sock->sk.sk_state != LLCP_LISTEN) {
                        reason = LLCP_DM_NOBOUND;
                        goto fail;
                }
-
-               sock_hold(&sock->sk);
-               mutex_unlock(&local->socket_lock);
-
-               lock_sock(&sock->sk);
-
-               if (sock->dsap == LLCP_SAP_SDP &&
-                   sock->sk.sk_state == LLCP_LISTEN)
-                       goto enqueue;
        } else {
                u8 *sn;
                size_t sn_len;
@@ -559,40 +644,15 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 
                pr_debug("Service name length %zu\n", sn_len);
 
-               mutex_lock(&local->socket_lock);
-               for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
-                    bound_sap++) {
-                       sock = local->sockets[bound_sap];
-                       if (sock == NULL)
-                               continue;
-
-                       if (sock->service_name == NULL ||
-                           sock->service_name_len == 0)
-                                       continue;
-
-                       if (sock->service_name_len != sn_len)
-                               continue;
-
-                       if (sock->dsap == LLCP_SAP_SDP &&
-                           sock->sk.sk_state == LLCP_LISTEN &&
-                           !memcmp(sn, sock->service_name, sn_len)) {
-                               pr_debug("Found service name at SAP %d\n",
-                                        bound_sap);
-                               sock_hold(&sock->sk);
-                               mutex_unlock(&local->socket_lock);
-
-                               lock_sock(&sock->sk);
-
-                               goto enqueue;
-                       }
+               sock = nfc_llcp_sock_get_sn(local, sn, sn_len);
+               if (sock == NULL) {
+                       reason = LLCP_DM_NOBOUND;
+                       goto fail;
                }
-               mutex_unlock(&local->socket_lock);
        }
 
-       reason = LLCP_DM_NOBOUND;
-       goto fail;
+       lock_sock(&sock->sk);
 
-enqueue:
        parent = &sock->sk;
 
        if (sk_acceptq_is_full(parent)) {
@@ -612,15 +672,19 @@ enqueue:
 
        new_sock = nfc_llcp_sock(new_sk);
        new_sock->dev = local->dev;
-       new_sock->local = local;
+       new_sock->local = nfc_llcp_local_get(local);
+       new_sock->miu = local->remote_miu;
        new_sock->nfc_protocol = sock->nfc_protocol;
-       new_sock->ssap = bound_sap;
+       new_sock->ssap = sock->ssap;
        new_sock->dsap = ssap;
        new_sock->parent = parent;
 
+       nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE],
+                                     skb->len - LLCP_HEADER_SIZE);
+
        pr_debug("new sock %p sk %p\n", new_sock, &new_sock->sk);
 
-       list_add_tail(&new_sock->list, &sock->list);
+       nfc_llcp_sock_link(&local->sockets, new_sk);
 
        nfc_llcp_accept_enqueue(&sock->sk, new_sk);
 
@@ -654,12 +718,12 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
 
        pr_debug("Remote ready %d tx queue len %d remote rw %d",
                 sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
-                local->remote_rw);
+                sock->rw);
 
        /* Try to queue some I frames for transmission */
        while (sock->remote_ready &&
-              skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
-               struct sk_buff *pdu, *pending_pdu;
+              skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
+               struct sk_buff *pdu;
 
                pdu = skb_dequeue(&sock->tx_queue);
                if (pdu == NULL)
@@ -668,10 +732,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
                /* Update N(S)/N(R) */
                nfc_llcp_set_nrns(sock, pdu);
 
-               pending_pdu = skb_clone(pdu, GFP_KERNEL);
-
                skb_queue_tail(&local->tx_queue, pdu);
-               skb_queue_tail(&sock->tx_pending_queue, pending_pdu);
                nr_frames++;
        }
 
@@ -728,11 +789,21 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
 
                llcp_sock->send_ack_n = nr;
 
-               skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp)
-                       if (nfc_llcp_ns(s) <= nr) {
-                               skb_unlink(s, &llcp_sock->tx_pending_queue);
-                               kfree_skb(s);
-                       }
+               /* Remove and free all skbs until ns == nr */
+               skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) {
+                       skb_unlink(s, &llcp_sock->tx_pending_queue);
+                       kfree_skb(s);
+
+                       if (nfc_llcp_ns(s) == nr)
+                               break;
+               }
+
+               /* Re-queue the remaining skbs for transmission */
+               skb_queue_reverse_walk_safe(&llcp_sock->tx_pending_queue,
+                                           s, tmp) {
+                       skb_unlink(s, &llcp_sock->tx_pending_queue);
+                       skb_queue_head(&local->tx_queue, s);
+               }
        }
 
        if (ptype == LLCP_PDU_RR)
@@ -740,7 +811,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
        else if (ptype == LLCP_PDU_RNR)
                llcp_sock->remote_ready = false;
 
-       if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
+       if (nfc_llcp_queue_i_frames(llcp_sock) == 0 && ptype == LLCP_PDU_I)
                nfc_llcp_send_rr(llcp_sock);
 
        release_sock(sk);
@@ -791,11 +862,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
        dsap = nfc_llcp_dsap(skb);
        ssap = nfc_llcp_ssap(skb);
 
-       llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
-
-       if (llcp_sock == NULL)
-               llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
-
+       llcp_sock = nfc_llcp_connecting_sock_get(local, dsap);
        if (llcp_sock == NULL) {
                pr_err("Invalid CC\n");
                nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -803,11 +870,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
                return;
        }
 
-       llcp_sock->dsap = ssap;
        sk = &llcp_sock->sk;
 
-       nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
-                          skb->len - LLCP_HEADER_SIZE);
+       /* Unlink from connecting and link to the client array */
+       nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+       nfc_llcp_sock_link(&local->sockets, sk);
+       llcp_sock->dsap = ssap;
+
+       nfc_llcp_parse_connection_tlv(llcp_sock, &skb->data[LLCP_HEADER_SIZE],
+                                     skb->len - LLCP_HEADER_SIZE);
 
        sk->sk_state = LLCP_CONNECTED;
        sk->sk_state_change(sk);
@@ -891,6 +962,21 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
        return;
 }
 
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+       struct nfc_llcp_local *local;
+
+       local = nfc_llcp_find_local(dev);
+       if (local == NULL)
+               return -ENODEV;
+
+       local->rx_pending = skb_get(skb);
+       del_timer(&local->link_timer);
+       queue_work(local->rx_wq, &local->rx_work);
+
+       return 0;
+}
+
 void nfc_llcp_mac_is_down(struct nfc_dev *dev)
 {
        struct nfc_llcp_local *local;
@@ -943,8 +1029,8 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
 
        local->dev = ndev;
        INIT_LIST_HEAD(&local->list);
+       kref_init(&local->ref);
        mutex_init(&local->sdp_lock);
-       mutex_init(&local->socket_lock);
        init_timer(&local->link_timer);
        local->link_timer.data = (unsigned long) local;
        local->link_timer.function = nfc_llcp_symm_timer;
@@ -984,11 +1070,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
                goto err_rx_wq;
        }
 
+       local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock);
+       local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock);
+
        nfc_llcp_build_gb(local);
 
        local->remote_miu = LLCP_DEFAULT_MIU;
        local->remote_lto = LLCP_DEFAULT_LTO;
-       local->remote_rw = LLCP_DEFAULT_RW;
 
        list_add(&llcp_devices, &local->list);
 
@@ -1015,14 +1103,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
                return;
        }
 
-       list_del(&local->list);
-       nfc_llcp_socket_release(local);
-       del_timer_sync(&local->link_timer);
-       skb_queue_purge(&local->tx_queue);
-       destroy_workqueue(local->tx_wq);
-       destroy_workqueue(local->rx_wq);
-       kfree_skb(local->rx_pending);
-       kfree(local);
+       nfc_llcp_local_put(local);
 }
 
 int __init nfc_llcp_init(void)
index 50680ce5ae4396435552936f22cf3a8d17e26a25..7286c86982ffa0ec135376717b902354f0167eb3 100644 (file)
@@ -40,12 +40,18 @@ enum llcp_state {
 
 struct nfc_llcp_sock;
 
+struct llcp_sock_list {
+       struct hlist_head head;
+       rwlock_t          lock;
+};
+
 struct nfc_llcp_local {
        struct list_head list;
        struct nfc_dev *dev;
 
+       struct kref ref;
+
        struct mutex sdp_lock;
-       struct mutex socket_lock;
 
        struct timer_list link_timer;
        struct sk_buff_head tx_queue;
@@ -77,24 +83,26 @@ struct nfc_llcp_local {
        u16 remote_lto;
        u8  remote_opt;
        u16 remote_wks;
-       u8  remote_rw;
 
        /* sockets array */
-       struct nfc_llcp_sock *sockets[LLCP_MAX_SAP];
+       struct llcp_sock_list sockets;
+       struct llcp_sock_list connecting_sockets;
 };
 
 struct nfc_llcp_sock {
        struct sock sk;
-       struct list_head list;
        struct nfc_dev *dev;
        struct nfc_llcp_local *local;
        u32 target_idx;
        u32 nfc_protocol;
 
+       /* Link parameters */
        u8 ssap;
        u8 dsap;
        char *service_name;
        size_t service_name_len;
+       u8 rw;
+       u16 miu;
 
        /* Link variables */
        u8 send_n;
@@ -164,7 +172,11 @@ struct nfc_llcp_sock {
 #define LLCP_DM_REJ     0x03
 
 
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
+int nfc_llcp_local_put(struct nfc_llcp_local *local);
 u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
                         struct nfc_llcp_sock *sock);
 u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
@@ -179,8 +191,10 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk);
 struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock);
 
 /* TLV API */
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
-                      u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+                         u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+                                 u8 *tlv_array, u16 tlv_array_len);
 
 /* Commands API */
 void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
index e06d458fc7197ff73e1f1f6f155c154c330cfa67..05ca5a6800712335153eb62eeead88d09ffbb3bc 100644 (file)
@@ -111,7 +111,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        }
 
        llcp_sock->dev = dev;
-       llcp_sock->local = local;
+       llcp_sock->local = nfc_llcp_local_get(local);
        llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
        llcp_sock->service_name_len = min_t(unsigned int,
                                            llcp_addr.service_name_len,
@@ -124,7 +124,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (llcp_sock->ssap == LLCP_MAX_SAP)
                goto put_dev;
 
-       local->sockets[llcp_sock->ssap] = llcp_sock;
+       nfc_llcp_sock_link(&local->sockets, sk);
 
        pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
 
@@ -382,15 +382,6 @@ static int llcp_sock_release(struct socket *sock)
                goto out;
        }
 
-       mutex_lock(&local->socket_lock);
-
-       if (llcp_sock == local->sockets[llcp_sock->ssap])
-               local->sockets[llcp_sock->ssap] = NULL;
-       else
-               list_del_init(&llcp_sock->list);
-
-       mutex_unlock(&local->socket_lock);
-
        lock_sock(sk);
 
        /* Send a DISC */
@@ -415,14 +406,12 @@ static int llcp_sock_release(struct socket *sock)
                }
        }
 
-       /* Freeing the SAP */
-       if ((sk->sk_state == LLCP_CONNECTED
-            && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
-           sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
-               nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
+       nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
 
        release_sock(sk);
 
+       nfc_llcp_sock_unlink(&local->sockets, sk);
+
 out:
        sock_orphan(sk);
        sock_put(sk);
@@ -490,7 +479,8 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        }
 
        llcp_sock->dev = dev;
-       llcp_sock->local = local;
+       llcp_sock->local = nfc_llcp_local_get(local);
+       llcp_sock->miu = llcp_sock->local->remote_miu;
        llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
        if (llcp_sock->ssap == LLCP_SAP_MAX) {
                ret = -ENOMEM;
@@ -508,21 +498,26 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
                                          llcp_sock->service_name_len,
                                          GFP_KERNEL);
 
-       local->sockets[llcp_sock->ssap] = llcp_sock;
+       nfc_llcp_sock_link(&local->connecting_sockets, sk);
 
        ret = nfc_llcp_send_connect(llcp_sock);
        if (ret)
-               goto put_dev;
+               goto sock_unlink;
 
        ret = sock_wait_state(sk, LLCP_CONNECTED,
                              sock_sndtimeo(sk, flags & O_NONBLOCK));
        if (ret)
-               goto put_dev;
+               goto sock_unlink;
 
        release_sock(sk);
 
        return 0;
 
+sock_unlink:
+       nfc_llcp_put_ssap(local, llcp_sock->ssap);
+
+       nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+
 put_dev:
        nfc_put_device(dev);
 
@@ -687,13 +682,14 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
        llcp_sock->ssap = 0;
        llcp_sock->dsap = LLCP_SAP_SDP;
+       llcp_sock->rw = LLCP_DEFAULT_RW;
+       llcp_sock->miu = LLCP_DEFAULT_MIU;
        llcp_sock->send_n = llcp_sock->send_ack_n = 0;
        llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
        llcp_sock->remote_ready = 1;
        skb_queue_head_init(&llcp_sock->tx_queue);
        skb_queue_head_init(&llcp_sock->tx_pending_queue);
        skb_queue_head_init(&llcp_sock->tx_backlog_queue);
-       INIT_LIST_HEAD(&llcp_sock->list);
        INIT_LIST_HEAD(&llcp_sock->accept_queue);
 
        if (sock != NULL)
@@ -704,8 +700,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 
 void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 {
-       struct nfc_llcp_local *local = sock->local;
-
        kfree(sock->service_name);
 
        skb_queue_purge(&sock->tx_queue);
@@ -714,12 +708,9 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
 
        list_del_init(&sock->accept_queue);
 
-       if (local != NULL && sock == local->sockets[sock->ssap])
-               local->sockets[sock->ssap] = NULL;
-       else
-               list_del_init(&sock->list);
-
        sock->parent = NULL;
+
+       nfc_llcp_local_put(sock->local);
 }
 
 static int llcp_sock_create(struct net *net, struct socket *sock,
index d560e6f13072037a51fece26bd917bdb275b02e7..766a02b1dfa148fb521cc120f07623c00ac88e60 100644 (file)
@@ -387,7 +387,8 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
        return nci_close_device(ndev);
 }
 
-static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
+static int nci_start_poll(struct nfc_dev *nfc_dev,
+                         __u32 im_protocols, __u32 tm_protocols)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        int rc;
@@ -413,11 +414,11 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
                        return -EBUSY;
        }
 
-       rc = nci_request(ndev, nci_rf_discover_req, protocols,
+       rc = nci_request(ndev, nci_rf_discover_req, im_protocols,
                         msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
 
        if (!rc)
-               ndev->poll_prots = protocols;
+               ndev->poll_prots = im_protocols;
 
        return rc;
 }
@@ -521,9 +522,9 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
        }
 }
 
-static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
-                            struct sk_buff *skb,
-                            data_exchange_cb_t cb, void *cb_context)
+static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+                         struct sk_buff *skb,
+                         data_exchange_cb_t cb, void *cb_context)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        int rc;
@@ -556,7 +557,7 @@ static struct nfc_ops nci_nfc_ops = {
        .stop_poll = nci_stop_poll,
        .activate_target = nci_activate_target,
        .deactivate_target = nci_deactivate_target,
-       .data_exchange = nci_data_exchange,
+       .im_transceive = nci_transceive,
 };
 
 /* ---- Interface to NCI drivers ---- */
index 581d419083aafd9110f06715b4ccfaebc4e0e211..03c31db38f1284dbceed6cb57a97ab8ec0bd13ab 100644 (file)
@@ -49,6 +49,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
        [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
        [NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
        [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
+       [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
+       [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
 };
 
 static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -219,6 +221,68 @@ free_msg:
        return -EMSGSIZE;
 }
 
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+                         NFC_EVENT_TM_ACTIVATED);
+       if (!hdr)
+               goto free_msg;
+
+       if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+               goto nla_put_failure;
+       if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+free_msg:
+       nlmsg_free(msg);
+       return -EMSGSIZE;
+}
+
+int nfc_genl_tm_deactivated(struct nfc_dev *dev)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+                         NFC_EVENT_TM_DEACTIVATED);
+       if (!hdr)
+               goto free_msg;
+
+       if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+free_msg:
+       nlmsg_free(msg);
+       return -EMSGSIZE;
+}
+
 int nfc_genl_device_added(struct nfc_dev *dev)
 {
        struct sk_buff *msg;
@@ -519,16 +583,25 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
        struct nfc_dev *dev;
        int rc;
        u32 idx;
-       u32 protocols;
+       u32 im_protocols = 0, tm_protocols = 0;
 
        pr_debug("Poll start\n");
 
        if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
-           !info->attrs[NFC_ATTR_PROTOCOLS])
+           ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
+             !info->attrs[NFC_ATTR_PROTOCOLS]) &&
+            !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
                return -EINVAL;
 
        idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
-       protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
+
+       if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
+               tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
+
+       if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
+               im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
+       else if (info->attrs[NFC_ATTR_PROTOCOLS])
+               im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
 
        dev = nfc_get_device(idx);
        if (!dev)
@@ -536,7 +609,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
 
        mutex_lock(&dev->genl_data.genl_data_mutex);
 
-       rc = nfc_start_poll(dev, protocols);
+       rc = nfc_start_poll(dev, im_protocols, tm_protocols);
        if (!rc)
                dev->genl_data.poll_req_pid = info->snd_pid;
 
index 3dd4232ae6649a6a2bcc1816a46aa7e443fcec33..c5e42b79a418073d9ec8de66627c91d4ff3e3c23 100644 (file)
@@ -55,6 +55,7 @@ int nfc_llcp_register_device(struct nfc_dev *dev);
 void nfc_llcp_unregister_device(struct nfc_dev *dev);
 int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
 u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
 int __init nfc_llcp_init(void);
 void nfc_llcp_exit(void);
 
@@ -90,6 +91,12 @@ static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
        return NULL;
 }
 
+static inline int nfc_llcp_data_received(struct nfc_dev *dev,
+                                        struct sk_buff *skb)
+{
+       return 0;
+}
+
 static inline int nfc_llcp_init(void)
 {
        return 0;
@@ -128,6 +135,9 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
                               u8 comm_mode, u8 rf_mode);
 int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
 
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
+int nfc_genl_tm_deactivated(struct nfc_dev *dev);
+
 struct nfc_dev *nfc_get_device(unsigned int idx);
 
 static inline void nfc_put_device(struct nfc_dev *dev)
@@ -158,7 +168,7 @@ int nfc_dev_up(struct nfc_dev *dev);
 
 int nfc_dev_down(struct nfc_dev *dev);
 
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols);
 
 int nfc_stop_poll(struct nfc_dev *dev);
 
index f974961754ca90df62dcc685db2d037b910091b8..752b72360ebcb5736c849201aa6ed00361714ed9 100644 (file)
@@ -325,7 +325,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
 
        rfkill_global_states[type].cur = blocked;
        list_for_each_entry(rfkill, &rfkill_list, node) {
-               if (rfkill->type != type)
+               if (rfkill->type != type && type != RFKILL_TYPE_ALL)
                        continue;
 
                rfkill_set_block(rfkill, blocked);
index 2e4444fedbe0143430fdaffdd58c8793ee6da9de..4d2b1ec6516ff7f2e96c3ecee6bca4062c1d3a80 100644 (file)
@@ -114,24 +114,10 @@ config CFG80211_WEXT
        bool "cfg80211 wireless extensions compatibility"
        depends on CFG80211
        select WEXT_CORE
-       default y
        help
          Enable this option if you need old userspace for wireless
          extensions with cfg80211-based drivers.
 
-config WIRELESS_EXT_SYSFS
-       bool "Wireless extensions sysfs files"
-       depends on WEXT_CORE && SYSFS
-       help
-         This option enables the deprecated wireless statistics
-         files in /sys/class/net/*/wireless/. The same information
-         is available via the ioctls as well.
-
-         Say N. If you know you have ancient tools requiring it,
-         like very old versions of hal (prior to 0.5.12 release),
-         say Y and update the tools as soon as possible as this
-         option will be removed soon.
-
 config LIB80211
        tristate "Common routines for IEEE802.11 drivers"
        default n
index 884801ac4dd07a24db5b46c3df52fe44d81e2eec..c1999e45a07c125b51592a95763412e5863b2c37 100644 (file)
@@ -60,7 +60,7 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
                diff = -20;
                break;
        default:
-               return false;
+               return true;
        }
 
        sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
@@ -78,60 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
 
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-                     struct wireless_dev *wdev, int freq,
-                     enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                                int freq, enum nl80211_channel_type chantype)
 {
        struct ieee80211_channel *chan;
-       int result;
-
-       if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR)
-               wdev = NULL;
-
-       if (wdev) {
-               ASSERT_WDEV_LOCK(wdev);
-
-               if (!netif_running(wdev->netdev))
-                       return -ENETDOWN;
-       }
 
-       if (!rdev->ops->set_channel)
+       if (!rdev->ops->set_monitor_channel)
                return -EOPNOTSUPP;
 
-       chan = rdev_freq_to_chan(rdev, freq, channel_type);
+       chan = rdev_freq_to_chan(rdev, freq, chantype);
        if (!chan)
                return -EINVAL;
 
-       /* Both channels should be able to initiate communication */
-       if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
-                    wdev->iftype == NL80211_IFTYPE_AP ||
-                    wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
-                    wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
-                    wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
-               switch (channel_type) {
-               case NL80211_CHAN_HT40PLUS:
-               case NL80211_CHAN_HT40MINUS:
-                       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
-                                                         channel_type)) {
-                               printk(KERN_DEBUG
-                                      "cfg80211: Secondary channel not "
-                                      "allowed to initiate communication\n");
-                               return -EINVAL;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       result = rdev->ops->set_channel(&rdev->wiphy,
-                                       wdev ? wdev->netdev : NULL,
-                                       chan, channel_type);
-       if (result)
-               return result;
-
-       if (wdev)
-               wdev->channel = chan;
-
-       return 0;
+       return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
 }
index a87d4355297461d9ad31f4066758095d7d4cae4f..907f62c80e28cbc92403d65bb6fe984b56aae578 100644 (file)
@@ -96,69 +96,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
        return &rdev->wiphy;
 }
 
-/* requires cfg80211_mutex to be held! */
-struct cfg80211_registered_device *
-__cfg80211_rdev_from_info(struct genl_info *info)
-{
-       int ifindex;
-       struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
-       struct net_device *dev;
-       int err = -EINVAL;
-
-       assert_cfg80211_lock();
-
-       if (info->attrs[NL80211_ATTR_WIPHY]) {
-               bywiphyidx = cfg80211_rdev_by_wiphy_idx(
-                               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
-               err = -ENODEV;
-       }
-
-       if (info->attrs[NL80211_ATTR_IFINDEX]) {
-               ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
-               dev = dev_get_by_index(genl_info_net(info), ifindex);
-               if (dev) {
-                       if (dev->ieee80211_ptr)
-                               byifidx =
-                                       wiphy_to_dev(dev->ieee80211_ptr->wiphy);
-                       dev_put(dev);
-               }
-               err = -ENODEV;
-       }
-
-       if (bywiphyidx && byifidx) {
-               if (bywiphyidx != byifidx)
-                       return ERR_PTR(-EINVAL);
-               else
-                       return bywiphyidx; /* == byifidx */
-       }
-       if (bywiphyidx)
-               return bywiphyidx;
-
-       if (byifidx)
-               return byifidx;
-
-       return ERR_PTR(err);
-}
-
-struct cfg80211_registered_device *
-cfg80211_get_dev_from_info(struct genl_info *info)
-{
-       struct cfg80211_registered_device *rdev;
-
-       mutex_lock(&cfg80211_mutex);
-       rdev = __cfg80211_rdev_from_info(info);
-
-       /* if it is not an error we grab the lock on
-        * it to assure it won't be going away while
-        * we operate on it */
-       if (!IS_ERR(rdev))
-               mutex_lock(&rdev->mtx);
-
-       mutex_unlock(&cfg80211_mutex);
-
-       return rdev;
-}
-
 struct cfg80211_registered_device *
 cfg80211_get_dev_from_ifindex(struct net *net, int ifindex)
 {
index 8523f3878677518be3e46e3230903e2d90ba3ae0..609a579255acfd8e5398d73846a9c56eedd65399 100644 (file)
@@ -159,32 +159,6 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
 struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx);
 int get_wiphy_idx(struct wiphy *wiphy);
 
-struct cfg80211_registered_device *
-__cfg80211_rdev_from_info(struct genl_info *info);
-
-/*
- * This function returns a pointer to the driver
- * that the genl_info item that is passed refers to.
- * If successful, it returns non-NULL and also locks
- * the driver's mutex!
- *
- * This means that you need to call cfg80211_unlock_rdev()
- * before being allowed to acquire &cfg80211_mutex!
- *
- * This is necessary because we need to lock the global
- * mutex to get an item off the list safely, and then
- * we lock the rdev mutex so it doesn't go away under us.
- *
- * We don't want to keep cfg80211_mutex locked
- * for all the time in order to allow requests on
- * other interfaces to go through at the same time.
- *
- * The result of this can be a PTR_ERR and hence must
- * be checked with IS_ERR() for errors.
- */
-extern struct cfg80211_registered_device *
-cfg80211_get_dev_from_info(struct genl_info *info);
-
 /* requires cfg80211_rdev_mutex to be held! */
 struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
 
@@ -303,14 +277,17 @@ extern const struct mesh_config default_mesh_config;
 extern const struct mesh_setup default_mesh_setup;
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                         struct net_device *dev,
-                        const struct mesh_setup *setup,
+                        struct mesh_setup *setup,
                         const struct mesh_config *conf);
 int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      const struct mesh_setup *setup,
+                      struct mesh_setup *setup,
                       const struct mesh_config *conf);
 int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+                          struct wireless_dev *wdev, int freq,
+                          enum nl80211_channel_type channel_type);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -441,9 +418,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
                  int freq, enum nl80211_channel_type channel_type);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
-                     struct wireless_dev *wdev, int freq,
-                     enum nl80211_channel_type channel_type);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                                int freq, enum nl80211_channel_type chantype);
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
                           const u8 *rates, unsigned int n_rates,
index 2749cb86b4625142d53fa44e6145a011012fb478..3b73b07486cfb34197f653f1e4896e1cb56c6173 100644 (file)
@@ -14,6 +14,9 @@
 
 #define MESH_PATH_TIMEOUT      5000
 #define MESH_RANN_INTERVAL      5000
+#define MESH_PATH_TO_ROOT_TIMEOUT      6000
+#define MESH_ROOT_INTERVAL     5000
+#define MESH_ROOT_CONFIRMATION_INTERVAL 2000
 
 /*
  * Minimum interval between two consecutive PREQs originated by the same
@@ -62,9 +65,15 @@ const struct mesh_config default_mesh_config = {
        .dot11MeshForwarding = true,
        .rssi_threshold = MESH_RSSI_THRESHOLD,
        .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED,
+       .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
+       .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
+       .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
 };
 
 const struct mesh_setup default_mesh_setup = {
+       /* cfg80211_join_mesh() will pick a channel if needed */
+       .channel = NULL,
+       .channel_type = NL80211_CHAN_NO_HT,
        .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
        .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
        .path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -75,7 +84,7 @@ const struct mesh_setup default_mesh_setup = {
 
 int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                         struct net_device *dev,
-                        const struct mesh_setup *setup,
+                        struct mesh_setup *setup,
                         const struct mesh_config *conf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -101,6 +110,51 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (!rdev->ops->join_mesh)
                return -EOPNOTSUPP;
 
+       if (!setup->channel) {
+               /* if no channel explicitly given, use preset channel */
+               setup->channel = wdev->preset_chan;
+               setup->channel_type = wdev->preset_chantype;
+       }
+
+       if (!setup->channel) {
+               /* if we don't have that either, use the first usable channel */
+               enum ieee80211_band band;
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       struct ieee80211_supported_band *sband;
+                       struct ieee80211_channel *chan;
+                       int i;
+
+                       sband = rdev->wiphy.bands[band];
+                       if (!sband)
+                               continue;
+
+                       for (i = 0; i < sband->n_channels; i++) {
+                               chan = &sband->channels[i];
+                               if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
+                                                  IEEE80211_CHAN_PASSIVE_SCAN |
+                                                  IEEE80211_CHAN_DISABLED |
+                                                  IEEE80211_CHAN_RADAR))
+                                       continue;
+                               setup->channel = chan;
+                               break;
+                       }
+
+                       if (setup->channel)
+                               break;
+               }
+
+               /* no usable channel ... */
+               if (!setup->channel)
+                       return -EINVAL;
+
+               setup->channel_type = NL80211_CHAN_NO_HT;
+       }
+
+       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
+                                         setup->channel_type))
+               return -EINVAL;
+
        err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -112,7 +166,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 
 int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                       struct net_device *dev,
-                      const struct mesh_setup *setup,
+                      struct mesh_setup *setup,
                       const struct mesh_config *conf)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -125,6 +179,45 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        return err;
 }
 
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+                          struct wireless_dev *wdev, int freq,
+                          enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_channel *channel;
+
+       channel = rdev_freq_to_chan(rdev, freq, channel_type);
+       if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+                                                     channel,
+                                                     channel_type)) {
+               return -EINVAL;
+       }
+
+       /*
+        * Workaround for libertas (only!), it puts the interface
+        * into mesh mode but doesn't implement join_mesh. Instead,
+        * it is configured via sysfs and then joins the mesh when
+        * you set the channel. Note that the libertas mesh isn't
+        * compatible with 802.11 mesh.
+        */
+       if (rdev->ops->libertas_set_mesh_channel) {
+               if (channel_type != NL80211_CHAN_NO_HT)
+                       return -EINVAL;
+
+               if (!netif_running(wdev->netdev))
+                       return -ENETDOWN;
+               return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+                                                           wdev->netdev,
+                                                           channel);
+       }
+
+       if (wdev->mesh_id_len)
+               return -EBUSY;
+
+       wdev->preset_chan = channel;
+       wdev->preset_chantype = channel_type;
+       return 0;
+}
+
 void cfg80211_notify_new_peer_candidate(struct net_device *dev,
                const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
 {
index eb90988bbd36d4396ed2ac2094565561c5131875..da4406f11929e8235ac934ee40c04cc1b2a1547c 100644 (file)
@@ -947,8 +947,6 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
        if (WARN_ON(!chan))
                goto out;
 
-       wdev->channel = chan;
-
        nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
 out:
        wdev_unlock(wdev);
index 206465dc0cab403cede6c0f9b9321c4e3b696d7a..234ff3bbd104c9f8538e5225dfb1be2f7831b89a 100644 (file)
@@ -70,6 +70,94 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
        return 0;
 }
 
+static struct cfg80211_registered_device *
+__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
+{
+       struct cfg80211_registered_device *rdev = NULL, *tmp;
+       struct net_device *netdev;
+
+       assert_cfg80211_lock();
+
+       if (!attrs[NL80211_ATTR_WIPHY] &&
+           !attrs[NL80211_ATTR_IFINDEX])
+               return ERR_PTR(-EINVAL);
+
+       if (attrs[NL80211_ATTR_WIPHY])
+               rdev = cfg80211_rdev_by_wiphy_idx(
+                               nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
+
+       if (attrs[NL80211_ATTR_IFINDEX]) {
+               int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
+               netdev = dev_get_by_index(netns, ifindex);
+               if (netdev) {
+                       if (netdev->ieee80211_ptr)
+                               tmp = wiphy_to_dev(
+                                               netdev->ieee80211_ptr->wiphy);
+                       else
+                               tmp = NULL;
+
+                       dev_put(netdev);
+
+                       /* not wireless device -- return error */
+                       if (!tmp)
+                               return ERR_PTR(-EINVAL);
+
+                       /* mismatch -- return error */
+                       if (rdev && tmp != rdev)
+                               return ERR_PTR(-EINVAL);
+
+                       rdev = tmp;
+               }
+       }
+
+       if (!rdev)
+               return ERR_PTR(-ENODEV);
+
+       if (netns != wiphy_net(&rdev->wiphy))
+               return ERR_PTR(-ENODEV);
+
+       return rdev;
+}
+
+/*
+ * This function returns a pointer to the driver
+ * that the genl_info item that is passed refers to.
+ * If successful, it returns non-NULL and also locks
+ * the driver's mutex!
+ *
+ * This means that you need to call cfg80211_unlock_rdev()
+ * before being allowed to acquire &cfg80211_mutex!
+ *
+ * This is necessary because we need to lock the global
+ * mutex to get an item off the list safely, and then
+ * we lock the rdev mutex so it doesn't go away under us.
+ *
+ * We don't want to keep cfg80211_mutex locked
+ * for all the time in order to allow requests on
+ * other interfaces to go through at the same time.
+ *
+ * The result of this can be a PTR_ERR and hence must
+ * be checked with IS_ERR() for errors.
+ */
+static struct cfg80211_registered_device *
+cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+
+       mutex_lock(&cfg80211_mutex);
+       rdev = __cfg80211_rdev_from_attrs(netns, info->attrs);
+
+       /* if it is not an error we grab the lock on
+        * it to assure it won't be going away while
+        * we operate on it */
+       if (!IS_ERR(rdev))
+               mutex_lock(&rdev->mtx);
+
+       mutex_unlock(&cfg80211_mutex);
+
+       return rdev;
+}
+
 /* policy for the attributes */
 static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -115,7 +203,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
        [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
        [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
-                               .len = IEEE80211_MAX_MESH_ID_LEN },
+                                  .len = IEEE80211_MAX_MESH_ID_LEN },
        [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
 
        [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
@@ -250,8 +338,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
 
 static const struct nla_policy
 nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
-       [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
+       [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
                                                 .len = IEEE80211_MAX_SSID_LEN },
+       [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
 /* ifidx get helper */
@@ -921,7 +1010,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
                        goto nla_put_failure;
        }
-       CMD(set_channel, SET_CHANNEL);
+       if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
+           dev->ops->join_mesh) {
+               i++;
+               if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+                       goto nla_put_failure;
+       }
        CMD(set_wds_peer, SET_WDS_PEER);
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
                CMD(tdls_mgmt, TDLS_MGMT);
@@ -1162,18 +1256,22 @@ static int parse_txq_params(struct nlattr *tb[],
 static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
 {
        /*
-        * You can only set the channel explicitly for AP, mesh
-        * and WDS type interfaces; all others have their channel
-        * managed via their respective "establish a connection"
-        * command (connect, join, ...)
+        * You can only set the channel explicitly for WDS interfaces,
+        * all others have their channel managed via their respective
+        * "establish a connection" command (connect, join, ...)
+        *
+        * For AP/GO and mesh mode, the channel can be set with the
+        * channel userspace API, but is only stored and passed to the
+        * low-level driver when the AP starts or the mesh is joined.
+        * This is for backward compatibility, userspace can also give
+        * the channel in the start-ap or join-mesh commands instead.
         *
         * Monitors are special as they are normally slaved to
-        * whatever else is going on, so they behave as though
-        * you tried setting the wiphy channel itself.
+        * whatever else is going on, so they have their own special
+        * operation to set the monitor channel if possible.
         */
        return !wdev ||
                wdev->iftype == NL80211_IFTYPE_AP ||
-               wdev->iftype == NL80211_IFTYPE_WDS ||
                wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
                wdev->iftype == NL80211_IFTYPE_MONITOR ||
                wdev->iftype == NL80211_IFTYPE_P2P_GO;
@@ -1204,9 +1302,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 struct genl_info *info)
 {
+       struct ieee80211_channel *channel;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
        u32 freq;
        int result;
+       enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+       if (wdev)
+               iftype = wdev->iftype;
 
        if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
@@ -1221,12 +1324,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
 
        mutex_lock(&rdev->devlist_mtx);
-       if (wdev) {
-               wdev_lock(wdev);
-               result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
-               wdev_unlock(wdev);
-       } else {
-               result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+               if (wdev->beacon_interval) {
+                       result = -EBUSY;
+                       break;
+               }
+               channel = rdev_freq_to_chan(rdev, freq, channel_type);
+               if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+                                                             channel,
+                                                             channel_type)) {
+                       result = -EINVAL;
+                       break;
+               }
+               wdev->preset_chan = channel;
+               wdev->preset_chantype = channel_type;
+               result = 0;
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+               break;
+       default:
+               result = -EINVAL;
        }
        mutex_unlock(&rdev->devlist_mtx);
 
@@ -1300,7 +1423,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (!netdev) {
-               rdev = __cfg80211_rdev_from_info(info);
+               rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
+                                                 info->attrs);
                if (IS_ERR(rdev)) {
                        mutex_unlock(&cfg80211_mutex);
                        return PTR_ERR(rdev);
@@ -1310,8 +1434,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                result = 0;
 
                mutex_lock(&rdev->mtx);
-       } else if (netif_running(netdev) &&
-                  nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+       } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
                wdev = netdev->ieee80211_ptr;
        else
                wdev = NULL;
@@ -2213,6 +2336,33 @@ static int nl80211_parse_beacon(struct genl_info *info,
        return 0;
 }
 
+static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
+                                  struct cfg80211_ap_settings *params)
+{
+       struct wireless_dev *wdev;
+       bool ret = false;
+
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list) {
+               if (wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO)
+                       continue;
+
+               if (!wdev->preset_chan)
+                       continue;
+
+               params->channel = wdev->preset_chan;
+               params->channel_type = wdev->preset_chantype;
+               ret = true;
+               break;
+       }
+
+       mutex_unlock(&rdev->devlist_mtx);
+
+       return ret;
+}
+
 static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -2299,9 +2449,35 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                        info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+               if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+                   !nl80211_valid_channel_type(info, &channel_type))
+                       return -EINVAL;
+
+               params.channel = rdev_freq_to_chan(rdev,
+                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+                       channel_type);
+               if (!params.channel)
+                       return -EINVAL;
+               params.channel_type = channel_type;
+       } else if (wdev->preset_chan) {
+               params.channel = wdev->preset_chan;
+               params.channel_type = wdev->preset_chantype;
+       } else if (!nl80211_get_ap_channel(rdev, &params))
+               return -EINVAL;
+
+       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
+                                         params.channel_type))
+               return -EINVAL;
+
        err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
-       if (!err)
+       if (!err) {
+               wdev->preset_chan = params.channel;
+               wdev->preset_chantype = params.channel_type;
                wdev->beacon_interval = params.beacon_interval;
+       }
        return err;
 }
 
@@ -3413,7 +3589,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
            nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
                        cur_params.rssi_threshold) ||
            nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
-                       cur_params.ht_opmode))
+                       cur_params.ht_opmode) ||
+           nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+                       cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
+           nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+                       cur_params.dot11MeshHWMProotInterval) ||
+           nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+                       cur_params.dot11MeshHWMPconfirmationInterval))
                goto nla_put_failure;
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
@@ -3436,7 +3618,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
        [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
        [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
-
        [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
        [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
        [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
@@ -3448,8 +3629,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
        [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
-       [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
-       [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16},
+       [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
+       [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
+       [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
 };
 
 static const struct nla_policy
@@ -3459,7 +3643,7 @@ static const struct nla_policy
        [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
        [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
        [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
-               .len = IEEE80211_MAX_DATA_LEN },
+                                   .len = IEEE80211_MAX_DATA_LEN },
        [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
 };
 
@@ -3492,63 +3676,82 @@ do {\
 
        /* Fill in the params struct */
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
-                       mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
+                                 mask, NL80211_MESHCONF_RETRY_TIMEOUT,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
-                       mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16);
+                                 mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
-                       mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16);
+                                 mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
-                       mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16);
+                                 mask, NL80211_MESHCONF_MAX_PEER_LINKS,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
-                       mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
+                                 mask, NL80211_MESHCONF_MAX_RETRIES,
+                                 nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
-                       mask, NL80211_MESHCONF_TTL, nla_get_u8);
+                                 mask, NL80211_MESHCONF_TTL, nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
-                       mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
+                                 mask, NL80211_MESHCONF_ELEMENT_TTL,
+                                 nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
-                       mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
-                       mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
-                       nla_get_u32);
+                                 mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+                                 nla_get_u8);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask,
+                                 NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+                                 nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
-                       mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
-                       nla_get_u8);
+                                 mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+                                 nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
-                       mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32);
+                                 mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
+                                 nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
-                       mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
-                       nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
-                       mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
-                       nla_get_u32);
+                                 mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+                                 nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask,
+                                 NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+                                 nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
-                       mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
-                       nla_get_u16);
+                                 mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
-                       mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
-                       nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                       dot11MeshHWMPnetDiameterTraversalTime,
-                       mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
-                       nla_get_u16);
+                                 mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                       dot11MeshHWMPRootMode, mask,
-                       NL80211_MESHCONF_HWMP_ROOTMODE,
-                       nla_get_u8);
+                                 dot11MeshHWMPnetDiameterTraversalTime, mask,
+                                 NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+                                 nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
+                                 NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
+                                 NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+                                 nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                       dot11MeshHWMPRannInterval, mask,
-                       NL80211_MESHCONF_HWMP_RANN_INTERVAL,
-                       nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
-                       dot11MeshGateAnnouncementProtocol, mask,
-                       NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
-                       nla_get_u8);
+                                 dot11MeshGateAnnouncementProtocol, mask,
+                                 NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+                                 nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
-                       mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
+                                 mask, NL80211_MESHCONF_FORWARDING,
+                                 nla_get_u8);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
-                       mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
+                                 mask, NL80211_MESHCONF_RSSI_THRESHOLD,
+                                 nla_get_u32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
-                       mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16);
+                                 mask, NL80211_MESHCONF_HT_OPMODE,
+                                 nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
+                                 mask,
+                                 NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+                                 nla_get_u32);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval,
+                                 mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+                                 nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+                                 dot11MeshHWMPconfirmationInterval, mask,
+                                 NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+                                 nla_get_u16);
        if (mask_out)
                *mask_out = mask;
 
@@ -4185,12 +4388,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                nla_for_each_nested(attr,
                                    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
                                    tmp) {
-                       struct nlattr *ssid;
+                       struct nlattr *ssid, *rssi;
 
                        nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
                                  nla_data(attr), nla_len(attr),
                                  nl80211_match_policy);
-                       ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
+                       ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
                        if (ssid) {
                                if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
                                        err = -EINVAL;
@@ -4201,6 +4404,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                                request->match_sets[i].ssid.ssid_len =
                                        nla_len(ssid);
                        }
+                       rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+                       if (rssi)
+                               request->rssi_thold = nla_get_u32(rssi);
+                       else
+                               request->rssi_thold =
+                                                  NL80211_SCAN_RSSI_THOLD_OFF;
                        i++;
                }
        }
@@ -5058,21 +5267,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
                                  nl80211_policy);
                if (err)
                        return err;
-               if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) {
-                       phy_idx = nla_get_u32(
-                               nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
-               } else {
-                       struct net_device *netdev;
 
-                       err = get_rdev_dev_by_ifindex(sock_net(skb->sk),
-                                                     nl80211_fam.attrbuf,
-                                                     &rdev, &netdev);
-                       if (err)
-                               return err;
-                       dev_put(netdev);
-                       phy_idx = rdev->wiphy_idx;
-                       cfg80211_unlock_rdev(rdev);
+               mutex_lock(&cfg80211_mutex);
+               rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+                                                 nl80211_fam.attrbuf);
+               if (IS_ERR(rdev)) {
+                       mutex_unlock(&cfg80211_mutex);
+                       return PTR_ERR(rdev);
                }
+               phy_idx = rdev->wiphy_idx;
+               rdev = NULL;
+               mutex_unlock(&cfg80211_mutex);
+
                if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
                        cb->args[1] =
                                (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
@@ -5489,18 +5695,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
 
        duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 
+       if (!rdev->ops->remain_on_channel ||
+           !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
+               return -EOPNOTSUPP;
+
        /*
-        * We should be on that channel for at least one jiffie,
-        * and more than 5 seconds seems excessive.
+        * We should be on that channel for at least a minimum amount of
+        * time (10ms) but no longer than the driver supports.
         */
-       if (!duration || !msecs_to_jiffies(duration) ||
+       if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
            duration > rdev->wiphy.max_remain_on_channel_duration)
                return -EINVAL;
 
-       if (!rdev->ops->remain_on_channel ||
-           !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
-               return -EOPNOTSUPP;
-
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
            !nl80211_valid_channel_type(info, &channel_type))
                return -EINVAL;
@@ -5771,6 +5977,15 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                        return -EINVAL;
                wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+
+               /*
+                * We should wait on the channel for at least a minimum amount
+                * of time (10ms) but no longer than the driver supports.
+                */
+               if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
+                   wait > rdev->wiphy.max_remain_on_channel_duration)
+                       return -EINVAL;
+
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -6032,6 +6247,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+               if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+                   !nl80211_valid_channel_type(info, &channel_type))
+                       return -EINVAL;
+
+               setup.channel = rdev_freq_to_chan(rdev,
+                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+                       channel_type);
+               if (!setup.channel)
+                       return -EINVAL;
+               setup.channel_type = channel_type;
+       } else {
+               /* cfg80211_join_mesh() will sort it out */
+               setup.channel = NULL;
+       }
+
        return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
 }
 
@@ -6428,7 +6661,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
                rtnl_lock();
 
        if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
-               rdev = cfg80211_get_dev_from_info(info);
+               rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
                if (IS_ERR(rdev)) {
                        if (rtnl)
                                rtnl_unlock();
index 6a6181a673ca07a378a4b524f88249de78b661e4..bc879833b21f91354822dcabe841cb593dea36ca 100644 (file)
@@ -796,7 +796,15 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
        case NL80211_IFTYPE_MONITOR:
-       case NL80211_IFTYPE_WDS:
+               freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+               if (freq < 0)
+                       return freq;
+               if (freq == 0)
+                       return -EINVAL;
+               mutex_lock(&rdev->devlist_mtx);
+               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+               mutex_unlock(&rdev->devlist_mtx);
+               return err;
        case NL80211_IFTYPE_MESH_POINT:
                freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
                if (freq < 0)
@@ -804,9 +812,8 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                if (freq == 0)
                        return -EINVAL;
                mutex_lock(&rdev->devlist_mtx);
-               wdev_lock(wdev);
-               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
-               wdev_unlock(wdev);
+               err = cfg80211_set_mesh_freq(rdev, wdev, freq,
+                                            NL80211_CHAN_NO_HT);
                mutex_unlock(&rdev->devlist_mtx);
                return err;
        default:
@@ -839,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                freq->e = 6;
                return 0;
        default:
-               if (!wdev->channel)
-                       return -EINVAL;
-               freq->m = wdev->channel->center_freq;
-               freq->e = 6;
-               return 0;
+               return -EINVAL;
        }
 }
 
index 7decbd357d516161c0c659a093d9066926daac4b..1f773f668d1a557ae2712195ed510c3b9a2405b3 100644 (file)
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
        wdev->wext.connect.channel = chan;
 
-       /* SSID is not set, we just want to switch channel */
+       /*
+        * SSID is not set, we just want to switch monitor channel,
+        * this is really just backward compatibility, if the SSID
+        * is set then we use the channel to select the BSS to use
+        * to connect to instead. If we were connected on another
+        * channel we disconnected above and reconnect below.
+        */
        if (chan && !wdev->wext.connect.ssid_len) {
-               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
                goto out;
        }