summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig163
-rw-r--r--drivers/net/wireless/Makefile22
-rw-r--r--drivers/net/wireless/adm8211.c52
-rw-r--r--drivers/net/wireless/adm8211.h2
-rw-r--r--drivers/net/wireless/airo.c243
-rw-r--r--drivers/net/wireless/arlan-main.c27
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h102
-rw-r--r--drivers/net/wireless/ath5k/attach.c14
-rw-r--r--drivers/net/wireless/ath5k/base.c226
-rw-r--r--drivers/net/wireless/ath5k/base.h1
-rw-r--r--drivers/net/wireless/ath5k/debug.c10
-rw-r--r--drivers/net/wireless/ath5k/desc.c4
-rw-r--r--drivers/net/wireless/ath5k/dma.c190
-rw-r--r--drivers/net/wireless/ath5k/eeprom.c1194
-rw-r--r--drivers/net/wireless/ath5k/eeprom.h253
-rw-r--r--drivers/net/wireless/ath5k/initvals.c8
-rw-r--r--drivers/net/wireless/ath5k/pcu.c233
-rw-r--r--drivers/net/wireless/ath5k/phy.c9
-rw-r--r--drivers/net/wireless/ath5k/qcu.c37
-rw-r--r--drivers/net/wireless/ath5k/reg.h16
-rw-r--r--drivers/net/wireless/ath5k/reset.c9
-rw-r--r--drivers/net/wireless/ath9k/Kconfig11
-rw-r--r--drivers/net/wireless/ath9k/Makefile9
-rw-r--r--drivers/net/wireless/ath9k/ani.c852
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h432
-rw-r--r--drivers/net/wireless/ath9k/beacon.c329
-rw-r--r--drivers/net/wireless/ath9k/calib.c1021
-rw-r--r--drivers/net/wireless/ath9k/core.c1886
-rw-r--r--drivers/net/wireless/ath9k/core.h926
-rw-r--r--drivers/net/wireless/ath9k/debug.c262
-rw-r--r--drivers/net/wireless/ath9k/eeprom.c2824
-rw-r--r--drivers/net/wireless/ath9k/hw.c8490
-rw-r--r--drivers/net/wireless/ath9k/hw.h165
-rw-r--r--drivers/net/wireless/ath9k/initvals.h1938
-rw-r--r--drivers/net/wireless/ath9k/mac.c946
-rw-r--r--drivers/net/wireless/ath9k/main.c2353
-rw-r--r--drivers/net/wireless/ath9k/phy.c24
-rw-r--r--drivers/net/wireless/ath9k/phy.h5
-rw-r--r--drivers/net/wireless/ath9k/rc.c1832
-rw-r--r--drivers/net/wireless/ath9k/rc.h220
-rw-r--r--drivers/net/wireless/ath9k/recv.c1251
-rw-r--r--drivers/net/wireless/ath9k/reg.h109
-rw-r--r--drivers/net/wireless/ath9k/regd.c85
-rw-r--r--drivers/net/wireless/ath9k/regd.h2
-rw-r--r--drivers/net/wireless/ath9k/xmit.c1532
-rw-r--r--drivers/net/wireless/atmel.c79
-rw-r--r--drivers/net/wireless/b43/b43.h1
-rw-r--r--drivers/net/wireless/b43/debugfs.c1
-rw-r--r--drivers/net/wireless/b43/debugfs.h1
-rw-r--r--drivers/net/wireless/b43/dma.c4
-rw-r--r--drivers/net/wireless/b43/main.c280
-rw-r--r--drivers/net/wireless/b43/phy_a.c4
-rw-r--r--drivers/net/wireless/b43/phy_common.c18
-rw-r--r--drivers/net/wireless/b43/phy_g.c28
-rw-r--r--drivers/net/wireless/b43/pio.c3
-rw-r--r--drivers/net/wireless/b43/xmit.c64
-rw-r--r--drivers/net/wireless/b43/xmit.h5
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h5
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.c2
-rw-r--r--drivers/net/wireless/b43legacy/dma.c48
-rw-r--r--drivers/net/wireless/b43legacy/main.c211
-rw-r--r--drivers/net/wireless/b43legacy/phy.c6
-rw-r--r--drivers/net/wireless/b43legacy/pio.c31
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c26
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h2
-rw-r--r--drivers/net/wireless/hostap/Kconfig13
-rw-r--r--drivers/net/wireless/hostap/hostap.h2
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h2
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c72
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c23
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c253
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.h8
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h13
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c71
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c16
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c157
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c45
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c35
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h8
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig191
-rw-r--r--drivers/net/wireless/ipw2x00/Makefile14
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c (renamed from drivers/net/wireless/ipw2100.c)71
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h (renamed from drivers/net/wireless/ipw2100.h)0
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c (renamed from drivers/net/wireless/ipw2200.c)486
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.h (renamed from drivers/net/wireless/ipw2200.h)2
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_geo.c195
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_module.c293
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_rx.c1799
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c546
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_wx.c760
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig2
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-commands.h148
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-core.h28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-debug.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-io.h24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c223
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c125
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h203
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c251
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c440
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c108
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c179
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c1249
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h536
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c332
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h78
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c83
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h183
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h173
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h111
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c230
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c131
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.c198
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c283
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c438
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c751
-rw-r--r--drivers/net/wireless/libertas/assoc.c69
-rw-r--r--drivers/net/wireless/libertas/cmd.c32
-rw-r--r--drivers/net/wireless/libertas/cmd.h3
-rw-r--r--drivers/net/wireless/libertas/debugfs.c11
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/defs.h14
-rw-r--r--drivers/net/wireless/libertas/dev.h7
-rw-r--r--drivers/net/wireless/libertas/ethtool.c14
-rw-r--r--drivers/net/wireless/libertas/host.h9
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h26
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c3
-rw-r--r--drivers/net/wireless/libertas/if_usb.c7
-rw-r--r--drivers/net/wireless/libertas/main.c135
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c18
-rw-r--r--drivers/net/wireless/libertas/radiotap.h3
-rw-r--r--drivers/net/wireless/libertas/scan.c105
-rw-r--r--drivers/net/wireless/libertas/scan.h4
-rw-r--r--drivers/net/wireless/libertas/tx.c2
-rw-r--r--drivers/net/wireless/libertas/types.h5
-rw-r--r--drivers/net/wireless/libertas/wext.c80
-rw-r--r--drivers/net/wireless/libertas_tf/cmd.c5
-rw-r--r--drivers/net/wireless/libertas_tf/main.c8
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c294
-rw-r--r--drivers/net/wireless/netwave_cs.c6
-rw-r--r--drivers/net/wireless/orinoco/Makefile12
-rw-r--r--drivers/net/wireless/orinoco/airport.c (renamed from drivers/net/wireless/airport.c)2
-rw-r--r--drivers/net/wireless/orinoco/hermes.c (renamed from drivers/net/wireless/hermes.c)0
-rw-r--r--drivers/net/wireless/orinoco/hermes.h (renamed from drivers/net/wireless/hermes.h)0
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c (renamed from drivers/net/wireless/hermes_dld.c)0
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.h (renamed from drivers/net/wireless/hermes_dld.h)0
-rw-r--r--drivers/net/wireless/orinoco/hermes_rid.h (renamed from drivers/net/wireless/hermes_rid.h)0
-rw-r--r--drivers/net/wireless/orinoco/orinoco.c (renamed from drivers/net/wireless/orinoco.c)231
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h (renamed from drivers/net/wireless/orinoco.h)9
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c (renamed from drivers/net/wireless/orinoco_cs.c)10
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c (renamed from drivers/net/wireless/orinoco_nortel.c)0
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c (renamed from drivers/net/wireless/orinoco_pci.c)0
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h (renamed from drivers/net/wireless/orinoco_pci.h)0
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c (renamed from drivers/net/wireless/orinoco_plx.c)0
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c (renamed from drivers/net/wireless/orinoco_tmd.c)0
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c (renamed from drivers/net/wireless/spectrum_cs.c)31
-rw-r--r--drivers/net/wireless/p54/p54.h74
-rw-r--r--drivers/net/wireless/p54/p54common.c1620
-rw-r--r--drivers/net/wireless/p54/p54common.h349
-rw-r--r--drivers/net/wireless/p54/p54pci.c70
-rw-r--r--drivers/net/wireless/p54/p54pci.h2
-rw-r--r--drivers/net/wireless/p54/p54usb.c261
-rw-r--r--drivers/net/wireless/p54/p54usb.h1
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c24
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c8
-rw-r--r--drivers/net/wireless/ray_cs.c12
-rw-r--r--drivers/net/wireless/rndis_wlan.c95
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c373
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c407
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c443
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h113
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c202
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c79
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c47
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.h13
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c86
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00leds.c88
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h33
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c56
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c41
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c94
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h47
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c145
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h141
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c469
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c689
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h2
-rw-r--r--drivers/net/wireless/rtl818x/Makefile7
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180.h (renamed from drivers/net/wireless/rtl8180.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c (renamed from drivers/net/wireless/rtl8180_dev.c)48
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_grf5101.c (renamed from drivers/net/wireless/rtl8180_grf5101.c)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_grf5101.h (renamed from drivers/net/wireless/rtl8180_grf5101.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_max2820.c (renamed from drivers/net/wireless/rtl8180_max2820.c)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_max2820.h (renamed from drivers/net/wireless/rtl8180_max2820.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_rtl8225.c (renamed from drivers/net/wireless/rtl8180_rtl8225.c)14
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_rtl8225.h (renamed from drivers/net/wireless/rtl8180_rtl8225.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_sa2400.c (renamed from drivers/net/wireless/rtl8180_sa2400.c)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_sa2400.h (renamed from drivers/net/wireless/rtl8180_sa2400.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h (renamed from drivers/net/wireless/rtl8187.h)8
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c (renamed from drivers/net/wireless/rtl8187_dev.c)459
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rtl8225.c (renamed from drivers/net/wireless/rtl8187_rtl8225.c)397
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_rtl8225.h (renamed from drivers/net/wireless/rtl8187_rtl8225.h)0
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h (renamed from drivers/net/wireless/rtl818x.h)1
-rw-r--r--drivers/net/wireless/strip.c22
-rw-r--r--drivers/net/wireless/wavelan.c122
-rw-r--r--drivers/net/wireless/wavelan_cs.c39
-rw-r--r--drivers/net/wireless/wl3501.h4
-rw-r--r--drivers/net/wireless/wl3501_cs.c11
-rw-r--r--drivers/net/wireless/zd1201.c131
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c46
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c5
244 files changed, 29461 insertions, 22270 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 45bdf0b339b..ea543fcf268 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -123,154 +123,11 @@ config PCMCIA_RAYCS
To compile this driver as a module, choose M here: the module will be
called ray_cs. If unsure, say N.
-config IPW2100
- tristate "Intel PRO/Wireless 2100 Network Connection"
- depends on PCI && WLAN_80211
- select WIRELESS_EXT
- select FW_LOADER
- select IEEE80211
- ---help---
- A driver for the Intel PRO/Wireless 2100 Network
- Connection 802.11b wireless network adapter.
-
- See <file:Documentation/networking/README.ipw2100> for information on
- the capabilities currently enabled in this driver and for tips
- for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2100.sf.net/>. Once you have the firmware image, you
- will need to place it in /lib/firmware.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2100_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2100
- ---help---
- Enables promiscuous/monitor mode support for the ipw2100 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2100_DEBUG
- bool "Enable full debugging output in IPW2100 module."
- depends on IPW2100
- ---help---
- This option will enable debug tracing output for the IPW2100.
-
- This will result in the kernel module being ~60k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/bus/pci/drivers/ipw2100/debug_level
-
- This entry will only exist if this option is enabled.
-
- If you are not trying to debug or develop the IPW2100 driver, you
- most likely want to say N here.
-
-config IPW2200
- tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && WLAN_80211
- select WIRELESS_EXT
- select FW_LOADER
- select IEEE80211
- ---help---
- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
- Connection adapters.
-
- See <file:Documentation/networking/README.ipw2200> for
- information on the capabilities currently enabled in this
- driver and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
- for information on where to install the firmware images.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2200_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2200
- ---help---
- Enables promiscuous/monitor mode support for the ipw2200 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2200_RADIOTAP
- bool "Enable radiotap format 802.11 raw packet support"
- depends on IPW2200_MONITOR
-
-config IPW2200_PROMISCUOUS
- bool "Enable creation of a RF radiotap promiscuous interface"
- depends on IPW2200_MONITOR
- select IPW2200_RADIOTAP
- ---help---
- Enables the creation of a second interface prefixed 'rtap'.
- This second interface will provide every received in radiotap
- format.
-
- This is useful for performing wireless network analysis while
- maintaining an active association.
-
- Example usage:
-
- % modprobe ipw2200 rtap_iface=1
- % ifconfig rtap0 up
- % tethereal -i rtap0
-
- If you do not specify 'rtap_iface=1' as a module parameter then
- the rtap interface will not be created and you will need to turn
- it on via sysfs:
-
- % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
-
-config IPW2200_QOS
- bool "Enable QoS support"
- depends on IPW2200 && EXPERIMENTAL
-
-config IPW2200_DEBUG
- bool "Enable full debugging output in IPW2200 module."
- depends on IPW2200
- ---help---
- This option will enable low level debug tracing output for IPW2200.
-
- Note, normal debug code is already compiled in. This low level
- debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
- will result in the kernel module being ~70 larger. Most users
- will typically not need this high verbosity debug information.
-
- If you are not sure, say N here.
-
config LIBERTAS
tristate "Marvell 8xxx Libertas WLAN driver support"
depends on WLAN_80211
select WIRELESS_EXT
+ select LIB80211
select FW_LOADER
---help---
A library for Marvell Libertas 8xxx devices.
@@ -357,6 +214,21 @@ config HERMES
configure your card and that /etc/pcmcia/wireless.opts works :
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
+config HERMES_CACHE_FW_ON_INIT
+ bool "Cache Hermes firmware on driver initialisation"
+ depends on HERMES
+ default y
+ ---help---
+ Say Y to cache any firmware required by the Hermes drivers
+ on startup. The firmware will remain cached until the
+ driver is unloaded. The cache uses 64K of RAM.
+
+ Otherwise load the firmware from userspace as required. In
+ this case the driver should be unloaded and restarted
+ whenever the firmware is changed.
+
+ If you are not sure, say Y.
+
config APPLE_AIRPORT
tristate "Apple Airport support (built-in)"
depends on PPC_PMAC && HERMES
@@ -651,7 +523,7 @@ config RTL8180
config RTL8187
tristate "Realtek 8187 and 8187B USB support"
- depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+ depends on MAC80211 && USB && WLAN_80211
select EEPROM_93CX6
---help---
This is a driver for RTL8187 and RTL8187B based cards.
@@ -711,6 +583,7 @@ config MAC80211_HWSIM
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath5k/Kconfig"
source "drivers/net/wireless/ath9k/Kconfig"
+source "drivers/net/wireless/ipw2x00/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 59d2d805f60..ac590e1ca8b 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -2,9 +2,8 @@
# Makefile for the Linux Wireless network device drivers.
#
-obj-$(CONFIG_IPW2100) += ipw2100.o
-
-obj-$(CONFIG_IPW2200) += ipw2200.o
+obj-$(CONFIG_IPW2100) += ipw2x00/
+obj-$(CONFIG_IPW2200) += ipw2x00/
obj-$(CONFIG_STRIP) += strip.o
obj-$(CONFIG_ARLAN) += arlan.o
@@ -16,14 +15,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o
obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o
obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o
-obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o
-obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT) += airport.o
-obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
+obj-$(CONFIG_HERMES) += orinoco/
obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
@@ -38,6 +30,8 @@ obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_B43) += b43/
obj-$(CONFIG_B43LEGACY) += b43legacy/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
+obj-$(CONFIG_RTL8180) += rtl818x/
+obj-$(CONFIG_RTL8187) += rtl818x/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
@@ -50,12 +44,6 @@ obj-$(CONFIG_LIBERTAS) += libertas/
obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/
-rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
-
-obj-$(CONFIG_RTL8180) += rtl8180.o
-obj-$(CONFIG_RTL8187) += rtl8187.o
-
obj-$(CONFIG_ADM8211) += adm8211.o
obj-$(CONFIG_IWLWIFI) += iwlwifi/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index b2c050b6889..fc0897fb223 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
pci_unmap_single(priv->pdev, info->mapping,
info->skb->len, PCI_DMA_TODEVICE);
- memset(&txi->status, 0, sizeof(txi->status));
+ ieee80211_tx_info_clear_status(txi);
+
skb_pull(skb, sizeof(struct adm8211_tx_hdr));
memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
- if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
- if (status & TDES0_STATUS_ES)
- txi->status.excessive_retries = 1;
- else
- txi->flags |= IEEE80211_TX_STAT_ACK;
- }
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ !(status & TDES0_STATUS_ES))
+ txi->flags |= IEEE80211_TX_STAT_ACK;
+
ieee80211_tx_status_irqsafe(dev, skb);
info->skb = NULL;
@@ -1298,25 +1297,10 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
ADM8211_CSR_WRITE(ABDA1, reg);
}
-static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
-{
- struct adm8211_priv *priv = dev->priv;
- u8 buf[36];
-
- if (ssid_len > 32)
- return -EINVAL;
-
- memset(buf, 0, sizeof(buf));
- buf[0] = ssid_len;
- memcpy(buf + 1, ssid, ssid_len);
- adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
- /* TODO: configure beacon for adhoc? */
- return 0;
-}
-
-static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
{
struct adm8211_priv *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
if (channel != priv->channel) {
@@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev,
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
}
- if (conf->ssid_len != priv->ssid_len ||
- memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
- adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
- priv->ssid_len = conf->ssid_len;
- memcpy(priv->ssid, conf->ssid, conf->ssid_len);
- }
-
return 0;
}
@@ -1690,8 +1667,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
+ u8 rc_flags;
- short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
+ rc_flags = info->control.rates[0].flags;
+ short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
plcp_signal = txrate->bitrate;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -1723,10 +1702,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
if (short_preamble)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
- txhdr->retry_limit = info->control.retry_limit;
+ txhdr->retry_limit = info->control.rates[0].count;
adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
@@ -1791,7 +1770,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
int err;
u32 reg;
u8 perm_addr[ETH_ALEN];
- DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if (err) {
@@ -1925,8 +1903,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
goto err_free_desc;
}
- printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",
- wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+ printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
pdev->revision);
return 0;
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index 9b190ee26e9..4f6ab132218 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -553,8 +553,6 @@ struct adm8211_priv {
int channel;
u8 bssid[ETH_ALEN];
- u8 ssid[32];
- size_t ssid_len;
u8 soft_rx_crc;
u8 retry_limit;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 370133e492d..fc4322ca669 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -47,10 +47,11 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
-#include <net/ieee80211.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/ieee80211.h>
+
#include "airo.h"
#define DRV_NAME "airo"
@@ -1270,6 +1271,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev);
#define airo_print_err(name, fmt, args...) \
airo_print(KERN_ERR, name, fmt, ##args)
+#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash)
/***********************************************************************
* MIC ROUTINES *
@@ -1865,7 +1867,7 @@ static void try_auto_wep(struct airo_info *ai)
}
static int airo_open(struct net_device *dev) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int rc = 0;
if (test_bit(FLAG_FLASHING, &ai->flags))
@@ -1912,7 +1914,7 @@ static int airo_open(struct net_device *dev) {
static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
int npacks, pending;
unsigned long flags;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
if (!skb) {
airo_print_err(dev->name, "%s: skb == NULL!",__func__);
@@ -1956,7 +1958,7 @@ static int mpi_send_packet (struct net_device *dev)
unsigned char *buffer;
s16 len;
__le16 *payloadLen;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
u8 *sendbuf;
/* get a packet to send */
@@ -2085,7 +2087,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
static void airo_end_xmit(struct net_device *dev) {
u16 status;
int i;
- struct airo_info *priv = dev->priv;
+ struct airo_info *priv = dev->ml_priv;
struct sk_buff *skb = priv->xmit.skb;
int fid = priv->xmit.fid;
u32 *fids = priv->fids;
@@ -2111,7 +2113,7 @@ static void airo_end_xmit(struct net_device *dev) {
static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
s16 len;
int i, j;
- struct airo_info *priv = dev->priv;
+ struct airo_info *priv = dev->ml_priv;
u32 *fids = priv->fids;
if ( skb == NULL ) {
@@ -2150,7 +2152,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
static void airo_end_xmit11(struct net_device *dev) {
u16 status;
int i;
- struct airo_info *priv = dev->priv;
+ struct airo_info *priv = dev->ml_priv;
struct sk_buff *skb = priv->xmit11.skb;
int fid = priv->xmit11.fid;
u32 *fids = priv->fids;
@@ -2176,7 +2178,7 @@ static void airo_end_xmit11(struct net_device *dev) {
static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
s16 len;
int i, j;
- struct airo_info *priv = dev->priv;
+ struct airo_info *priv = dev->ml_priv;
u32 *fids = priv->fids;
if (test_bit(FLAG_MPI, &priv->flags)) {
@@ -2220,7 +2222,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
static void airo_read_stats(struct net_device *dev)
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
StatsRid stats_rid;
__le32 *vals = stats_rid.vals;
@@ -2254,7 +2256,7 @@ static void airo_read_stats(struct net_device *dev)
static struct net_device_stats *airo_get_stats(struct net_device *dev)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
if (!test_bit(JOB_STATS, &local->jobs)) {
/* Get stats out of the card if available */
@@ -2281,7 +2283,7 @@ static void airo_set_promisc(struct airo_info *ai) {
}
static void airo_set_multicast_list(struct net_device *dev) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
change_bit(FLAG_PROMISC, &ai->flags);
@@ -2299,7 +2301,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
static int airo_set_mac_address(struct net_device *dev, void *p)
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
struct sockaddr *addr = p;
readConfigRid(ai, 1);
@@ -2339,7 +2341,7 @@ static void del_airo_dev(struct airo_info *ai)
}
static int airo_close(struct net_device *dev) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
netif_stop_queue(dev);
@@ -2365,7 +2367,7 @@ static int airo_close(struct net_device *dev) {
void stop_airo_card( struct net_device *dev, int freeres )
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
set_bit(FLAG_RADIO_DOWN, &ai->flags);
disable_MAC(ai, 1);
@@ -2665,7 +2667,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup);
if (!dev)
return NULL;
- dev->priv = ethdev->priv;
+ dev->ml_priv = ethdev->ml_priv;
dev->irq = ethdev->irq;
dev->base_addr = ethdev->base_addr;
dev->wireless_data = ethdev->wireless_data;
@@ -2680,7 +2682,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
}
static int reset_card( struct net_device *dev , int lock) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
if (lock && down_interruptible(&ai->sem))
return -1;
@@ -2757,7 +2759,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
struct net_device *dev;
struct airo_info *ai;
int i, rc;
- DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2766,7 +2767,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
return NULL;
}
- ai = dev->priv;
+ ai = dev->ml_priv = netdev_priv(dev);
ai->wifidev = NULL;
ai->flags = 1 << FLAG_RADIO_DOWN;
ai->jobs = 0;
@@ -2860,15 +2861,14 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
goto err_out_reg;
set_bit(FLAG_REGISTERED,&ai->flags);
- airo_print_info(dev->name, "MAC enabled %s",
- print_mac(mac, dev->dev_addr));
+ airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
/* Allocate the transmit buffers */
if (probe && !test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
- if (setup_proc_entry(dev, dev->priv) < 0)
+ if (setup_proc_entry(dev, dev->ml_priv) < 0)
goto err_out_wifi;
return dev;
@@ -2917,8 +2917,7 @@ static int waitbusy (struct airo_info *ai) {
int reset_airo_card( struct net_device *dev )
{
int i;
- struct airo_info *ai = dev->priv;
- DECLARE_MAC_BUF(mac);
+ struct airo_info *ai = dev->ml_priv;
if (reset_card (dev, 1))
return -1;
@@ -2927,8 +2926,7 @@ int reset_airo_card( struct net_device *dev )
airo_print_err(dev->name, "MAC could not be enabled");
return -1;
}
- airo_print_info(dev->name, "MAC enabled %s",
- print_mac(mac, dev->dev_addr));
+ airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
/* Allocate the transmit buffers if needed */
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
@@ -2942,7 +2940,7 @@ int reset_airo_card( struct net_device *dev )
EXPORT_SYMBOL(reset_airo_card);
static void airo_send_event(struct net_device *dev) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
union iwreq_data wrqu;
StatusRid status_rid;
@@ -3019,7 +3017,7 @@ out:
static int airo_thread(void *data) {
struct net_device *dev = data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int locked;
set_freezable();
@@ -3134,7 +3132,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
struct net_device *dev = dev_id;
u16 status;
u16 fid;
- struct airo_info *apriv = dev->priv;
+ struct airo_info *apriv = dev->ml_priv;
u16 savedInterrupts = 0;
int handled = 0;
@@ -3369,7 +3367,6 @@ badrx:
skb->protocol = htons(ETH_P_802_2);
} else
skb->protocol = eth_type_trans(skb,dev);
- skb->dev->last_rx = jiffies;
skb->ip_summed = CHECKSUM_NONE;
netif_rx( skb );
@@ -3599,7 +3596,6 @@ badmic:
skb->ip_summed = CHECKSUM_NONE;
skb->protocol = eth_type_trans(skb, ai->dev);
- skb->dev->last_rx = jiffies;
netif_rx(skb);
}
badrx:
@@ -3611,7 +3607,7 @@ badrx:
}
}
-void mpi_receive_802_11 (struct airo_info *ai)
+static void mpi_receive_802_11(struct airo_info *ai)
{
RxFid rxd;
struct sk_buff *skb = NULL;
@@ -3693,7 +3689,6 @@ void mpi_receive_802_11 (struct airo_info *ai)
skb->pkt_type = PACKET_OTHERHOST;
skb->dev = ai->wifidev;
skb->protocol = htons(ETH_P_802_2);
- skb->dev->last_rx = jiffies;
skb->ip_summed = CHECKSUM_NONE;
netif_rx( skb );
badrx:
@@ -4604,7 +4599,7 @@ static int proc_status_open(struct inode *inode, struct file *file)
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *apriv = dev->priv;
+ struct airo_info *apriv = dev->ml_priv;
CapabilityRid cap_rid;
StatusRid status_rid;
u16 mode;
@@ -4687,7 +4682,7 @@ static int proc_stats_rid_open( struct inode *inode,
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *apriv = dev->priv;
+ struct airo_info *apriv = dev->ml_priv;
StatsRid stats;
int i, j;
__le32 *vals = stats.vals;
@@ -4750,7 +4745,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file)
struct proc_data *data = file->private_data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
char *line;
if ( !data->writelen ) return;
@@ -4962,7 +4957,7 @@ static int proc_config_open(struct inode *inode, struct file *file)
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int i;
__le16 mode;
@@ -5053,7 +5048,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file)
struct proc_data *data = (struct proc_data *)file->private_data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
SsidRid SSID_rid;
int i;
char *p = data->wbuffer;
@@ -5096,7 +5091,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
struct proc_data *data = (struct proc_data *)file->private_data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
APListRid APList_rid;
int i;
@@ -5191,7 +5186,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int i;
char key[16];
u16 index = 0;
@@ -5233,7 +5228,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file )
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
char *ptr;
WepKeyRid wkr;
__le16 lastindex;
@@ -5282,7 +5277,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file)
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int i;
char *ptr;
SsidRid SSID_rid;
@@ -5326,11 +5321,10 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int i;
char *ptr;
APListRid APList_rid;
- DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5354,8 +5348,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
// We end when we find a zero MAC
if ( !*(int*)APList_rid.ap[i] &&
!*(int*)&APList_rid.ap[i][2]) break;
- ptr += sprintf(ptr, "%s\n",
- print_mac(mac, APList_rid.ap[i]));
+ ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]);
}
if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
@@ -5368,13 +5361,12 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
struct proc_data *data;
struct proc_dir_entry *dp = PDE(inode);
struct net_device *dev = dp->data;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
char *ptr;
BSSListRid BSSList_rid;
int rc;
/* If doLoseSync is not 1, we won't do a Lose Sync */
int doLoseSync = -1;
- DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5411,8 +5403,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
we have to add a spin lock... */
rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
- ptr += sprintf(ptr, "%s %*s rssi = %d",
- print_mac(mac, BSSList_rid.bssid),
+ ptr += sprintf(ptr, "%pM %*s rssi = %d",
+ BSSList_rid.bssid,
(int)BSSList_rid.ssidLen,
BSSList_rid.ssid,
le16_to_cpu(BSSList_rid.dBm));
@@ -5447,7 +5439,7 @@ static int proc_close( struct inode *inode, struct file *file )
associated we will check every minute to see if anything has
changed. */
static void timer_func( struct net_device *dev ) {
- struct airo_info *apriv = dev->priv;
+ struct airo_info *apriv = dev->ml_priv;
/* We don't have a link so try changing the authtype */
readConfigRid(apriv, 0);
@@ -5518,7 +5510,7 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)
static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
Cmd cmd;
Resp rsp;
@@ -5550,7 +5542,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int airo_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
pci_power_t prev_state = pdev->current_state;
pci_set_power_state(pdev, PCI_D0);
@@ -5729,7 +5721,7 @@ static int airo_set_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int rc = -EINPROGRESS; /* Call commit handler */
/* If setting by frequency, convert to a channel */
@@ -5774,7 +5766,7 @@ static int airo_get_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
StatusRid status_rid; /* Card status info */
int ch;
@@ -5805,7 +5797,7 @@ static int airo_set_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
SsidRid SSID_rid; /* SSIDs */
/* Reload the list of current SSID */
@@ -5851,7 +5843,7 @@ static int airo_get_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
StatusRid status_rid; /* Card status info */
readStatusRid(local, &status_rid, 1);
@@ -5879,7 +5871,7 @@ static int airo_set_wap(struct net_device *dev,
struct sockaddr *awrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
Cmd cmd;
Resp rsp;
APListRid APList_rid;
@@ -5916,7 +5908,7 @@ static int airo_get_wap(struct net_device *dev,
struct sockaddr *awrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
StatusRid status_rid; /* Card status info */
readStatusRid(local, &status_rid, 1);
@@ -5937,7 +5929,7 @@ static int airo_set_nick(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
/* Check the size of the string */
if(dwrq->length > 16) {
@@ -5960,7 +5952,7 @@ static int airo_get_nick(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
strncpy(extra, local->config.nodeName, 16);
@@ -5979,7 +5971,7 @@ static int airo_set_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
CapabilityRid cap_rid; /* Card capability info */
u8 brate = 0;
int i;
@@ -6049,7 +6041,7 @@ static int airo_get_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
StatusRid status_rid; /* Card status info */
readStatusRid(local, &status_rid, 1);
@@ -6071,7 +6063,7 @@ static int airo_set_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int rthr = vwrq->value;
if(vwrq->disabled)
@@ -6095,7 +6087,7 @@ static int airo_get_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
vwrq->value = le16_to_cpu(local->config.rtsThres);
@@ -6114,7 +6106,7 @@ static int airo_set_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int fthr = vwrq->value;
if(vwrq->disabled)
@@ -6139,7 +6131,7 @@ static int airo_get_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
vwrq->value = le16_to_cpu(local->config.fragThresh);
@@ -6158,7 +6150,7 @@ static int airo_set_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int reset = 0;
readConfigRid(local, 1);
@@ -6221,7 +6213,7 @@ static int airo_get_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
/* If not managed, assume it's ad-hoc */
@@ -6258,7 +6250,7 @@ static int airo_set_encode(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
CapabilityRid cap_rid; /* Card capability info */
int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
__le16 currentAuthType = local->config.authType;
@@ -6345,7 +6337,7 @@ static int airo_get_encode(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
CapabilityRid cap_rid; /* Card capability info */
@@ -6393,7 +6385,7 @@ static int airo_set_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
CapabilityRid cap_rid; /* Card capability info */
@@ -6479,7 +6471,7 @@ static int airo_get_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
CapabilityRid cap_rid; /* Card capability info */
@@ -6542,7 +6534,7 @@ static int airo_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct iw_param *param = &wrqu->param;
__le16 currentAuthType = local->config.authType;
@@ -6610,7 +6602,7 @@ static int airo_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct iw_param *param = &wrqu->param;
__le16 currentAuthType = local->config.authType;
@@ -6659,7 +6651,7 @@ static int airo_set_txpow(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
CapabilityRid cap_rid; /* Card capability info */
int i;
int rc = -EINVAL;
@@ -6696,7 +6688,7 @@ static int airo_get_txpow(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
vwrq->value = le16_to_cpu(local->config.txPower);
@@ -6716,7 +6708,7 @@ static int airo_set_retry(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
int rc = -EINVAL;
if(vwrq->disabled) {
@@ -6754,7 +6746,7 @@ static int airo_get_retry(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
vwrq->disabled = 0; /* Can't be disabled */
@@ -6785,7 +6777,7 @@ static int airo_get_range(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct iw_range *range = (struct iw_range *) extra;
CapabilityRid cap_rid; /* Card capability info */
int i;
@@ -6910,7 +6902,7 @@ static int airo_set_power(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
if (vwrq->disabled) {
@@ -6967,7 +6959,7 @@ static int airo_get_power(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
__le16 mode;
readConfigRid(local, 1);
@@ -6998,7 +6990,7 @@ static int airo_set_sens(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
local->config.rssiThreshold =
@@ -7017,7 +7009,7 @@ static int airo_get_sens(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
readConfigRid(local, 1);
vwrq->value = le16_to_cpu(local->config.rssiThreshold);
@@ -7037,7 +7029,7 @@ static int airo_get_aplist(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
struct sockaddr *address = (struct sockaddr *) extra;
struct iw_quality qual[IW_MAX_AP];
BSSListRid BSSList;
@@ -7110,7 +7102,7 @@ static int airo_set_scan(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
Cmd cmd;
Resp rsp;
int wake = 0;
@@ -7156,7 +7148,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
char *end_buf,
BSSListRid *bss)
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
struct iw_event iwe; /* Temporary buffer */
__le16 capabilities;
char * current_val; /* For rates */
@@ -7274,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev,
if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
unsigned int num_null_ies = 0;
u16 length = sizeof (bss->extra.iep);
- struct ieee80211_info_element *info_element =
- (struct ieee80211_info_element *) &bss->extra.iep;
+ u8 *ie = (void *)&bss->extra.iep;
- while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
- if (sizeof(*info_element) + info_element->len > length) {
+ while ((length >= 2) && (num_null_ies < 2)) {
+ if (2 + ie[1] > length) {
/* Invalid element, don't continue parsing IE */
break;
}
- switch (info_element->id) {
- case MFIE_TYPE_SSID:
+ switch (ie[0]) {
+ case WLAN_EID_SSID:
/* Two zero-length SSID elements
* mean we're done parsing elements */
- if (!info_element->len)
+ if (!ie[1])
num_null_ies++;
break;
- case MFIE_TYPE_GENERIC:
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x01) {
+ case WLAN_EID_GENERIC:
+ if (ie[1] >= 4 &&
+ ie[2] == 0x00 &&
+ ie[3] == 0x50 &&
+ ie[4] == 0xf2 &&
+ ie[5] == 0x01) {
iwe.cmd = IWEVGENIE;
- iwe.u.data.length = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
+ /* 64 is an arbitrary cut-off */
+ iwe.u.data.length = min(ie[1] + 2,
+ 64);
current_ev = iwe_stream_add_point(
info, current_ev,
- end_buf, &iwe,
- (char *) info_element);
+ end_buf, &iwe, ie);
}
break;
- case MFIE_TYPE_RSN:
+ case WLAN_EID_RSN:
iwe.cmd = IWEVGENIE;
- iwe.u.data.length = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
+ /* 64 is an arbitrary cut-off */
+ iwe.u.data.length = min(ie[1] + 2, 64);
current_ev = iwe_stream_add_point(
info, current_ev, end_buf,
- &iwe, (char *) info_element);
+ &iwe, ie);
break;
default:
break;
}
- length -= sizeof(*info_element) + info_element->len;
- info_element =
- (struct ieee80211_info_element *)&info_element->
- data[info_element->len];
+ length -= 2 + ie[1];
+ ie += 2 + ie[1];
}
}
return current_ev;
@@ -7338,7 +7327,7 @@ static int airo_get_scan(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
BSSListElement *net;
int err = 0;
char *current_ev = extra;
@@ -7382,7 +7371,7 @@ static int airo_config_commit(struct net_device *dev,
void *zwrq, /* NULL */
char *extra) /* NULL */
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
if (!test_bit (FLAG_COMMIT, &local->flags))
return 0;
@@ -7527,7 +7516,7 @@ static const struct iw_handler_def airo_handler_def =
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
int rc = 0;
- struct airo_info *ai = (struct airo_info *)dev->priv;
+ struct airo_info *ai = dev->ml_priv;
if (ai->power.event)
return 0;
@@ -7655,7 +7644,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
{
- struct airo_info *local = dev->priv;
+ struct airo_info *local = dev->ml_priv;
if (!test_bit(JOB_WSTATS, &local->jobs)) {
/* Get stats out of the card if available */
@@ -7680,7 +7669,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
unsigned short ridcode;
unsigned char *iobuf;
int len;
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO;
@@ -7746,7 +7735,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
*/
static int writerids(struct net_device *dev, aironet_ioctl *comp) {
- struct airo_info *ai = dev->priv;
+ struct airo_info *ai = dev->ml_priv;
int ridcode;
int enabled;
static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
@@ -7869,41 +7858,41 @@ static int flashcard(struct net_device *dev, aironet_ioctl *comp) {
switch(comp->command)
{
case AIROFLSHRST:
- return cmdreset((struct airo_info *)dev->priv);
+ return cmdreset((struct airo_info *)dev->ml_priv);
case AIROFLSHSTFL:
- if (!((struct airo_info *)dev->priv)->flash &&
- (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL)
+ if (!AIRO_FLASH(dev) &&
+ (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL)
return -ENOMEM;
- return setflashmode((struct airo_info *)dev->priv);
+ return setflashmode((struct airo_info *)dev->ml_priv);
case AIROFLSHGCHR: /* Get char from aux */
if(comp->len != sizeof(int))
return -EINVAL;
if (copy_from_user(&z,comp->data,comp->len))
return -EFAULT;
- return flashgchar((struct airo_info *)dev->priv,z,8000);
+ return flashgchar((struct airo_info *)dev->ml_priv, z, 8000);
case AIROFLSHPCHR: /* Send char to card. */
if(comp->len != sizeof(int))
return -EINVAL;
if (copy_from_user(&z,comp->data,comp->len))
return -EFAULT;
- return flashpchar((struct airo_info *)dev->priv,z,8000);
+ return flashpchar((struct airo_info *)dev->ml_priv, z, 8000);
case AIROFLPUTBUF: /* Send 32k to card */
- if (!((struct airo_info *)dev->priv)->flash)
+ if (!AIRO_FLASH(dev))
return -ENOMEM;
if(comp->len > FLASHSIZE)
return -EINVAL;
- if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len))
+ if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len))
return -EFAULT;
- flashputbuf((struct airo_info *)dev->priv);
+ flashputbuf((struct airo_info *)dev->ml_priv);
return 0;
case AIRORESTART:
- if(flashrestart((struct airo_info *)dev->priv,dev))
+ if (flashrestart((struct airo_info *)dev->ml_priv, dev))
return -EIO;
return 0;
}
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index dec5e874a54..bfca15da6f0 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1467,19 +1467,17 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
else if (hw_dst_addr[1] == 0x40)
printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
while (dmi)
- { if (dmi->dmi_addrlen == 6)
- {
- DECLARE_MAC_BUF(mac);
+ {
+ if (dmi->dmi_addrlen == 6) {
if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
- printk(KERN_ERR "%s mcl %s\n",
- dev->name, print_mac(mac, dmi->dmi_addr));
+ printk(KERN_ERR "%s mcl %pM\n",
+ dev->name, dmi->dmi_addr);
for (i = 0; i < 6; i++)
if (dmi->dmi_addr[i] != hw_dst_addr[i])
break;
if (i == 6)
break;
- }
- else
+ } else
printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name);
dmi = dmi->next;
}
@@ -1512,18 +1510,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
{
char immedDestAddress[6];
char immedSrcAddress[6];
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
- DECLARE_MAC_BUF(mac4);
memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
- printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n",
- dev->name, print_mac(mac, skbtmp),
- print_mac(mac2, &skbtmp[6]),
- print_mac(mac3, immedDestAddress),
- print_mac(mac4, immedSrcAddress));
+ printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n",
+ dev->name, skbtmp,
+ &skbtmp[6],
+ immedDestAddress,
+ immedSrcAddress);
}
skb->protocol = eth_type_trans(skb, dev);
IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
@@ -1535,7 +1529,6 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol);
}
netif_rx(skb);
- dev->last_rx = jiffies;
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index 53ea439aff4..183ffc8e62c 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -507,11 +507,15 @@ enum ath5k_tx_queue_id {
#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */
#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */
#define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */
-#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */
-#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/
-#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */
-#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */
-#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/
+#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */
+#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */
+#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */
+#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/
/*
* A struct to hold tx queue's parameters
@@ -817,13 +821,6 @@ struct ath5k_athchan_2ghz {
return (false); \
} while (0)
-enum ath5k_ant_setting {
- AR5K_ANT_VARIABLE = 0, /* variable by programming */
- AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
- AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
- AR5K_ANT_MAX = 3,
-};
-
/*
* Hardware interrupt abstraction
*/
@@ -853,7 +850,7 @@ enum ath5k_ant_setting {
* checked. We should do this with ath5k_hw_update_mib_counters() but
* it seems we should also then do some noise immunity work.
* @AR5K_INT_RXPHY: RX PHY Error
- * @AR5K_INT_RXKCM: ??
+ * @AR5K_INT_RXKCM: RX Key cache miss
* @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
* beacon that must be handled in software. The alternative is if you
* have VEOL support, in that case you let the hardware deal with things.
@@ -869,7 +866,7 @@ enum ath5k_ant_setting {
* @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
* errors. These types of errors we can enable seem to be of type
* AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
- * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER
+ * @AR5K_INT_GLOBAL: Used to clear and set the IER
* @AR5K_INT_NOCARD: signals the card has been removed
* @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
* bit value
@@ -881,36 +878,61 @@ enum ath5k_ant_setting {
* MACs.
*/
enum ath5k_int {
- AR5K_INT_RX = 0x00000001, /* Not common */
+ AR5K_INT_RXOK = 0x00000001,
AR5K_INT_RXDESC = 0x00000002,
+ AR5K_INT_RXERR = 0x00000004,
AR5K_INT_RXNOFRM = 0x00000008,
AR5K_INT_RXEOL = 0x00000010,
AR5K_INT_RXORN = 0x00000020,
- AR5K_INT_TX = 0x00000040, /* Not common */
+ AR5K_INT_TXOK = 0x00000040,
AR5K_INT_TXDESC = 0x00000080,
+ AR5K_INT_TXERR = 0x00000100,
+ AR5K_INT_TXNOFRM = 0x00000200,
+ AR5K_INT_TXEOL = 0x00000400,
AR5K_INT_TXURN = 0x00000800,
AR5K_INT_MIB = 0x00001000,
+ AR5K_INT_SWI = 0x00002000,
AR5K_INT_RXPHY = 0x00004000,
AR5K_INT_RXKCM = 0x00008000,
AR5K_INT_SWBA = 0x00010000,
+ AR5K_INT_BRSSI = 0x00020000,
AR5K_INT_BMISS = 0x00040000,
- AR5K_INT_BNR = 0x00100000, /* Not common */
- AR5K_INT_GPIO = 0x01000000,
- AR5K_INT_FATAL = 0x40000000, /* Not common */
- AR5K_INT_GLOBAL = 0x80000000,
-
- AR5K_INT_COMMON = AR5K_INT_RXNOFRM
- | AR5K_INT_RXDESC
- | AR5K_INT_RXEOL
- | AR5K_INT_RXORN
- | AR5K_INT_TXURN
- | AR5K_INT_TXDESC
- | AR5K_INT_MIB
- | AR5K_INT_RXPHY
- | AR5K_INT_RXKCM
- | AR5K_INT_SWBA
- | AR5K_INT_BMISS
- | AR5K_INT_GPIO,
+ AR5K_INT_FATAL = 0x00080000, /* Non common */
+ AR5K_INT_BNR = 0x00100000, /* Non common */
+ AR5K_INT_TIM = 0x00200000, /* Non common */
+ AR5K_INT_DTIM = 0x00400000, /* Non common */
+ AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */
+ AR5K_INT_GPIO = 0x01000000,
+ AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */
+ AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */
+ AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */
+ AR5K_INT_QCBRORN = 0x10000000, /* Non common */
+ AR5K_INT_QCBRURN = 0x20000000, /* Non common */
+ AR5K_INT_QTRIG = 0x40000000, /* Non common */
+ AR5K_INT_GLOBAL = 0x80000000,
+
+ AR5K_INT_COMMON = AR5K_INT_RXOK
+ | AR5K_INT_RXDESC
+ | AR5K_INT_RXERR
+ | AR5K_INT_RXNOFRM
+ | AR5K_INT_RXEOL
+ | AR5K_INT_RXORN
+ | AR5K_INT_TXOK
+ | AR5K_INT_TXDESC
+ | AR5K_INT_TXERR
+ | AR5K_INT_TXNOFRM
+ | AR5K_INT_TXEOL
+ | AR5K_INT_TXURN
+ | AR5K_INT_MIB
+ | AR5K_INT_SWI
+ | AR5K_INT_RXPHY
+ | AR5K_INT_RXKCM
+ | AR5K_INT_SWBA
+ | AR5K_INT_BRSSI
+ | AR5K_INT_BMISS
+ | AR5K_INT_GPIO
+ | AR5K_INT_GLOBAL,
+
AR5K_INT_NOCARD = 0xffffffff
};
@@ -1030,6 +1052,7 @@ struct ath5k_hw {
bool ah_calibration;
bool ah_running;
bool ah_single_chip;
+ bool ah_combined_mic;
enum ath5k_rfgain ah_rf_gain;
u32 ah_mac_srev;
@@ -1064,10 +1087,11 @@ struct ath5k_hw {
u8 ah_sta_id[ETH_ALEN];
- /* Current BSSID we are trying to assoc to / creating.
+ /* Current BSSID we are trying to assoc to / create.
* This is passed by mac80211 on config_interface() and cached here for
* use in resets */
u8 ah_bssid[ETH_ALEN];
+ u8 ah_bssid_mask[ETH_ALEN];
u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
@@ -1081,6 +1105,11 @@ struct ath5k_hw {
u32 ah_txq_imr_txurn;
u32 ah_txq_imr_txdesc;
u32 ah_txq_imr_txeol;
+ u32 ah_txq_imr_cbrorn;
+ u32 ah_txq_imr_cbrurn;
+ u32 ah_txq_imr_qtrig;
+ u32 ah_txq_imr_nofrm;
+ u32 ah_txq_isr;
u32 *ah_rf_banks;
size_t ah_rf_banks_size;
struct ath5k_gain ah_gain;
@@ -1321,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
return retval;
}
+static inline int ath5k_pad_size(int hdrlen)
+{
+ return (hdrlen < 24) ? 0 : hdrlen & 3;
+}
+
#endif
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c
index 51d569883cd..dea378f7673 100644
--- a/drivers/net/wireless/ath5k/attach.c
+++ b/drivers/net/wireless/ath5k/attach.c
@@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
{
struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev;
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] = {};
int ret;
u32 srev;
@@ -317,15 +317,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
- /* Set MAC address */
- ret = ath5k_eeprom_read_mac(ah, mac);
- if (ret) {
- ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
- sc->pdev->device);
- goto err_free;
+ if (srev >= AR5K_SREV_AR2414) {
+ ah->ah_combined_mic = true;
+ AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
+ AR5K_MISC_MODE_COMBINED_MIC);
}
+ /* MAC address is cleared until add_interface */
ath5k_hw_set_lladdr(ah, mac);
+
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
memset(ah->ah_bssid, 0xff, ETH_ALEN);
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index cfd4d052d66..4af2607deec 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -60,6 +60,9 @@
#include "debug.h"
static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/******************\
@@ -197,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev);
#endif /* CONFIG_PM */
static struct pci_driver ath5k_pci_driver = {
- .name = "ath5k_pci",
+ .name = KBUILD_MODNAME,
.id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe,
.remove = __devexit_p(ath5k_pci_remove),
@@ -219,8 +222,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
static void ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
-static int ath5k_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf);
+static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
static int ath5k_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf);
@@ -238,8 +240,12 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
-static int ath5k_beacon_update(struct ieee80211_hw *hw,
+static int ath5k_beacon_update(struct ath5k_softc *sc,
struct sk_buff *skb);
+static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes);
static struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -256,6 +262,7 @@ static struct ieee80211_ops ath5k_hw_ops = {
.get_tx_stats = ath5k_get_tx_stats,
.get_tsf = ath5k_get_tsf,
.reset_tsf = ath5k_reset_tsf,
+ .bss_info_changed = ath5k_bss_info_changed,
};
/*
@@ -543,8 +550,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* set up multi-rate retry capabilities */
if (sc->ah->ah_version == AR5K_AR5212) {
- hw->max_altrates = 3;
- hw->max_altrate_tries = 11;
+ hw->max_rates = 4;
+ hw->max_rate_tries = 11;
}
/* Finish private driver data initialization */
@@ -706,7 +713,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] = {};
int ret;
ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
@@ -776,7 +783,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
- ath5k_hw_get_lladdr(ah, mac);
+ ret = ath5k_eeprom_read_mac(ah, mac);
+ if (ret) {
+ ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+ sc->pdev->device);
+ goto err_queues;
+ }
+
SET_IEEE80211_PERM_ADDR(hw, mac);
/* All MAC address bits matter for ACKs */
memset(sc->bssidmask, 0xff, ETH_ALEN);
@@ -1183,7 +1196,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
(sc->power_level * 2),
ieee80211_get_tx_rate(sc->hw, info)->hw_value,
- info->control.retry_limit, keyidx, 0, flags, 0, 0);
+ info->control.rates[0].count, keyidx, 0, flags, 0, 0);
if (ret)
goto err_unmap;
@@ -1195,7 +1208,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
break;
mrr_rate[i] = rate->hw_value;
- mrr_tries[i] = info->control.retries[i].limit;
+ mrr_tries[i] = info->control.rates[i + 1].count;
}
ah->ah_setup_mrr_tx_desc(ah, ds,
@@ -1655,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
struct ath5k_desc *ds;
int ret;
int hdrlen;
- int pad;
+ int padsize;
spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) {
@@ -1740,16 +1753,19 @@ accept:
skb_put(skb, rs.rs_datalen);
- /*
- * the hardware adds a padding to 4 byte boundaries between
- * the header and the payload data if the header length is
- * not multiples of 4 - remove it
- */
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - hdrlen % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- if (hdrlen & 3) {
- pad = hdrlen % 4;
- memmove(skb->data + pad, skb->data, hdrlen);
- skb_pull(skb, pad);
+ padsize = ath5k_pad_size(hdrlen);
+ if (padsize) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
}
/*
@@ -1780,7 +1796,17 @@ accept:
rxs.noise = sc->ah->ah_noise_floor;
rxs.signal = rxs.noise + rs.rs_rssi;
- rxs.qual = rs.rs_rssi * 100 / 64;
+
+ /* An rssi of 35 indicates you should be able use
+ * 54 Mbps reliably. A more elaborate scheme can be used
+ * here but it requires a map of SNR/throughput for each
+ * possible mode used */
+ rxs.qual = rs.rs_rssi * 100 / 35;
+
+ /* rssi can be more than 35 though, anything above that
+ * should be considered at 100% */
+ if (rxs.qual > 100)
+ rxs.qual = 100;
rxs.antenna = rs.rs_antenna;
rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
@@ -1841,30 +1867,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
PCI_DMA_TODEVICE);
- memset(&info->status, 0, sizeof(info->status));
- info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
- ts.ts_rate[ts.ts_final_idx]);
- info->status.retry_count = ts.ts_longretry;
-
+ ieee80211_tx_info_clear_status(info);
for (i = 0; i < 4; i++) {
- struct ieee80211_tx_altrate *r =
- &info->status.retries[i];
+ struct ieee80211_tx_rate *r =
+ &info->status.rates[i];
if (ts.ts_rate[i]) {
- r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
- r->limit = ts.ts_retry[i];
+ r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
+ r->count = ts.ts_retry[i];
} else {
- r->rate_idx = -1;
- r->limit = 0;
+ r->idx = -1;
+ r->count = 0;
}
}
- info->status.excessive_retries = 0;
+ /* count the successful attempt as well */
+ info->status.rates[ts.ts_final_idx].count++;
+
if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++;
- if (ts.ts_status & AR5K_TXERR_XRETRY)
- info->status.excessive_retries = 1;
- else if (ts.ts_status & AR5K_TXERR_FILT)
+ if (ts.ts_status & AR5K_TXERR_FILT)
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
@@ -2138,8 +2160,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
*
* In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
* interrupts to detect TSF updates only.
- *
- * AP mode is missing.
*/
static void
ath5k_beacon_config(struct ath5k_softc *sc)
@@ -2152,7 +2172,9 @@ ath5k_beacon_config(struct ath5k_softc *sc)
if (sc->opmode == NL80211_IFTYPE_STATION) {
sc->imask |= AR5K_INT_BMISS;
- } else if (sc->opmode == NL80211_IFTYPE_ADHOC) {
+ } else if (sc->opmode == NL80211_IFTYPE_ADHOC ||
+ sc->opmode == NL80211_IFTYPE_MESH_POINT ||
+ sc->opmode == NL80211_IFTYPE_AP) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2164,13 +2186,15 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
- if (ath5k_hw_hasveol(ah)) {
- spin_lock(&sc->block);
- ath5k_beacon_send(sc);
- spin_unlock(&sc->block);
- }
+ if (sc->opmode == NL80211_IFTYPE_ADHOC) {
+ if (ath5k_hw_hasveol(ah)) {
+ spin_lock(&sc->block);
+ ath5k_beacon_send(sc);
+ spin_unlock(&sc->block);
+ }
+ } else
+ ath5k_beacon_update_timers(sc, -1);
}
- /* TODO else AP */
ath5k_hw_set_imr(ah, sc->imask);
}
@@ -2210,9 +2234,9 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume)
*/
sc->curchan = sc->hw->conf.channel;
sc->curband = &sc->sbands[sc->curchan->band];
- sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
- AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL |
- AR5K_INT_MIB;
+ sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
+ AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
+ AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
ret = ath5k_reset(sc, false, false);
if (ret)
goto done;
@@ -2404,9 +2428,10 @@ ath5k_intr(int irq, void *dev_id)
/* bump tx trigger level */
ath5k_hw_update_tx_triglevel(ah, true);
}
- if (status & AR5K_INT_RX)
+ if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
tasklet_schedule(&sc->rxtq);
- if (status & AR5K_INT_TX)
+ if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+ | AR5K_INT_TXERR | AR5K_INT_TXEOL))
tasklet_schedule(&sc->txtq);
if (status & AR5K_INT_BMISS) {
}
@@ -2522,8 +2547,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
led->led_dev.brightness_set = ath5k_led_brightness_set;
err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
- if (err)
- {
+ if (err) {
ATH5K_WARN(sc, "could not register LED %s\n", name);
led->sc = NULL;
}
@@ -2602,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ath5k_buf *bf;
unsigned long flags;
int hdrlen;
- int pad;
+ int padsize;
ath5k_debug_dump_skb(sc, skb, "TX ", 1);
@@ -2614,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* if this is not the case we add the padding after the header
*/
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- if (hdrlen & 3) {
- pad = hdrlen % 4;
- if (skb_headroom(skb) < pad) {
+ padsize = ath5k_pad_size(hdrlen);
+ if (padsize) {
+
+ if (skb_headroom(skb) < padsize) {
ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
- " headroom to pad %d\n", hdrlen, pad);
+ " headroom to pad %d\n", hdrlen, padsize);
return -1;
}
- skb_push(skb, pad);
- memmove(skb->data, skb->data+pad, hdrlen);
+ skb_push(skb, padsize);
+ memmove(skb->data, skb->data+padsize, hdrlen);
}
spin_lock_irqsave(&sc->txbuflock, flags);
@@ -2741,8 +2766,10 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
sc->vif = conf->vif;
switch (conf->type) {
+ case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_MONITOR:
sc->opmode = conf->type;
break;
@@ -2754,6 +2781,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
/* Set to a reasonable value. Note that this will
* be set to mac80211's value at ath5k_config(). */
sc->bintval = 1000;
+ ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
ret = 0;
end:
@@ -2766,11 +2794,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ath5k_softc *sc = hw->priv;
+ u8 mac[ETH_ALEN] = {};
mutex_lock(&sc->lock);
if (sc->vif != conf->vif)
goto end;
+ ath5k_hw_set_lladdr(sc->ah, mac);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@@ -2780,10 +2810,10 @@ end:
* TODO: Phy disable/diversity etc
*/
static int
-ath5k_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf)
+ath5k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath5k_softc *sc = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
sc->bintval = conf->beacon_int;
sc->power_level = conf->power_level;
@@ -2804,7 +2834,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ret = -EIO;
goto unlock;
}
- if (conf->bssid) {
+ if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
/* Cache for later use during resets */
memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN);
/* XXX: assoc id is set to 0 for now, mac80211 doesn't have
@@ -2812,18 +2842,17 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
mmiowb();
}
-
if (conf->changed & IEEE80211_IFCC_BEACON &&
- vif->type == NL80211_IFTYPE_ADHOC) {
+ (vif->type == NL80211_IFTYPE_ADHOC ||
+ vif->type == NL80211_IFTYPE_MESH_POINT ||
+ vif->type == NL80211_IFTYPE_AP)) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon) {
ret = -ENOMEM;
goto unlock;
}
- /* call old handler for now */
- ath5k_beacon_update(hw, beacon);
+ ath5k_beacon_update(sc, beacon);
}
-
mutex_unlock(&sc->lock);
return ath5k_reset_wake(sc);
@@ -2883,9 +2912,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
if (*new_flags & FIF_PROMISC_IN_BSS) {
rfilt |= AR5K_RX_FILTER_PROM;
__set_bit(ATH_STAT_PROMISC, sc->status);
- }
- else
+ } else {
__clear_bit(ATH_STAT_PROMISC, sc->status);
+ }
}
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
@@ -2942,13 +2971,16 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
sc->opmode != NL80211_IFTYPE_MESH_POINT &&
test_bit(ATH_STAT_PROMISC, sc->status))
rfilt |= AR5K_RX_FILTER_PROM;
- if (sc->opmode == NL80211_IFTYPE_STATION ||
- sc->opmode == NL80211_IFTYPE_ADHOC) {
+ if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
+ sc->opmode == NL80211_IFTYPE_ADHOC ||
+ sc->opmode == NL80211_IFTYPE_AP)
rfilt |= AR5K_RX_FILTER_BEACON;
- }
+ if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
+ rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
+ AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
/* Set filters */
- ath5k_hw_set_rx_filter(ah,rfilt);
+ ath5k_hw_set_rx_filter(ah, rfilt);
/* Set multicast bits */
ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
@@ -2965,12 +2997,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ath5k_softc *sc = hw->priv;
int ret = 0;
- switch(key->alg) {
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ switch (key->alg) {
case ALG_WEP:
- /* XXX: fix hardware encryption, its not working. For now
- * allow software encryption */
- /* break; */
case ALG_TKIP:
+ break;
case ALG_CCMP:
return -EOPNOTSUPP;
default:
@@ -2989,6 +3022,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
__set_bit(key->keyidx, sc->keymap);
key->hw_key_idx = key->keyidx;
+ key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
+ IEEE80211_KEY_FLAG_GENERATE_MMIC);
break;
case DISABLE_KEY:
ath5k_hw_reset_key(sc->ah, key->keyidx);
@@ -3055,19 +3090,13 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
}
static int
-ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb)
{
- struct ath5k_softc *sc = hw->priv;
unsigned long flags;
int ret;
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
- if (sc->opmode != NL80211_IFTYPE_ADHOC) {
- ret = -EIO;
- goto end;
- }
-
spin_lock_irqsave(&sc->block, flags);
ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb;
@@ -3080,7 +3109,34 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
mmiowb();
}
-end:
return ret;
}
+static void
+set_beacon_filter(struct ieee80211_hw *hw, bool enable)
+{
+ struct ath5k_softc *sc = hw->priv;
+ struct ath5k_hw *ah = sc->ah;
+ u32 rfilt;
+ rfilt = ath5k_hw_get_rx_filter(ah);
+ if (enable)
+ rfilt |= AR5K_RX_FILTER_BEACON;
+ else
+ rfilt &= ~AR5K_RX_FILTER_BEACON;
+ ath5k_hw_set_rx_filter(ah, rfilt);
+ sc->filter_flags = rfilt;
+}
+static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changes)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (changes & BSS_CHANGED_ASSOC) {
+ mutex_lock(&sc->lock);
+ sc->assoc = bss_conf->assoc;
+ if (sc->opmode == NL80211_IFTYPE_STATION)
+ set_beacon_filter(hw, sc->assoc);
+ mutex_unlock(&sc->lock);
+ }
+}
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 06d1054ca94..facc60ddada 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -179,6 +179,7 @@ struct ath5k_softc {
struct timer_list calib_tim; /* calibration timer */
int power_level; /* Requested tx power in dbm */
+ bool assoc; /* assocate state */
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
index 19980cbd5d5..ccaeb5c219d 100644
--- a/drivers/net/wireless/ath5k/debug.c
+++ b/drivers/net/wireless/ath5k/debug.c
@@ -417,19 +417,19 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath5k_global_debugfs);
- sc->debug.debugfs_debug = debugfs_create_file("debug", 0666,
+ sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
sc->debug.debugfs_phydir, sc, &fops_debug);
- sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
+ sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
sc->debug.debugfs_phydir, sc, &fops_registers);
- sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
+ sc->debug.debugfs_tsf = debugfs_create_file("tsf", S_IWUSR | S_IRUGO,
sc->debug.debugfs_phydir, sc, &fops_tsf);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
+ sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
sc->debug.debugfs_phydir, sc, &fops_beacon);
- sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
+ sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
sc->debug.debugfs_phydir, sc, &fops_reset);
}
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c
index 5e362a7a362..b40a9287a39 100644
--- a/drivers/net/wireless/ath5k/desc.c
+++ b/drivers/net/wireless/ath5k/desc.c
@@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
/* Verify and set frame length */
/* remove padding we might have added before */
- frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+ frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
@@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/* Verify and set frame length */
/* remove padding we might have added before */
- frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+ frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
index 7adceb2c7fa..7e2b1a67e5d 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -472,9 +472,6 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
*
* NOTE: We use read-and-clear register, so after this function is called ISR
* is zeroed.
- *
- * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all
- * plus it can be misleading (one might thing that we save interrupts this way)
*/
int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
{
@@ -494,11 +491,16 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
}
} else {
/*
- * Read interrupt status from the Read-And-Clear
- * shadow register.
+ * Read interrupt status from Interrupt
+ * Status Register shadow copy (Read And Clear)
+ *
* Note: PISR/SISR Not available on 5210
*/
data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+ if (unlikely(data == AR5K_INT_NOCARD)) {
+ *interrupt_mask = data;
+ return -ENODEV;
+ }
}
/*
@@ -506,17 +508,9 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
*/
*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
- if (unlikely(data == AR5K_INT_NOCARD))
- return -ENODEV;
-
- if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
- *interrupt_mask |= AR5K_INT_RX;
-
- if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
- | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
- *interrupt_mask |= AR5K_INT_TX;
-
if (ah->ah_version != AR5K_AR5210) {
+ u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
+
/*HIU = Host Interface Unit (PCI etc)*/
if (unlikely(data & (AR5K_ISR_HIUERR)))
*interrupt_mask |= AR5K_INT_FATAL;
@@ -524,24 +518,93 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
/*Beacon Not Ready*/
if (unlikely(data & (AR5K_ISR_BNR)))
*interrupt_mask |= AR5K_INT_BNR;
- }
- /*
- * XXX: BMISS interrupts may occur after association.
- * I found this on 5210 code but it needs testing. If this is
- * true we should disable them before assoc and re-enable them
- * after a successfull assoc + some jiffies.
- */
-#if 0
- interrupt_mask &= ~AR5K_INT_BMISS;
-#endif
+ if (unlikely(sisr2 & (AR5K_SISR2_SSERR |
+ AR5K_SISR2_DPERR |
+ AR5K_SISR2_MCABT)))
+ *interrupt_mask |= AR5K_INT_FATAL;
+
+ if (data & AR5K_ISR_TIM)
+ *interrupt_mask |= AR5K_INT_TIM;
+
+ if (data & AR5K_ISR_BCNMISC) {
+ if (sisr2 & AR5K_SISR2_TIM)
+ *interrupt_mask |= AR5K_INT_TIM;
+ if (sisr2 & AR5K_SISR2_DTIM)
+ *interrupt_mask |= AR5K_INT_DTIM;
+ if (sisr2 & AR5K_SISR2_DTIM_SYNC)
+ *interrupt_mask |= AR5K_INT_DTIM_SYNC;
+ if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
+ *interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
+ if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
+ *interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
+ }
+
+ if (data & AR5K_ISR_RXDOPPLER)
+ *interrupt_mask |= AR5K_INT_RX_DOPPLER;
+ if (data & AR5K_ISR_QCBRORN) {
+ *interrupt_mask |= AR5K_INT_QCBRORN;
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+ AR5K_SISR3_QCBRORN);
+ }
+ if (data & AR5K_ISR_QCBRURN) {
+ *interrupt_mask |= AR5K_INT_QCBRURN;
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+ AR5K_SISR3_QCBRURN);
+ }
+ if (data & AR5K_ISR_QTRIG) {
+ *interrupt_mask |= AR5K_INT_QTRIG;
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
+ AR5K_SISR4_QTRIG);
+ }
+
+ if (data & AR5K_ISR_TXOK)
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+ AR5K_SISR0_QCU_TXOK);
+
+ if (data & AR5K_ISR_TXDESC)
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+ AR5K_SISR0_QCU_TXDESC);
+
+ if (data & AR5K_ISR_TXERR)
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+ AR5K_SISR1_QCU_TXERR);
+
+ if (data & AR5K_ISR_TXEOL)
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+ AR5K_SISR1_QCU_TXEOL);
+
+ if (data & AR5K_ISR_TXURN)
+ ah->ah_txq_isr |= AR5K_REG_MS(
+ ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
+ AR5K_SISR2_QCU_TXURN);
+ } else {
+ if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
+ | AR5K_ISR_HIUERR | AR5K_ISR_DPERR)))
+ *interrupt_mask |= AR5K_INT_FATAL;
+
+ /*
+ * XXX: BMISS interrupts may occur after association.
+ * I found this on 5210 code but it needs testing. If this is
+ * true we should disable them before assoc and re-enable them
+ * after a successfull assoc + some jiffies.
+ interrupt_mask &= ~AR5K_INT_BMISS;
+ */
+ }
/*
* In case we didn't handle anything,
* print the register value.
*/
if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
- ATH5K_PRINTF("0x%08x\n", data);
+ ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr);
return 0;
}
@@ -560,14 +623,17 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
{
enum ath5k_int old_mask, int_mask;
+ old_mask = ah->ah_imr;
+
/*
* Disable card interrupts to prevent any race conditions
- * (they will be re-enabled afterwards).
+ * (they will be re-enabled afterwards if AR5K_INT GLOBAL
+ * is set again on the new mask).
*/
- ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
- ath5k_hw_reg_read(ah, AR5K_IER);
-
- old_mask = ah->ah_imr;
+ if (old_mask & AR5K_INT_GLOBAL) {
+ ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+ ath5k_hw_reg_read(ah, AR5K_IER);
+ }
/*
* Add additional, chipset-dependent interrupt mask flags
@@ -575,30 +641,64 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
*/
int_mask = new_mask & AR5K_INT_COMMON;
- if (new_mask & AR5K_INT_RX)
- int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
- AR5K_IMR_RXDESC;
-
- if (new_mask & AR5K_INT_TX)
- int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
- AR5K_IMR_TXURN;
-
if (ah->ah_version != AR5K_AR5210) {
+ /* Preserve per queue TXURN interrupt mask */
+ u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
+ & AR5K_SIMR2_QCU_TXURN;
+
if (new_mask & AR5K_INT_FATAL) {
int_mask |= AR5K_IMR_HIUERR;
- AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
- AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
+ simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
+ | AR5K_SIMR2_DPERR);
}
+
+ /*Beacon Not Ready*/
+ if (new_mask & AR5K_INT_BNR)
+ int_mask |= AR5K_INT_BNR;
+
+ if (new_mask & AR5K_INT_TIM)
+ int_mask |= AR5K_IMR_TIM;
+
+ if (new_mask & AR5K_INT_TIM)
+ simr2 |= AR5K_SISR2_TIM;
+ if (new_mask & AR5K_INT_DTIM)
+ simr2 |= AR5K_SISR2_DTIM;
+ if (new_mask & AR5K_INT_DTIM_SYNC)
+ simr2 |= AR5K_SISR2_DTIM_SYNC;
+ if (new_mask & AR5K_INT_BCN_TIMEOUT)
+ simr2 |= AR5K_SISR2_BCN_TIMEOUT;
+ if (new_mask & AR5K_INT_CAB_TIMEOUT)
+ simr2 |= AR5K_SISR2_CAB_TIMEOUT;
+
+ if (new_mask & AR5K_INT_RX_DOPPLER)
+ int_mask |= AR5K_IMR_RXDOPPLER;
+
+ /* Note: Per queue interrupt masks
+ * are set via reset_tx_queue (qcu.c) */
+ ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+ ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
+
+ } else {
+ if (new_mask & AR5K_INT_FATAL)
+ int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
+ | AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
+
+ ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
}
- ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+ /* If RXNOFRM interrupt is masked disable it
+ * by setting AR5K_RXNOFRM to zero */
+ if (!(new_mask & AR5K_INT_RXNOFRM))
+ ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
/* Store new interrupt mask */
ah->ah_imr = new_mask;
- /* ..re-enable interrupts */
- ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
- ath5k_hw_reg_read(ah, AR5K_IER);
+ /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
+ if (new_mask & AR5K_INT_GLOBAL) {
+ ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+ ath5k_hw_reg_read(ah, AR5K_IER);
+ }
return old_mask;
}
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
index a883839b6a9..1cb7edfae62 100644
--- a/drivers/net/wireless/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
/*
* Translate binary channel representation in EEPROM to frequency
*/
-static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
- unsigned int mode)
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+ unsigned int mode)
{
u16 val;
@@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
return bin;
if (mode == AR5K_EEPROM_MODE_11A) {
- if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
val = (5 * bin) + 4800;
else
val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
(bin * 10) + 5100;
} else {
- if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+ if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
val = bin + 2300;
else
val = bin + 2400;
@@ -88,6 +89,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
}
/*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ int ret;
+ u16 val;
+
+ /* Initial TX thermal adjustment values */
+ ee->ee_tx_clip = 4;
+ ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+ ee->ee_gain_select = 1;
+
+ /*
+ * Read values from EEPROM and store them in the capability structure
+ */
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+ /* Return if we have an old EEPROM */
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+ return 0;
+
+#ifdef notyet
+ /*
+ * Validate the checksum of the EEPROM date. There are some
+ * devices with invalid EEPROMs.
+ */
+ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+ cksum ^= val;
+ }
+ if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+ return -EIO;
+ }
+#endif
+
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+ ee_ant_gain);
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+ }
+
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+ ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+ AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+ ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+ ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+ }
+
+ return 0;
+}
+
+
+/*
* Read antenna infos from eeprom
*/
static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
@@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
AR5K_EEPROM_READ(o++, val);
ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
- ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
+ ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f;
ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
AR5K_EEPROM_READ(o++, val);
@@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
u16 val;
int ret;
+ ee->ee_n_piers[mode] = 0;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ ee->ee_ob[mode][3] = (val >> 5) & 0x7;
+ ee->ee_db[mode][3] = (val >> 2) & 0x7;
+ ee->ee_ob[mode][2] = (val << 1) & 0x7;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
+ ee->ee_db[mode][2] = (val >> 12) & 0x7;
+ ee->ee_ob[mode][1] = (val >> 9) & 0x7;
+ ee->ee_db[mode][1] = (val >> 6) & 0x7;
+ ee->ee_ob[mode][0] = (val >> 3) & 0x7;
+ ee->ee_db[mode][0] = val & 0x7;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ case AR5K_EEPROM_MODE_11B:
+ ee->ee_ob[mode][1] = (val >> 4) & 0x7;
+ ee->ee_db[mode][1] = val & 0x7;
+ break;
+ }
+
AR5K_EEPROM_READ(o++, val);
ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
ee->ee_thr_62[mode] = val & 0xff;
@@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
AR5K_EEPROM_READ(o++, val);
ee->ee_i_gain[mode] |= (val << 3) & 0x38;
- if (mode == AR5K_EEPROM_MODE_11G)
+ if (mode == AR5K_EEPROM_MODE_11G) {
ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+ ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+ }
}
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
@@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
- mode == AR5K_EEPROM_MODE_11G)
- ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+ goto done;
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+ break;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_margin_tx_rx[mode] = val & 0x3f;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ AR5K_EEPROM_READ(o++, val);
+
+ ee->ee_pwr_cal_b[0].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ ee->ee_pwr_cal_b[1].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+ if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_pwr_cal_b[2].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ AR5K_EEPROM_READ(o++, val);
+
+ ee->ee_pwr_cal_g[0].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ ee->ee_pwr_cal_g[1].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+ if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_turbo_max_power[mode] = val & 0x7f;
+ ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_pwr_cal_g[2].freq =
+ ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+ if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+ ee->ee_n_piers[mode]++;
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+ ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+ ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ }
+ break;
+ }
+
+done:
/* return new offset */
*offset = o;
@@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
}
/*
- * Initialize eeprom & capabilities structs
+ * Read turbo mode information on newer EEPROM versions
*/
-int ath5k_eeprom_init(struct ath5k_hw *ah)
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+ u32 *offset, unsigned int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- unsigned int mode, i;
- int ret;
- u32 offset;
+ u32 o = *offset;
u16 val;
+ int ret;
- /* Initial TX thermal adjustment values */
- ee->ee_tx_clip = 4;
- ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
- ee->ee_gain_select = 1;
+ if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+ return 0;
- /*
- * Read values from EEPROM and store them in the capability structure
- */
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+ switch (mode){
+ case AR5K_EEPROM_MODE_11A:
+ ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
- /* Return if we have an old EEPROM */
- if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
- return 0;
+ ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+ ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+ ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+ ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+ if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+ ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+ ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+ ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+ ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+ AR5K_EEPROM_READ(o++, val);
+ ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+ ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+ break;
+ }
+
+ /* return new offset */
+ *offset = o;
+
+ return 0;
+}
+
+
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ u32 mode_offset[3];
+ unsigned int mode;
+ u32 offset;
+ int ret;
-#ifdef notyet
/*
- * Validate the checksum of the EEPROM date. There are some
- * devices with invalid EEPROMs.
+ * Get values for all modes
*/
- for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
- AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
- cksum ^= val;
+ mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+ mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+ mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+ ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+ AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+ for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+ offset = mode_offset[mode];
+
+ ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+ if (ret)
+ return ret;
+
+ ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+ if (ret)
+ return ret;
+
+ ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+ if (ret)
+ return ret;
}
- if (cksum != AR5K_EEPROM_INFO_CKSUM) {
- ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
- return -EIO;
+
+ /* override for older eeprom versions for better performance */
+ if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+ ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
}
-#endif
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
- ee_ant_gain);
+ return 0;
+}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
- AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
- }
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+ const static u16 intercepts3[] =
+ { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+ const static u16 intercepts3_2[] =
+ { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+ const u16 *ip;
+ int i;
+
+ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+ ip = intercepts3_2;
+ else
+ ip = intercepts3;
- if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
- AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
- ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
- ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+ for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+ *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
- AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
- ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
- ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+ struct ath5k_chan_pcal_info *pc, u8 *count)
+{
+ int o = *offset;
+ int i = 0;
+ u8 f1, f2;
+ int ret;
+ u16 val;
+
+ while(i < max) {
+ AR5K_EEPROM_READ(o++, val);
+
+ f1 = (val >> 8) & 0xff;
+ f2 = val & 0xff;
+
+ if (f1)
+ pc[i++].freq = f1;
+
+ if (f2)
+ pc[i++].freq = f2;
+
+ if (!f1 || !f2)
+ break;
}
+ *offset = o;
+ *count = i;
- /*
- * Get conformance test limit values
- */
- offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
- ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+ return 0;
+}
+
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+ int i, ret;
+ u16 val;
+ u8 mask;
+
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+ ath5k_eeprom_read_freq_list(ah, &offset,
+ AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+ &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]);
+ } else {
+ mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
- for (i = 0; i < ee->ee_ctls; i++) {
AR5K_EEPROM_READ(offset++, val);
- ee->ee_ctl[i] = (val >> 8) & 0xff;
- ee->ee_ctl[i + 1] = val & 0xff;
+ pcal[0].freq = (val >> 9) & mask;
+ pcal[1].freq = (val >> 2) & mask;
+ pcal[2].freq = (val << 5) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[2].freq |= (val >> 11) & 0x1f;
+ pcal[3].freq = (val >> 4) & mask;
+ pcal[4].freq = (val << 3) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[4].freq |= (val >> 13) & 0x7;
+ pcal[5].freq = (val >> 6) & mask;
+ pcal[6].freq = (val << 1) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[6].freq |= (val >> 15) & 0x1;
+ pcal[7].freq = (val >> 8) & mask;
+ pcal[8].freq = (val >> 1) & mask;
+ pcal[9].freq = (val << 6) & mask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ pcal[9].freq |= (val >> 10) & 0x3f;
+ ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
}
- /*
- * Get values for 802.11a (5GHz)
- */
- mode = AR5K_EEPROM_MODE_11A;
+ for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) {
+ pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+ pcal[i].freq, AR5K_EEPROM_MODE_11A);
+ }
- ee->ee_turbo_max_power[mode] =
- AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+ return 0;
+}
- offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal;
+ int i;
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11B:
+ pcal = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ pcal = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ ath5k_eeprom_read_freq_list(ah, &offset,
+ AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+ &ee->ee_n_piers[mode]);
+ for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) {
+ pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+ pcal[i].freq, mode);
+ }
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][3] = (val >> 5) & 0x7;
- ee->ee_db[mode][3] = (val >> 2) & 0x7;
- ee->ee_ob[mode][2] = (val << 1) & 0x7;
-
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
- ee->ee_db[mode][2] = (val >> 12) & 0x7;
- ee->ee_ob[mode][1] = (val >> 9) & 0x7;
- ee->ee_db[mode][1] = (val >> 6) & 0x7;
- ee->ee_ob[mode][0] = (val >> 3) & 0x7;
- ee->ee_db[mode][0] = val & 0x7;
-
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ return 0;
+}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_margin_tx_rx[mode] = val & 0x3f;
+
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *pcal;
+ int offset, ret;
+ int i, j;
+ u16 val;
+
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+
+ ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+ offset + AR5K_EEPROM_GROUP1_OFFSET);
+ if (ret < 0)
+ return ret;
+
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+ pcal = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+ !AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ pcal = ee->ee_pwr_cal_b;
+ offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+ /* fixed piers */
+ pcal[0].freq = 2412;
+ pcal[1].freq = 2447;
+ pcal[2].freq = 2484;
+ ee->ee_n_piers[mode] = 3;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ pcal = ee->ee_pwr_cal_g;
+ offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+ /* fixed piers */
+ pcal[0].freq = 2312;
+ pcal[1].freq = 2412;
+ pcal[2].freq = 2484;
+ ee->ee_n_piers[mode] = 3;
+ break;
+ default:
+ return -EINVAL;
}
- /*
- * Get values for 802.11b (2.4GHz)
- */
- mode = AR5K_EEPROM_MODE_11B;
- offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ struct ath5k_chan_pcal_info_rf5111 *cdata =
+ &pcal[i].rf5111_info;
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+ cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+ cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][1] = (val >> 4) & 0x7;
- ee->ee_db[mode][1] = val & 0x7;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pwr[0] |= ((val >> 14) & 0x3);
+ cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ AR5K_EEPROM_READ(offset++, val);
+ cdata->pwr[3] |= ((val >> 12) & 0xf);
+ cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M);
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][0] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
- ee->ee_cal_pier[mode][1] =
- ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+ cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][2] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+ cdata->pwr[8] |= ((val >> 14) & 0x3);
+ cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+ cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+ ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+ cdata->pcdac_max, cdata->pcdac);
+
+ for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) {
+ cdata->pwr[j] = (u16)
+ (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]);
+ }
}
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
- ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ return 0;
+}
- /*
- * Get values for 802.11g (2.4GHz)
- */
- mode = AR5K_EEPROM_MODE_11G;
- offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+ struct ath5k_chan_pcal_info *gen_chan_info;
+ u32 offset;
+ unsigned int i, c;
+ u16 val;
+ int ret;
- ret = ath5k_eeprom_read_ants(ah, &offset, mode);
- if (ret)
- return ret;
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ /*
+ * Read 5GHz EEPROM channels
+ */
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+ gen_chan_info = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+ /* NB: frequency piers parsed during mode init */
+ gen_chan_info = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP4_OFFSET;
+ else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+ /* NB: frequency piers parsed during mode init */
+ gen_chan_info = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
- AR5K_EEPROM_READ(offset++, val);
- ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
- ee->ee_ob[mode][1] = (val >> 4) & 0x7;
- ee->ee_db[mode][1] = val & 0x7;
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ chan_pcal_info = &gen_chan_info[i].rf5112_info;
- ret = ath5k_eeprom_read_modes(ah, &offset, mode);
- if (ret)
- return ret;
+ /* Power values in dBm * 4
+ * for the lower xpd gain curve
+ * (0 dBm -> higher output power) */
+ for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr_x0[c] = (val & 0xff);
+ chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff);
+ }
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+ /* PCDAC steps
+ * corresponding to the above power
+ * measurements */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][0] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
- ee->ee_cal_pier[mode][1] =
- ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+ chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+ chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+ chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
+ /* Power values in dBm * 4
+ * for the higher xpd gain curve
+ * (18 dBm -> lower output power) */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_turbo_max_power[mode] = val & 0x7f;
- ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+ chan_pcal_info->pwr_x3[0] = (val & 0xff);
+ chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff);
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cal_pier[mode][2] =
- ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+ chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+ /* PCDAC steps
+ * corresponding to the above power
+ * measurements (static) */
+ chan_pcal_info->pcdac_x3[0] = 20;
+ chan_pcal_info->pcdac_x3[1] = 35;
+ chan_pcal_info->pcdac_x3[2] = 63;
+
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+ chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff);
+
+ /* Last xpd0 power level is also channel maximum */
+ gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+ } else {
+ chan_pcal_info->pcdac_x0[0] = 1;
+ gen_chan_info[i].max_pwr = ((val >> 8) & 0xff);
+ }
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
- ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+ /* Recreate pcdac_x0 table for this channel using pcdac steps */
+ chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0];
+ chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1];
+ chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2];
+ }
+
+ return 0;
+}
+
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+ static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+ unsigned int sz;
+
+ sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+ sz *= ee->ee_n_piers[mode];
+
+ return sz;
+}
+
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+ u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+ switch(mode) {
+ case AR5K_EEPROM_MODE_11G:
+ if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+ offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2;
+ /* fall through */
+ case AR5K_EEPROM_MODE_11B:
+ if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+ offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5;
+ /* fall through */
+ case AR5K_EEPROM_MODE_11A:
+ break;
+ default:
+ break;
+ }
+
+ return offset;
+}
+
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info;
+ struct ath5k_chan_pcal_info *gen_chan_info;
+ unsigned int i, c;
+ u32 offset;
+ int ret;
+ u16 val;
+ u8 pd_gains = 0;
+
+ if (ee->ee_x_gain[mode] & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++;
+ if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++;
+ ee->ee_pd_gains[mode] = pd_gains;
+
+ offset = ath5k_cal_data_offset_2413(ee, mode);
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+
+ ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+ offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+ gen_chan_info = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+ return 0;
+ ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+ gen_chan_info = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+
+ ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+ offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+ gen_chan_info = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (pd_gains == 0)
+ return 0;
+
+ for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+ chan_pcal_info = &gen_chan_info[i].rf2413_info;
+
+ /*
+ * Read pwr_i, pddac_i and the first
+ * 2 pd points (pwr, pddac)
+ */
AR5K_EEPROM_READ(offset++, val);
- ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
- ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+ chan_pcal_info->pwr_i[0] = val & 0x1f;
+ chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f;
+ chan_pcal_info->pwr[0][0] =
+ (val >> 12) & 0xf;
- if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[0][0] = val & 0x3f;
+ chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf;
+ chan_pcal_info->pddac[0][1] =
+ (val >> 10) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[0][2] = val & 0xf;
+ chan_pcal_info->pddac[0][2] =
+ (val >> 4) & 0x3f;
+
+ chan_pcal_info->pwr[0][3] = 0;
+ chan_pcal_info->pddac[0][3] = 0;
+
+ if (pd_gains > 1) {
+ /*
+ * Pd gain 0 is not the last pd gain
+ * so it only has 2 pd points.
+ * Continue wih pd gain 1.
+ */
+ chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f;
+
+ chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1;
AR5K_EEPROM_READ(offset++, val);
- ee->ee_cck_ofdm_gain_delta = val & 0xff;
+ chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1;
+
+ chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf;
+ chan_pcal_info->pddac[1][0] =
+ (val >> 10) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[1][1] = val & 0xf;
+ chan_pcal_info->pddac[1][1] =
+ (val >> 4) & 0x3f;
+ chan_pcal_info->pwr[1][2] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[1][2] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[1][2] |=
+ (val & 0xF) << 2;
+
+ chan_pcal_info->pwr[1][3] = 0;
+ chan_pcal_info->pddac[1][3] = 0;
+ } else if (pd_gains == 1) {
+ /*
+ * Pd gain 0 is the last one so
+ * read the extra point.
+ */
+ chan_pcal_info->pwr[0][3] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[0][3] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[0][3] |=
+ (val & 0xF) << 2;
+ }
+
+ /*
+ * Proceed with the other pd_gains
+ * as above.
+ */
+ if (pd_gains > 2) {
+ chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f;
+ chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[2][0] =
+ (val >> 0) & 0xf;
+ chan_pcal_info->pddac[2][0] =
+ (val >> 4) & 0x3f;
+ chan_pcal_info->pwr[2][1] =
+ (val >> 10) & 0xf;
+
+ chan_pcal_info->pddac[2][1] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[2][1] |=
+ (val & 0xF) << 2;
+
+ chan_pcal_info->pwr[2][2] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[2][2] =
+ (val >> 8) & 0x3f;
+
+ chan_pcal_info->pwr[2][3] = 0;
+ chan_pcal_info->pddac[2][3] = 0;
+ } else if (pd_gains == 2) {
+ chan_pcal_info->pwr[1][3] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[1][3] =
+ (val >> 8) & 0x3f;
+ }
+
+ if (pd_gains > 3) {
+ chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+ chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f;
+ chan_pcal_info->pwr[3][0] =
+ (val >> 10) & 0xf;
+ chan_pcal_info->pddac[3][0] =
+ (val >> 14) & 0x3;
+
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[3][0] |=
+ (val & 0xF) << 2;
+ chan_pcal_info->pwr[3][1] =
+ (val >> 4) & 0xf;
+ chan_pcal_info->pddac[3][1] =
+ (val >> 8) & 0x3f;
+
+ chan_pcal_info->pwr[3][2] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[3][2] |=
+ ((val >> 0) & 0x3) << 2;
+
+ chan_pcal_info->pddac[3][2] =
+ (val >> 2) & 0x3f;
+ chan_pcal_info->pwr[3][3] =
+ (val >> 8) & 0xf;
+
+ chan_pcal_info->pddac[3][3] =
+ (val >> 12) & 0xF;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pddac[3][3] |=
+ ((val >> 0) & 0x3) << 4;
+ } else if (pd_gains == 3) {
+ chan_pcal_info->pwr[2][3] =
+ (val >> 14) & 0x3;
+ AR5K_EEPROM_READ(offset++, val);
+ chan_pcal_info->pwr[2][3] |=
+ ((val >> 0) & 0x3) << 2;
+
+ chan_pcal_info->pddac[2][3] =
+ (val >> 2) & 0x3f;
+ }
+
+ for (c = 0; c < pd_gains; c++) {
+ /* Recreate pwr table for this channel using pwr steps */
+ chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2;
+ chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0];
+ chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1];
+ chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2];
+ if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2])
+ chan_pcal_info->pwr[c][3] = 0;
+
+ /* Recreate pddac table for this channel using pddac steps */
+ chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c];
+ chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0];
+ chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1];
+ chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2];
+ if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2])
+ chan_pcal_info->pddac[c][3] = 0;
}
}
- /*
- * Read 5GHz EEPROM channels
- */
+ return 0;
+}
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_rate_pcal_info *rate_pcal_info;
+ u16 *rate_target_pwr_num;
+ u32 offset;
+ u16 val;
+ int ret, i;
+
+ offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+ rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_a;
+ ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_b;
+ ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+ rate_pcal_info = ee->ee_rate_tpwr_g;
+ ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Different freq mask for older eeproms (<= v3.2) */
+ if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+ for (i = 0; i < (*rate_target_pwr_num); i++) {
+ AR5K_EEPROM_READ(offset++, val);
+ rate_pcal_info[i].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+ rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+ rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+
+ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+ val == 0) {
+ (*rate_target_pwr_num) = i;
+ break;
+ }
+
+ rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+ rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+ rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+ }
+ } else {
+ for (i = 0; i < (*rate_target_pwr_num); i++) {
+ AR5K_EEPROM_READ(offset++, val);
+ rate_pcal_info[i].freq =
+ ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+ rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+ rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+ AR5K_EEPROM_READ(offset++, val);
+
+ if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+ val == 0) {
+ (*rate_target_pwr_num) = i;
+ break;
+ }
+
+ rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+ rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+ rate_pcal_info[i].target_power_54 = (val & 0x3f);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ int (*read_pcal)(struct ath5k_hw *hw, int mode);
+ int mode;
+ int err;
+
+ if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+ (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+ read_pcal = ath5k_eeprom_read_pcal_info_5112;
+ else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+ (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+ read_pcal = ath5k_eeprom_read_pcal_info_2413;
+ else
+ read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+ for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+ err = read_pcal(ah, mode);
+ if (err)
+ return err;
+
+ err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+/* Read conformance test limits */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_edge_power *rep;
+ unsigned int fmask, pmask;
+ unsigned int ctl_mode;
+ int ret, i, j;
+ u32 offset;
+ u16 val;
+
+ pmask = AR5K_EEPROM_POWER_M;
+ fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+ offset = AR5K_EEPROM_CTL(ee->ee_version);
+ ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+ for (i = 0; i < ee->ee_ctls; i += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ ee->ee_ctl[i] = (val >> 8) & 0xff;
+ ee->ee_ctl[i + 1] = val & 0xff;
+ }
+
+ offset = AR5K_EEPROM_GROUP8_OFFSET;
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+ offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+ AR5K_EEPROM_GROUP5_OFFSET;
+ else
+ offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
+
+ rep = ee->ee_ctl_pwr;
+ for(i = 0; i < ee->ee_ctls; i++) {
+ switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+ case AR5K_CTL_11A:
+ case AR5K_CTL_TURBO:
+ ctl_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ default:
+ ctl_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ }
+ if (ee->ee_ctl[i] == 0) {
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+ offset += 8;
+ else
+ offset += 7;
+ rep += AR5K_EEPROM_N_EDGES;
+ continue;
+ }
+ if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[j].freq = (val >> 8) & fmask;
+ rep[j + 1].freq = val & fmask;
+ }
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[j].edge = (val >> 8) & pmask;
+ rep[j].flag = (val >> 14) & 1;
+ rep[j + 1].edge = val & pmask;
+ rep[j + 1].flag = (val >> 6) & 1;
+ }
+ } else {
+ AR5K_EEPROM_READ(offset++, val);
+ rep[0].freq = (val >> 9) & fmask;
+ rep[1].freq = (val >> 2) & fmask;
+ rep[2].freq = (val << 5) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[2].freq |= (val >> 11) & 0x1f;
+ rep[3].freq = (val >> 4) & fmask;
+ rep[4].freq = (val << 3) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[4].freq |= (val >> 13) & 0x7;
+ rep[5].freq = (val >> 6) & fmask;
+ rep[6].freq = (val << 1) & fmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[6].freq |= (val >> 15) & 0x1;
+ rep[7].freq = (val >> 8) & fmask;
+
+ rep[0].edge = (val >> 2) & pmask;
+ rep[1].edge = (val << 4) & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[1].edge |= (val >> 12) & 0xf;
+ rep[2].edge = (val >> 6) & pmask;
+ rep[3].edge = val & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[4].edge = (val >> 10) & pmask;
+ rep[5].edge = (val >> 4) & pmask;
+ rep[6].edge = (val << 2) & pmask;
+
+ AR5K_EEPROM_READ(offset++, val);
+ rep[6].edge |= (val >> 14) & 0x3;
+ rep[7].edge = (val >> 8) & pmask;
+ }
+ for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+ rep[j].freq = ath5k_eeprom_bin2freq(ee,
+ rep[j].freq, ctl_mode);
+ }
+ rep += AR5K_EEPROM_N_EDGES;
+ }
return 0;
}
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+ int err;
+
+ err = ath5k_eeprom_init_header(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_init_modes(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_read_pcal_info(ah);
+ if (err < 0)
+ return err;
+
+ err = ath5k_eeprom_read_ctl_info(ah);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
/*
* Read the MAC address from eeprom
*/
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h
index a468ecfbb18..09eb7d0176a 100644
--- a/drivers/net/wireless/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath5k/eeprom.h
@@ -25,24 +25,8 @@
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
-#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
-#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
-#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
-#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
-#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
-#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
-#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
-#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
-#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
-#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
-#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
-#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
-#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
-#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
-#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
#define AR5K_EEPROM_INFO_CKSUM 0xffff
@@ -53,15 +37,19 @@
#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */
#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */
#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */
#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3 0x4003
+#define AR5K_EEPROM_VERSION_4_3 0x4003 /* power calibration changes */
#define AR5K_EEPROM_VERSION_4_4 0x4004
#define AR5K_EEPROM_VERSION_4_5 0x4005
#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7 0x4007
+#define AR5K_EEPROM_VERSION_4_7 0x3007 /* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */
#define AR5K_EEPROM_MODE_11A 0
#define AR5K_EEPROM_MODE_11B 1
@@ -74,8 +62,8 @@
#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */
#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */
#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */
#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c
#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
@@ -87,27 +75,95 @@
(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1)
/* calibration settings */
#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET 0x0
+#define AR5K_EEPROM_GROUP2_OFFSET 0x5
+#define AR5K_EEPROM_GROUP3_OFFSET 0x37
+#define AR5K_EEPROM_GROUP4_OFFSET 0x46
+#define AR5K_EEPROM_GROUP5_OFFSET 0x55
+#define AR5K_EEPROM_GROUP6_OFFSET 0x65
+#define AR5K_EEPROM_GROUP7_OFFSET 0x69
+#define AR5K_EEPROM_GROUP8_OFFSET 0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+ AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
/* [3.1 - 3.3] */
#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec
#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0 0x00c4
-#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
-#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
-#define AR5K_EEPROM_MISC1 0x00c5
-#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
-
+#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
/* Some EEPROM defines */
#define AR5K_EEPROM_EEP_SCALE 100
@@ -115,8 +171,11 @@
#define AR5K_EEPROM_N_MODES 3
#define AR5K_EEPROM_N_5GHZ_CHAN 10
#define AR5K_EEPROM_N_2GHZ_CHAN 3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
#define AR5K_EEPROM_MAX_CHAN 10
+#define AR5K_EEPROM_N_PWR_POINTS_5111 11
#define AR5K_EEPROM_N_PCDAC 11
+#define AR5K_EEPROM_N_PHASE_CAL 5
#define AR5K_EEPROM_N_TEST_FREQ 8
#define AR5K_EEPROM_N_EDGES 8
#define AR5K_EEPROM_N_INTERCEPTS 11
@@ -136,6 +195,8 @@
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
#define AR5K_EEPROM_N_XPD0_POINTS 4
#define AR5K_EEPROM_N_XPD3_POINTS 3
+#define AR5K_EEPROM_N_PD_GAINS 4
+#define AR5K_EEPROM_N_PD_POINTS 5
#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35
#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
#define AR5K_EEPROM_POWER_M 0x3f
@@ -158,8 +219,99 @@
#define AR5K_EEPROM_READ_HDR(_o, _v) \
AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \
-/* Struct to hold EEPROM calibration data */
+enum ath5k_ant_setting {
+ AR5K_ANT_VARIABLE = 0, /* variable by programming */
+ AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
+ AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */
+ AR5K_ANT_MAX = 3,
+};
+
+enum ath5k_ctl_mode {
+ AR5K_CTL_11A = 0,
+ AR5K_CTL_11B = 1,
+ AR5K_CTL_11G = 2,
+ AR5K_CTL_TURBO = 3,
+ AR5K_CTL_108G = 4,
+ AR5K_CTL_2GHT20 = 5,
+ AR5K_CTL_5GHT20 = 6,
+ AR5K_CTL_2GHT40 = 7,
+ AR5K_CTL_5GHT40 = 8,
+ AR5K_CTL_MODE_M = 15,
+};
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+ /* Power levels in half dbm units
+ * for one power curve. */
+ u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+ /* PCDAC table steps
+ * for the above values */
+ u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+ /* Starting PCDAC step */
+ u8 pcdac_min;
+ /* Final PCDAC step */
+ u8 pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+ /* Power levels in quarter dBm units
+ * for lower (0) and higher (3)
+ * level curves */
+ s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+ s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+ /* PCDAC table steps
+ * for the above values */
+ u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+ u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+ /* Starting pwr/pddac values */
+ s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
+ u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
+ /* (pwr,pddac) points */
+ s8 pwr[AR5K_EEPROM_N_PD_GAINS]
+ [AR5K_EEPROM_N_PD_POINTS];
+ u8 pddac[AR5K_EEPROM_N_PD_GAINS]
+ [AR5K_EEPROM_N_PD_POINTS];
+};
+
+struct ath5k_chan_pcal_info {
+ /* Frequency */
+ u16 freq;
+ /* Max available power */
+ s8 max_pwr;
+ union {
+ struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+ struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+ struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+ };
+};
+
+/* Per rate calibration data for each mode, used for power table setup */
+struct ath5k_rate_pcal_info {
+ u16 freq; /* Frequency */
+ /* Power level for 6-24Mbit/s rates */
+ u16 target_power_6to24;
+ /* Power level for 36Mbit rate */
+ u16 target_power_36;
+ /* Power level for 48Mbit rate */
+ u16 target_power_48;
+ /* Power level for 54Mbit rate */
+ u16 target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+ u16 freq;
+ u16 edge; /* in half dBm */
+ bool flag;
+};
+
+/* EEPROM calibration data */
struct ath5k_eeprom_info {
+
+ /* Header information */
u16 ee_magic;
u16 ee_protect;
u16 ee_regdomain;
@@ -168,6 +320,11 @@ struct ath5k_eeprom_info {
u16 ee_ant_gain;
u16 ee_misc0;
u16 ee_misc1;
+ u16 ee_misc2;
+ u16 ee_misc3;
+ u16 ee_misc4;
+ u16 ee_misc5;
+ u16 ee_misc6;
u16 ee_cck_ofdm_gain_delta;
u16 ee_cck_ofdm_power_delta;
u16 ee_scaled_cck_delta;
@@ -185,7 +342,7 @@ struct ath5k_eeprom_info {
u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES];
u16 ee_xr_power[AR5K_EEPROM_N_MODES];
u16 ee_switch_settling[AR5K_EEPROM_N_MODES];
- u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+ u16 ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
@@ -198,18 +355,40 @@ struct ath5k_eeprom_info {
u16 ee_x_gain[AR5K_EEPROM_N_MODES];
u16 ee_i_gain[AR5K_EEPROM_N_MODES];
u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+ u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+ u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+ u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
- /* Unused */
+ /* Power calibration data */
u16 ee_false_detect[AR5K_EEPROM_N_MODES];
- u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
- u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+ /* Number of pd gain curves per mode (RF2413) */
+ u8 ee_pd_gains[AR5K_EEPROM_N_MODES];
+
+ u8 ee_n_piers[AR5K_EEPROM_N_MODES];
+ struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+ struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN];
+ struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN];
+
+ /* Per rate target power levels */
+ u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN];
+ struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN];
/* Conformance test limits (Unused) */
u16 ee_ctls;
u16 ee_ctl[AR5K_EEPROM_MAX_CTLS];
+ struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
/* Noise Floor Calibration settings */
s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES];
s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+ s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+ s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+ s8 ee_pd_gain_overlap;
+
+ u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
+
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
index ceaa6c475c0..450bd6e945f 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -1681,7 +1681,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
*/
/* For AR5212 and combatible */
- if (ah->ah_version == AR5K_AR5212){
+ if (ah->ah_version == AR5K_AR5212) {
/* First set of mode-specific settings */
ath5k_hw_ini_mode_registers(ah,
@@ -1695,7 +1695,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ar5212_ini, change_channel);
/* Second set of mode-specific settings */
- if (ah->ah_radio == AR5K_RF5111){
+ if (ah->ah_radio == AR5K_RF5111) {
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
@@ -1706,7 +1706,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ARRAY_SIZE(rf5111_ini_bbgain),
rf5111_ini_bbgain, change_channel);
- } else if (ah->ah_radio == AR5K_RF5112){
+ } else if (ah->ah_radio == AR5K_RF5112) {
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
@@ -1716,7 +1716,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
ARRAY_SIZE(rf5112_ini_bbgain),
rf5112_ini_bbgain, change_channel);
- } else if (ah->ah_radio == AR5K_RF5413){
+ } else if (ah->ah_radio == AR5K_RF5413) {
ath5k_hw_ini_mode_registers(ah,
ARRAY_SIZE(rf5413_ini_mode_end),
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index a47df9a24aa..0cac05c6a9c 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
{
u32 pcu_reg, beacon_reg, low_id, high_id;
- pcu_reg = 0;
+
+ /* Preserve rest settings */
+ pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+ pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+ | AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
+ (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
beacon_reg = 0;
ATH5K_TRACE(ah->ah_sc);
switch (ah->ah_op_mode) {
case NL80211_IFTYPE_ADHOC:
- pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
- (ah->ah_version == AR5K_AR5210 ?
- AR5K_STA_ID1_NO_PSPOLL : 0);
+ pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
beacon_reg |= AR5K_BCR_ADHOC;
+ if (ah->ah_version == AR5K_AR5210)
+ pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+ else
+ AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
- pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
- (ah->ah_version == AR5K_AR5210 ?
- AR5K_STA_ID1_NO_PSPOLL : 0);
+ pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
beacon_reg |= AR5K_BCR_AP;
+ if (ah->ah_version == AR5K_AR5210)
+ pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+ else
+ AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
break;
case NL80211_IFTYPE_STATION:
- pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
- (ah->ah_version == AR5K_AR5210 ?
+ pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_PWR_SV : 0);
case NL80211_IFTYPE_MONITOR:
- pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
- (ah->ah_version == AR5K_AR5210 ?
+ pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+ | (ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_NO_PSPOLL : 0);
break;
@@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
}
+
+ /* TODO: Handle ANI stats */
}
/**
@@ -258,16 +271,19 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
{
u32 low_id, high_id;
+ u32 pcu_reg;
ATH5K_TRACE(ah->ah_sc);
/* Set new station ID */
memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+ pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+
low_id = AR5K_LOW_ID(mac);
high_id = AR5K_HIGH_ID(mac);
ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
- ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
+ ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
return 0;
}
@@ -290,8 +306,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
* Set simple BSSID mask on 5212
*/
if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+ ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+ AR5K_BSS_IDM0);
+ ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+ AR5K_BSS_IDM1);
}
/*
@@ -415,6 +433,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
u32 low_id, high_id;
ATH5K_TRACE(ah->ah_sc);
+ /* Cache bssid mask so that we can restore it
+ * on reset */
+ memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
if (ah->ah_version == AR5K_AR5212) {
low_id = AR5K_LOW_ID(mask);
high_id = AR5K_HIGH_ID(mask);
@@ -576,7 +597,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
filter |= AR5K_RX_FILTER_PROM;
}
- /*Zero length DMA*/
+ /*Zero length DMA (phy error reporting) */
if (data)
AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
else
@@ -661,7 +682,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
* Set the additional timers by mode
*/
switch (ah->ah_op_mode) {
+ case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_STATION:
+ /* In STA mode timer1 is used as next wakeup
+ * timer and timer2 as next CFP duration start
+ * timer. Both in 1/8TUs. */
+ /* TODO: PCF handling */
if (ah->ah_version == AR5K_AR5210) {
timer1 = 0xffffffff;
timer2 = 0xffffffff;
@@ -669,27 +695,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
timer1 = 0x0000ffff;
timer2 = 0x0007ffff;
}
+ /* Mark associated AP as PCF incapable for now */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
break;
-
+ case NL80211_IFTYPE_ADHOC:
+ AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
default:
+ /* On non-STA modes timer1 is used as next DMA
+ * beacon alert (DBA) timer and timer2 as next
+ * software beacon alert. Both in 1/8TUs. */
timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+ break;
}
+ /* Timer3 marks the end of our ATIM window
+ * a zero length window is not allowed because
+ * we 'll get no beacons */
timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
/*
* Set the beacon register and enable all timers.
- * (next beacon, DMA beacon, software beacon, ATIM window time)
*/
- ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+ /* When in AP mode zero timer0 to start TSF */
+ if (ah->ah_op_mode == NL80211_IFTYPE_AP)
+ ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+ else
+ ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
+ /* Force a TSF reset if requested and enable beacons */
+ if (interval & AR5K_BEACON_RESET_TSF)
+ ath5k_hw_reset_tsf(ah);
+
ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
- AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
- AR5K_BEACON);
+ AR5K_BEACON_ENABLE),
+ AR5K_BEACON);
+
+ /* Flush any pending BMISS interrupts on ISR by
+ * performing a clear-on-write operation on PISR
+ * register for the BMISS bit (writing a bit on
+ * ISR togles a reset for that bit and leaves
+ * the rest bits intact) */
+ if (ah->ah_version == AR5K_AR5210)
+ ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
+ else
+ ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
+
+ /* TODO: Set enchanced sleep registers on AR5212
+ * based on vif->bss_conf params, until then
+ * disable power save reporting.*/
+ AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
+
}
#if 0
@@ -899,14 +958,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
*/
int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
{
- unsigned int i;
+ unsigned int i, type;
+ u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+ type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+ /* Reset associated MIC entry if TKIP
+ * is enabled located at offset (entry + 64) */
+ if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+ AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
+ for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+ ath5k_hw_reg_write(ah, 0,
+ AR5K_KEYTABLE_OFF(micentry, i));
+ }
+
/*
* Set NULL encryption on AR5212+
*
@@ -916,10 +987,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
* Note2: Windows driver (ndiswrapper) sets this to
* 0x00000714 instead of 0x00000007
*/
- if (ah->ah_version > AR5K_AR5211)
+ if (ah->ah_version > AR5K_AR5211) {
ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
AR5K_KEYTABLE_TYPE(entry));
+ if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+ ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+ AR5K_KEYTABLE_TYPE(micentry));
+ }
+ }
+
return 0;
}
@@ -936,6 +1013,23 @@ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
AR5K_KEYTABLE_VALID;
}
+static
+int ath5k_keycache_type(const struct ieee80211_key_conf *key)
+{
+ switch (key->alg) {
+ case ALG_TKIP:
+ return AR5K_KEYTABLE_TYPE_TKIP;
+ case ALG_CCMP:
+ return AR5K_KEYTABLE_TYPE_CCM;
+ case ALG_WEP:
+ if (key->keylen == LEN_WEP40)
+ return AR5K_KEYTABLE_TYPE_40;
+ else if (key->keylen == LEN_WEP104)
+ return AR5K_KEYTABLE_TYPE_104;
+ }
+ return -EINVAL;
+}
+
/*
* Set a key entry on the table
*/
@@ -943,40 +1037,53 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
const struct ieee80211_key_conf *key, const u8 *mac)
{
unsigned int i;
+ int keylen;
__le32 key_v[5] = {};
+ __le32 key0 = 0, key1 = 0;
+ __le32 *rxmic, *txmic;
u32 keytype;
+ u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+ bool is_tkip;
+ const u8 *key_ptr;
ATH5K_TRACE(ah->ah_sc);
- /* key->keylen comes in from mac80211 in bytes */
+ is_tkip = (key->alg == ALG_TKIP);
- if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+ /*
+ * key->keylen comes in from mac80211 in bytes.
+ * TKIP is 128 bit + 128 bit mic
+ */
+ keylen = (is_tkip) ? (128 / 8) : key->keylen;
+
+ if (entry > AR5K_KEYTABLE_SIZE ||
+ (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
return -EOPNOTSUPP;
- switch (key->keylen) {
- /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */
- case 40 / 8:
- memcpy(&key_v[0], key->key, 5);
- keytype = AR5K_KEYTABLE_TYPE_40;
- break;
+ if (unlikely(keylen > 16))
+ return -EOPNOTSUPP;
- /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */
- case 104 / 8:
- memcpy(&key_v[0], &key->key[0], 6);
- memcpy(&key_v[2], &key->key[6], 6);
- memcpy(&key_v[4], &key->key[12], 1);
- keytype = AR5K_KEYTABLE_TYPE_104;
- break;
- /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */
- case 128 / 8:
- memcpy(&key_v[0], &key->key[0], 6);
- memcpy(&key_v[2], &key->key[6], 6);
- memcpy(&key_v[4], &key->key[12], 4);
- keytype = AR5K_KEYTABLE_TYPE_128;
- break;
+ keytype = ath5k_keycache_type(key);
+ if (keytype < 0)
+ return keytype;
- default:
- return -EINVAL; /* shouldn't happen */
+ /*
+ * each key block is 6 bytes wide, written as pairs of
+ * alternating 32 and 16 bit le values.
+ */
+ key_ptr = key->key;
+ for (i = 0; keylen >= 6; keylen -= 6) {
+ memcpy(&key_v[i], key_ptr, 6);
+ i += 2;
+ key_ptr += 6;
+ }
+ if (keylen)
+ memcpy(&key_v[i], key_ptr, keylen);
+
+ /* intentionally corrupt key until mic is installed */
+ if (is_tkip) {
+ key0 = key_v[0] = ~key_v[0];
+ key1 = key_v[1] = ~key_v[1];
}
for (i = 0; i < ARRAY_SIZE(key_v); i++)
@@ -985,6 +1092,40 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
+ if (is_tkip) {
+ /* Install rx/tx MIC */
+ rxmic = (__le32 *) &key->key[16];
+ txmic = (__le32 *) &key->key[24];
+
+ if (ah->ah_combined_mic) {
+ key_v[0] = rxmic[0];
+ key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16);
+ key_v[2] = rxmic[1];
+ key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff);
+ key_v[4] = txmic[1];
+ } else {
+ key_v[0] = rxmic[0];
+ key_v[1] = 0;
+ key_v[2] = rxmic[1];
+ key_v[3] = 0;
+ key_v[4] = 0;
+ }
+ for (i = 0; i < ARRAY_SIZE(key_v); i++)
+ ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+ AR5K_KEYTABLE_OFF(micentry, i));
+
+ ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+ AR5K_KEYTABLE_TYPE(micentry));
+ ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
+ ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
+
+ /* restore first 2 words of key */
+ ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
+ AR5K_KEYTABLE_OFF(entry, 0));
+ ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
+ AR5K_KEYTABLE_OFF(entry, 1));
+ }
+
return ath5k_hw_set_key_lladdr(ah, entry, mac);
}
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index e43f6563e61..7ba18e09463 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -1412,7 +1412,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
rf_ini = rfregs_2112a;
rf_size = ARRAY_SIZE(rfregs_5112a);
if (mode < 2) {
- ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode);
+ ATH5K_ERR(ah->ah_sc, "invalid channel mode: %i\n",
+ mode);
return -EINVAL;
}
mode = mode - 2; /*no a/turboa modes for 2112*/
@@ -1708,7 +1709,7 @@ enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
if (ah->ah_radio >= AR5K_RF5112) {
ath5k_hw_rfregs_gainf_corr(ah);
ah->ah_gain.g_current =
- ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ?
+ ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
0;
}
@@ -2195,9 +2196,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret;
}
- ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
- if (ret)
- return ret;
+ ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/*
* Re-enable RX/TX and beacons
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c
index 01bf09176d2..1b7bc50ea8e 100644
--- a/drivers/net/wireless/ath5k/qcu.c
+++ b/drivers/net/wireless/ath5k/qcu.c
@@ -432,13 +432,30 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
+
+ if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
+ AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
/* Update secondary interrupt mask registers */
+
+ /* Filter out inactive queues */
ah->ah_txq_imr_txok &= ah->ah_txq_status;
ah->ah_txq_imr_txerr &= ah->ah_txq_status;
ah->ah_txq_imr_txurn &= ah->ah_txq_status;
ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+ ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
+ ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
+ ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
+ ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
AR5K_SIMR0_QCU_TXOK) |
@@ -448,8 +465,24 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_SIMR1_QCU_TXERR) |
AR5K_REG_SM(ah->ah_txq_imr_txeol,
AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
- ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
- AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
+ /* Update simr2 but don't overwrite rest simr2 settings */
+ AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
+ AR5K_REG_SM(ah->ah_txq_imr_txurn,
+ AR5K_SIMR2_QCU_TXURN));
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
+ AR5K_SIMR3_QCBRORN) |
+ AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
+ AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
+ AR5K_SIMR4_QTRIG), AR5K_SIMR4);
+ /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
+ ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
+ AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
+ /* No queue has TXNOFRM enabled, disable the interrupt
+ * by setting AR5K_TXNOFRM to zero */
+ if (ah->ah_txq_imr_nofrm == 0)
+ ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
}
return 0;
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index e557fe178bb..91aaeaf8819 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -234,6 +234,7 @@
#define AR5K_TXNOFRM 0x004c
#define AR5K_TXNOFRM_M 0x000003ff
#define AR5K_TXNOFRM_QCU 0x000ffc00
+#define AR5K_TXNOFRM_QCU_S 10
/*
* Receive frame gap timeout register
@@ -350,7 +351,7 @@
#define AR5K_SISR3 0x0090 /* Register Address [5211+] */
#define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */
-#define AR5K_SISR3_QCBORN_S 0
+#define AR5K_SISR3_QCBRORN_S 0
#define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */
#define AR5K_SISR3_QCBRURN_S 16
@@ -1113,14 +1114,16 @@
#define AR5K_PCU_MAX 0x8fff
/*
- * First station id register (MAC address in lower 32 bits)
+ * First station id register (Lower 32 bits of MAC address)
*/
-#define AR5K_STA_ID0 0x8000
+#define AR5K_STA_ID0 0x8000
+#define AR5K_STA_ID0_ARRD_L32 0xffffffff
/*
- * Second station id register (MAC address in upper 16 bits)
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
*/
#define AR5K_STA_ID1 0x8004 /* Register Address */
+#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */
#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */
#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */
#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */
@@ -1726,6 +1729,7 @@
#define AR5K_MISC_MODE 0x8120 /* Register Address */
#define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */
#define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */
+#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */
/* more bits */
/*
@@ -1810,6 +1814,10 @@
#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7)
#define AR5K_KEYTABLE_VALID 0x00008000
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define AR5K_KEYTABLE_MIC_OFFSET 64
+
/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit
* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c
index 1b6d45b6772..dc2d7d8bdb7 100644
--- a/drivers/net/wireless/ath5k/reset.c
+++ b/drivers/net/wireless/ath5k/reset.c
@@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
0xffffc07f);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
- (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+ (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000,
0xfffc0fff);
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
@@ -842,9 +842,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*
* XXX: Find an interval that's OK for all cards...
*/
- ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
- if (ret)
- return ret;
+ ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/*
* Reset queues and start beacon timers at the end of the reset routine
@@ -864,8 +862,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* Pre-enable interrupts on 5211/5212*/
if (ah->ah_version != AR5K_AR5210)
- ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX |
- AR5K_INT_FATAL);
+ ath5k_hw_set_imr(ah, ah->ah_imr);
/*
* Set RF kill flags if supported by the device (read from the EEPROM)
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index 80a69243041..c43bd321f97 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -9,3 +9,14 @@ config ATH9K
Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
If you choose to build a module, it'll be called ath9k.
+
+config ATH9K_DEBUG
+ bool "Atheros ath9k debugging"
+ depends on ATH9K
+ ---help---
+ Say Y, if you need ath9k to display debug messages.
+ Pass the debug mask as a module parameter:
+
+ modprobe ath9k debug=0x00002000
+
+ Look in ath9k/core.h for possible debug masks
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index a6411517e5f..1209d14613a 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -1,11 +1,16 @@
ath9k-y += hw.o \
+ eeprom.o \
+ mac.o \
+ calib.o \
+ ani.o \
phy.o \
regd.o \
beacon.o \
main.o \
recv.o \
xmit.o \
- rc.o \
- core.o
+ rc.o
+
+ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c
new file mode 100644
index 00000000000..251e2d9a7a4
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ani.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+ if (ahp->ah_ani[i].c.channel == chan->channel)
+ return i;
+ if (ahp->ah_ani[i].c.channel == 0) {
+ ahp->ah_ani[i].c.channel = chan->channel;
+ ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+ return i;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "No more channel states left. Using channel 0\n");
+
+ return 0;
+}
+
+static bool ath9k_hw_ani_control(struct ath_hal *ah,
+ enum ath9k_ani_cmd cmd, int param)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState = ahp->ah_curani;
+
+ switch (cmd & ahp->ah_ani_function) {
+ case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
+ return false;
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_TOT_DES,
+ ahp->ah_totalSizeDesired[level]);
+ REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+ AR_PHY_AGC_CTL1_COARSE_LOW,
+ ahp->ah_coarseLow[level]);
+ REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+ AR_PHY_AGC_CTL1_COARSE_HIGH,
+ ahp->ah_coarseHigh[level]);
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRPWR,
+ ahp->ah_firpwr[level]);
+
+ if (level > aniState->noiseImmunityLevel)
+ ahp->ah_stats.ast_ani_niup++;
+ else if (level < aniState->noiseImmunityLevel)
+ ahp->ah_stats.ast_ani_nidown++;
+ aniState->noiseImmunityLevel = level;
+ break;
+ }
+ case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+ const int m1ThreshLow[] = { 127, 50 };
+ const int m2ThreshLow[] = { 127, 40 };
+ const int m1Thresh[] = { 127, 0x4d };
+ const int m2Thresh[] = { 127, 0x40 };
+ const int m2CountThr[] = { 31, 16 };
+ const int m2CountThrLow[] = { 63, 48 };
+ u32 on = param ? 1 : 0;
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+ m1ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+ m2ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M1_THRESH,
+ m1Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2_THRESH,
+ m2Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2COUNT_THR,
+ m2CountThr[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+ m2CountThrLow[on]);
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+ m1ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+ m2ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH,
+ m1Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH,
+ m2Thresh[on]);
+
+ 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)
+ ahp->ah_stats.ast_ani_ofdmon++;
+ else
+ ahp->ah_stats.ast_ani_ofdmoff++;
+ aniState->ofdmWeakSigDetectOff = !on;
+ }
+ break;
+ }
+ case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+ 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)
+ ahp->ah_stats.ast_ani_cckhigh++;
+ else
+ ahp->ah_stats.ast_ani_ccklow++;
+ aniState->cckWeakSigThreshold = high;
+ }
+ break;
+ }
+ case ATH9K_ANI_FIRSTEP_LEVEL:{
+ const int firstep[] = { 0, 4, 8 };
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(firstep)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(firstep));
+ return false;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRSTEP,
+ firstep[level]);
+ if (level > aniState->firstepLevel)
+ ahp->ah_stats.ast_ani_stepup++;
+ else if (level < aniState->firstepLevel)
+ ahp->ah_stats.ast_ani_stepdown++;
+ aniState->firstepLevel = level;
+ break;
+ }
+ case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+ const int cycpwrThr1[] =
+ { 2, 4, 6, 8, 10, 12, 14, 16 };
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(cycpwrThr1)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned)
+ ARRAY_SIZE(cycpwrThr1));
+ return false;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+ AR_PHY_TIMING5_CYCPWR_THR1,
+ cycpwrThr1[level]);
+ if (level > aniState->spurImmunityLevel)
+ ahp->ah_stats.ast_ani_spurup++;
+ else if (level < aniState->spurImmunityLevel)
+ ahp->ah_stats.ast_ani_spurdown++;
+ aniState->spurImmunityLevel = level;
+ break;
+ }
+ case ATH9K_ANI_PRESENT:
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "invalid cmd %u\n", cmd);
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+ "ofdmWeakSigDetectOff=%d\n",
+ aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "cckWeakSigThreshold=%d, "
+ "firstepLevel=%d, listenTime=%d\n",
+ aniState->cckWeakSigThreshold, aniState->firstepLevel,
+ aniState->listenTime);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+ aniState->cycleCount, aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
+
+ return true;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+ struct ath9k_mib_stats *stats)
+{
+ stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+ stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+ stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+ stats->rts_good += REG_READ(ah, AR_RTS_OK);
+ stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_ani_restart(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+
+ aniState->listenTime = 0;
+ if (ahp->ah_hasHwPhyCounters) {
+ if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->ofdmPhyErrBase = 0;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "OFDM Trigger is too high for hw counters\n");
+ } else {
+ aniState->ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+ }
+ if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->cckPhyErrBase = 0;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "CCK Trigger is too high for hw counters\n");
+ } else {
+ aniState->cckPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Writing ofdmbase=%u cckbase=%u\n",
+ aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+ }
+ aniState->ofdmPhyErrCount = 0;
+ aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ar5416AniState *aniState;
+ enum wireless_mode mode;
+ int32_t rssi;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+
+ 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->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(ahp);
+ 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 {
+ mode = ath9k_hw_chan2wmode(ah, chan);
+ if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+ 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(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ar5416AniState *aniState;
+ enum wireless_mode mode;
+ int32_t rssi;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+ if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel + 1)) {
+ return;
+ }
+ }
+ if (ah->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(ahp);
+ if (rssi > aniState->rssiThrLow) {
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ } else {
+ mode = ath9k_hw_chan2wmode(ah, chan);
+ if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+ if (aniState->firstepLevel > 0)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL, 0);
+ }
+ }
+}
+
+static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ int32_t rssi;
+
+ aniState = ahp->ah_curani;
+
+ if (ah->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(ahp);
+ 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) == true)
+ return;
+ }
+ if (aniState->firstepLevel > 0) {
+ if (ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1) == true)
+ return;
+ }
+ } else {
+ if (aniState->firstepLevel > 0) {
+ if (ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1) == true)
+ 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;
+ }
+}
+
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ u32 txFrameCount, rxFrameCount, cycleCount;
+ int32_t listenTime;
+
+ txFrameCount = REG_READ(ah, AR_TFCNT);
+ rxFrameCount = REG_READ(ah, AR_RFCNT);
+ cycleCount = REG_READ(ah, AR_CCCNT);
+
+ aniState = ahp->ah_curani;
+ if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+
+ listenTime = 0;
+ ahp->ah_stats.ast_ani_lzero++;
+ } else {
+ int32_t ccdelta = cycleCount - aniState->cycleCount;
+ int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
+ int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+ listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+ }
+ aniState->cycleCount = cycleCount;
+ aniState->txFrameCount = txFrameCount;
+ aniState->rxFrameCount = rxFrameCount;
+
+ return listenTime;
+}
+
+void ath9k_ani_reset(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ struct ath9k_channel *chan = ah->ah_curchan;
+ int index;
+
+ if (!DO_ANI(ah))
+ return;
+
+ index = ath9k_hw_get_ani_channel_idx(ah, chan);
+ aniState = &ahp->ah_ani[index];
+ ahp->ah_curani = aniState;
+
+ if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION
+ && ah->ah_opmode != NL80211_IFTYPE_ADHOC) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Reset ANI state opmode %u\n", ah->ah_opmode);
+ ahp->ah_stats.ast_ani_reset++;
+
+ 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_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+ ATH9K_RX_FILTER_PHYERR);
+
+ if (ah->ah_opmode == NL80211_IFTYPE_AP) {
+ ahp->ah_curani->ofdmTrigHigh =
+ ah->ah_config.ofdm_trig_high;
+ ahp->ah_curani->ofdmTrigLow =
+ ah->ah_config.ofdm_trig_low;
+ ahp->ah_curani->cckTrigHigh =
+ ah->ah_config.cck_trig_high;
+ ahp->ah_curani->cckTrigLow =
+ ah->ah_config.cck_trig_low;
+ }
+ 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);
+ if (ahp->ah_hasHwPhyCounters) {
+ ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+ ~ATH9K_RX_FILTER_PHYERR);
+ ath9k_ani_restart(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);
+
+ } else {
+ ath9k_ani_restart(ah);
+ ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+ ATH9K_RX_FILTER_PHYERR);
+ }
+}
+
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ int32_t listenTime;
+
+ aniState = ahp->ah_curani;
+ ahp->ah_stats.ast_nodestats = *stats;
+
+ listenTime = ath9k_hw_ani_get_listen_time(ah);
+ if (listenTime < 0) {
+ ahp->ah_stats.ast_ani_lneg++;
+ ath9k_ani_restart(ah);
+ return;
+ }
+
+ aniState->listenTime += listenTime;
+
+ if (ahp->ah_hasHwPhyCounters) {
+ u32 phyCnt1, phyCnt2;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+ if (phyCnt1 < aniState->ofdmPhyErrBase ||
+ phyCnt2 < aniState->cckPhyErrBase) {
+ if (phyCnt1 < aniState->ofdmPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "phyCnt1 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+ AR_PHY_ERR_OFDM_TIMING);
+ }
+ if (phyCnt2 < aniState->cckPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "phyCnt2 0x%x, resetting "
+ "counter value to 0x%x\n",
+ phyCnt2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+ AR_PHY_ERR_CCK_TIMING);
+ }
+ return;
+ }
+
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ahp->ah_stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ahp->ah_stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
+ }
+
+ if (!DO_ANI(ah))
+ return;
+
+ if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+ if (aniState->ofdmPhyErrCount <= aniState->listenTime *
+ aniState->ofdmTrigLow / 1000 &&
+ aniState->cckPhyErrCount <= aniState->listenTime *
+ aniState->cckTrigLow / 1000)
+ ath9k_hw_ani_lower_immunity(ah);
+ ath9k_ani_restart(ah);
+ } else if (aniState->listenTime > ahp->ah_aniPeriod) {
+ if (aniState->ofdmPhyErrCount > aniState->listenTime *
+ aniState->ofdmTrigHigh / 1000) {
+ ath9k_hw_ani_ofdm_err_trigger(ah);
+ ath9k_ani_restart(ah);
+ } else if (aniState->cckPhyErrCount >
+ aniState->listenTime * aniState->cckTrigHigh /
+ 1000) {
+ ath9k_hw_ani_cck_err_trigger(ah);
+ ath9k_ani_restart(ah);
+ }
+ }
+}
+
+bool ath9k_hw_phycounters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ahp->ah_hasHwPhyCounters ? true : false;
+}
+
+void ath9k_enable_mib_counters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+ REG_WRITE(ah, AR_MIBC,
+ ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
+ & 0x0f);
+ 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);
+}
+
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+
+ REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+}
+
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+ u32 *rxc_pcnt,
+ u32 *rxf_pcnt,
+ u32 *txf_pcnt)
+{
+ static u32 cycles, rx_clear, rx_frame, tx_frame;
+ u32 good = 1;
+
+ u32 rc = REG_READ(ah, AR_RCCNT);
+ u32 rf = REG_READ(ah, AR_RFCNT);
+ u32 tf = REG_READ(ah, AR_TFCNT);
+ u32 cc = REG_READ(ah, AR_CCCNT);
+
+ if (cycles == 0 || cycles > cc) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "cycle counter wrap. ExtBusy = 0\n");
+ good = 0;
+ } else {
+ u32 cc_d = cc - cycles;
+ u32 rc_d = rc - rx_clear;
+ u32 rf_d = rf - rx_frame;
+ u32 tf_d = tf - tx_frame;
+
+ if (cc_d != 0) {
+ *rxc_pcnt = rc_d * 100 / cc_d;
+ *rxf_pcnt = rf_d * 100 / cc_d;
+ *txf_pcnt = tf_d * 100 / cc_d;
+ } else {
+ good = 0;
+ }
+ }
+
+ cycles = cc;
+ rx_frame = rf;
+ rx_clear = rc;
+ tx_frame = tf;
+
+ return good;
+}
+
+/*
+ * 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_procmibevent(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats)
+{
+ struct ath_hal_5416 *ahp = AH5416(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, &ahp->ah_mibStats);
+ ahp->ah_stats.ast_nodestats = *stats;
+
+ if (!DO_ANI(ah))
+ 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)) {
+ struct ar5416AniState *aniState = ahp->ah_curani;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+ /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ahp->ah_stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ahp->ah_stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
+
+ /*
+ * NB: figure out which counter triggered. If both
+ * trigger we'll only deal with one as the processing
+ * clobbers the error counter so the trigger threshold
+ * check will never be true.
+ */
+ if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
+ ath9k_hw_ani_ofdm_err_trigger(ah);
+ if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
+ ath9k_hw_ani_cck_err_trigger(ah);
+ /* NB: always restart to insure the h/w counters are reset */
+ ath9k_ani_restart(ah);
+ }
+}
+
+void ath9k_hw_ani_setup(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+ const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+ const int coarseLow[] = { -64, -64, -64, -64, -70 };
+ const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+ for (i = 0; i < 5; i++) {
+ ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
+ ahp->ah_coarseHigh[i] = coarseHigh[i];
+ ahp->ah_coarseLow[i] = coarseLow[i];
+ ahp->ah_firpwr[i] = firpwr[i];
+ }
+}
+
+void ath9k_hw_ani_attach(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
+
+ ahp->ah_hasHwPhyCounters = 1;
+
+ memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
+ for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+ ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+ ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+ ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+ ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+ ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+ ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+ ahp->ah_ani[i].ofdmWeakSigDetectOff =
+ !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ ahp->ah_ani[i].cckWeakSigThreshold =
+ ATH9K_ANI_CCK_WEAK_SIG_THR;
+ ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+ ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+ if (ahp->ah_hasHwPhyCounters) {
+ ahp->ah_ani[i].ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+ ahp->ah_ani[i].cckPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+ }
+ }
+ if (ahp->ah_hasHwPhyCounters) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Setting OfdmErrBase = 0x%08x\n",
+ ahp->ah_ani[0].ofdmPhyErrBase);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+ ahp->ah_ani[0].cckPhyErrBase);
+
+ REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+ ath9k_enable_mib_counters(ah);
+ }
+ ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
+ if (ah->ah_config.enable_ani)
+ ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+}
+
+void ath9k_hw_ani_detach(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+
+ if (ahp->ah_hasHwPhyCounters) {
+ ath9k_hw_disable_mib_counters(ah);
+ REG_WRITE(ah, AR_PHY_ERR_1, 0);
+ REG_WRITE(ah, AR_PHY_ERR_2, 0);
+ }
+}
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index accace5f7ef..d2781350295 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -26,6 +26,7 @@
#define AR9160_DEVID_PCI 0x0027
#define AR9280_DEVID_PCI 0x0029
#define AR9280_DEVID_PCIE 0x002a
+#define AR9285_DEVID_PCIE 0x002b
#define AR5416_AR9100_DEVID 0x000b
@@ -138,6 +139,19 @@ struct ath_desc {
#define ATH9K_TXDESC_NOACK 0x0002
#define ATH9K_TXDESC_RTSENA 0x0004
#define ATH9K_TXDESC_CTSENA 0x0008
+/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
+ * the descriptor its marked on. We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt with this flag. Descriptors should be
+ * marked periodically to insure timely replenishing of the
+ * supply needed for sending frames. Defering interrupts
+ * reduces system load and potentially allows more concurrent
+ * work to be done but if done to aggressively can cause
+ * senders to backup. When the hardware queue is left too
+ * large rate control information may also be too out of
+ * date. An Alternative for this is TX interrupt mitigation
+ * but this needs more testing. */
#define ATH9K_TXDESC_INTREQ 0x0010
#define ATH9K_TXDESC_VEOL 0x0020
#define ATH9K_TXDESC_EXT_ONLY 0x0040
@@ -388,22 +402,6 @@ enum ath9k_int {
ATH9K_INT_NOCARD = 0xffffffff
};
-struct ath9k_rate_table {
- int rateCount;
- u8 rateCodeToIndex[256];
- struct {
- u8 valid;
- u8 phy;
- u32 rateKbps;
- u8 rateCode;
- u8 shortPreamble;
- u8 dot11Rate;
- u8 controlRate;
- u16 lpAckDuration;
- u16 spAckDuration;
- } info[32];
-};
-
#define ATH9K_RATESERIES_RTS_CTS 0x0001
#define ATH9K_RATESERIES_2040 0x0002
#define ATH9K_RATESERIES_HALFGI 0x0004
@@ -479,12 +477,10 @@ struct ath9k_channel {
(((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
(((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
(((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
-#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B)
#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
(((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
(((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
(((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0)
#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
@@ -493,6 +489,7 @@ struct ath9k_channel {
#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
/* These macros check chanmode and not channelFlags */
+#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \
((_c)->chanmode == CHANNEL_G_HT20))
#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \
@@ -651,13 +648,6 @@ enum ath9k_ant_setting {
ATH9K_ANT_FIXED_B
};
-enum ath9k_opmode {
- ATH9K_M_STA = 1,
- ATH9K_M_IBSS = 0,
- ATH9K_M_HOSTAP = 6,
- ATH9K_M_MONITOR = 8
-};
-
#define ATH9K_SLOT_TIME_6 6
#define ATH9K_SLOT_TIME_9 9
#define ATH9K_SLOT_TIME_20 20
@@ -689,13 +679,19 @@ enum ath9k_ani_cmd {
ATH9K_ANI_ALL = 0xff
};
-enum phytype {
- PHY_DS,
- PHY_FH,
- PHY_OFDM,
- PHY_HT,
+enum {
+ WLAN_RC_PHY_OFDM,
+ WLAN_RC_PHY_CCK,
+ WLAN_RC_PHY_HT_20_SS,
+ WLAN_RC_PHY_HT_20_DS,
+ WLAN_RC_PHY_HT_40_SS,
+ WLAN_RC_PHY_HT_40_DS,
+ WLAN_RC_PHY_HT_20_SS_HGI,
+ WLAN_RC_PHY_HT_20_DS_HGI,
+ WLAN_RC_PHY_HT_40_SS_HGI,
+ WLAN_RC_PHY_HT_40_DS_HGI,
+ WLAN_RC_PHY_MAX
};
-#define PHY_CCK PHY_DS
enum ath9k_tp_scale {
ATH9K_TP_SCALE_MAX = 0,
@@ -778,7 +774,8 @@ struct ath_hal {
void __iomem *ah_sh;
struct ath_softc *ah_sc;
- enum ath9k_opmode ah_opmode;
+
+ enum nl80211_iftype ah_opmode;
struct ath9k_ops_config ah_config;
struct ath9k_hw_capabilities ah_caps;
@@ -815,195 +812,246 @@ struct chan_centers {
u16 ext_center;
};
-int ath_hal_getcapability(struct ath_hal *ah,
- enum ath9k_capability_type type,
- u32 capability,
- u32 *result);
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
- u32 mode);
-void ath9k_hw_detach(struct ath_hal *ah);
-struct ath_hal *ath9k_hw_attach(u16 devid,
- struct ath_softc *sc,
- void __iomem *mem,
- int *error);
-bool ath9k_regd_init_channels(struct ath_hal *ah,
- u32 maxchans, u32 *nchans,
- u8 *regclassids,
- u32 maxregids, u32 *nregids,
- u16 cc,
- bool enableOutdoor,
- bool enableExtendedChannels);
+struct ath_rate_table;
+
+/* Helpers */
+
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+ const struct ath9k_channel *chan);
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+ u16 flags, u16 *low,
+ u16 *high);
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+ struct ath_rate_table *rates,
+ u32 frameLen, u16 rateix,
+ bool shortPreamble);
u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
- enum ath9k_int ints);
-bool ath9k_hw_reset(struct ath_hal *ah,
- struct ath9k_channel *chan,
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct chan_centers *centers);
+
+/* Attach, Detach */
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_detach(struct ath_hal *ah);
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+ void __iomem *mem, int *error);
+void ath9k_hw_rfdetach(struct ath_hal *ah);
+
+
+/* HW Reset */
+
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode,
u8 txchainmask, u8 rxchainmask,
enum ath9k_ht_extprotspacing extprotspacing,
- bool bChannelChange,
- int *status);
-bool ath9k_hw_phy_disable(struct ath_hal *ah);
-void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
- bool *isCalDone);
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
- const struct ath9k_node_stats *stats,
- struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hal *ah,
- struct ath9k_channel *chan,
- u8 rxchainmask,
- bool longcal,
- bool *isCalDone);
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
- struct ath9k_channel *chan);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
- u16 assocId);
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
- u16 assocId);
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
-void ath9k_hw_reset_tsf(struct ath_hal *ah);
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
- const u8 *mac);
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah,
- u16 entry,
- const struct ath9k_keyval *k,
- const u8 *mac,
- int xorKey);
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah,
- u32 setting);
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
-bool ath9k_hw_intrpend(struct ath_hal *ah);
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah,
- bool bIncTrigLevel);
-void ath9k_hw_procmibevent(struct ath_hal *ah,
- const struct ath9k_node_stats *stats);
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
-bool ath9k_hw_phycounters(struct ath_hal *ah);
+ bool bChannelChange, int *status);
+
+/* Key Cache Management */
+
bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_getcapability(struct ath_hal *ah,
- enum ath9k_capability_type type,
- u32 capability,
- u32 *result);
-bool ath9k_hw_setcapability(struct ath_hal *ah,
- enum ath9k_capability_type type,
- u32 capability,
- u32 setting,
- int *status);
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
-bool ath9k_hw_setbssidmask(struct ath_hal *ah,
- const u8 *mask);
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+ const struct ath9k_keyval *k,
+ const u8 *mac, int xorKey);
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
+
+/* Power Management */
+
bool ath9k_hw_setpower(struct ath_hal *ah,
enum ath9k_power_mode mode);
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
-u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
+
+/* Beacon timers */
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+ const struct ath9k_beacon_state *bs);
+/* HW Capabilities */
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+ u32 capability, u32 *result);
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+ u32 capability, u32 setting, int *status);
+
+/* GPIO / RFKILL / Antennae */
+
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+ u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+void ath9k_enable_rfkill(struct ath_hal *ah);
+#endif
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
enum ath9k_ant_setting settings,
struct ath9k_channel *chan,
u8 *tx_chainmask,
u8 *rx_chainmask,
u8 *antenna_cfgd);
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
-int ath9k_hw_select_antconfig(struct ath_hal *ah,
- u32 cfg);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
- u32 txdp);
+
+/* General Operation */
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
+bool ath9k_hw_phy_disable(struct ath_hal *ah);
+bool ath9k_hw_disable(struct ath_hal *ah);
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
+void ath9k_hw_setopmode(struct ath_hal *ah);
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
+u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_reset_tsf(struct ath_hal *ah);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+
+/* Regulatory */
+
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
+struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah,
+ const struct ath9k_channel *c);
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
+u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+bool ath9k_regd_init_channels(struct ath_hal *ah,
+ u32 maxchans, u32 *nchans, u8 *regclassids,
+ u32 maxregids, u32 *nregids, u16 cc,
+ bool enableOutdoor, bool enableExtendedChannels);
+
+/* ANI */
+
+void ath9k_ani_reset(struct ath_hal *ah);
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats,
+ struct ath9k_channel *chan);
+bool ath9k_hw_phycounters(struct ath_hal *ah);
+void ath9k_enable_mib_counters(struct ath_hal *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+ u32 *rxc_pcnt,
+ u32 *rxf_pcnt,
+ u32 *txf_pcnt);
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats);
+void ath9k_hw_ani_setup(struct ath_hal *ah);
+void ath9k_hw_ani_attach(struct ath_hal *ah);
+void ath9k_hw_ani_detach(struct ath_hal *ah);
+
+/* Calibration */
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+ bool *isCalDone);
+void ath9k_hw_start_nfcal(struct ath_hal *ah);
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal,
+ bool *isCalDone);
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+
+
+/* EEPROM */
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit);
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u8 AntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit);
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset);
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u8 index, u16 *config);
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+ enum ieee80211_band freq_band);
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
+int ath9k_hw_eeprom_attach(struct ath_hal *ah);
+
+/* Interrupt Handling */
+
+bool ath9k_hw_intrpend(struct ath_hal *ah);
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
+
+/* MAC (PCU/QCU) */
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
- const struct ath9k_rate_table *rates,
- u32 frameLen, u16 rateix,
- bool shortPreamble);
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 segLen, bool firstSeg,
+ bool lastSeg, const struct ath_desc *ds0);
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+ u32 keyIx, enum ath9k_key_type keyType, u32 flags);
void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
struct ath_desc *lastds,
u32 durUpdateEn, u32 rtsctsRate,
u32 rtsctsDuration,
struct ath9k_11n_rate_series series[],
u32 nseries, u32 flags);
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah,
- struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+ u32 aggrLen);
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+ u32 numDelims);
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
u32 burstDuration);
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
-u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
-u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
- struct ath9k_channel *chan);
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
- struct ath9k_tx_queue_info *qinfo);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+ u32 vmf);
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
const struct ath9k_tx_queue_info *qinfo);
-struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah,
- const struct ath9k_channel *c);
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 pktLen, enum ath9k_pkt_type type,
- u32 txPower, u32 keyIx,
- enum ath9k_key_type keyType, u32 flags);
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 segLen, bool firstSeg,
- bool lastSeg,
- const struct ath_desc *ds0);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
- u32 *rxc_pcnt,
- u32 *rxf_pcnt,
- u32 *txf_pcnt);
-void ath9k_hw_dmaRegDump(struct ath_hal *ah);
-void ath9k_hw_beaconinit(struct ath_hal *ah,
- u32 next_beacon, u32 beacon_period);
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
- const struct ath9k_beacon_state *bs);
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+ struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+ const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pa, struct ath_desc *nds, u64 tsf);
bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
u32 size, u32 flags);
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
void ath9k_hw_rxena(struct ath_hal *ah);
-void ath9k_hw_setopmode(struct ath_hal *ah);
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
- u32 filter1);
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
void ath9k_hw_startpcureceive(struct ath_hal *ah);
void ath9k_hw_stoppcurecv(struct ath_hal *ah);
bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
-int ath9k_hw_rxprocdesc(struct ath_hal *ah,
- struct ath_desc *ds, u32 pa,
- struct ath_desc *nds, u64 tsf);
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
-int ath9k_hw_txprocdesc(struct ath_hal *ah,
- struct ath_desc *ds);
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
- u32 numDelims);
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
- u32 aggrLen);
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah,
- struct ath_desc *ds, u32 vmf);
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
-bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
- const struct ath9k_tx_queue_info *qinfo);
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
-const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-bool ath9k_hw_disable(struct ath_hal *ah);
-void ath9k_hw_rfdetach(struct ath_hal *ah);
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
- struct ath9k_channel *chan,
- struct chan_centers *centers);
-bool ath9k_get_channel_edges(struct ath_hal *ah,
- u16 flags, u16 *low,
- u16 *high);
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
- u32 ah_signal_type);
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+
#endif
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 9e15c30bbc0..3ab0b43aaf9 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -14,13 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
- /* Implementation of beacon processing. */
-
#include "core.h"
/*
- * Configure parameters for the beacon queue
- *
* This function will modify certain transmit queue properties depending on
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
* settings and channel width min/max
@@ -30,33 +26,38 @@ static int ath_beaconq_config(struct ath_softc *sc)
struct ath_hal *ah = sc->sc_ah;
struct ath9k_tx_queue_info qi;
- ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi);
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+ ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
/* Always burst out beacon and CAB traffic. */
qi.tqi_aifs = 1;
qi.tqi_cwmin = 0;
qi.tqi_cwmax = 0;
} else {
/* Adhoc mode; important thing is to use 2x cwmin. */
- qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs;
- qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin;
- qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax;
+ qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs;
+ qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin;
+ qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax;
}
- if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) {
+ if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to update h/w beacon queue parameters\n",
- __func__);
+ "unable to update h/w beacon queue parameters\n");
return 0;
} else {
- ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
+ ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */
return 1;
}
}
+static void ath_bstuck_process(struct ath_softc *sc)
+{
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "stuck beacon; resetting (bmiss count %u)\n",
+ sc->beacon.bmisscnt);
+ ath_reset(sc, false);
+}
+
/*
- * Setup the beacon frame for transmit.
- *
* Associates the beacon frame buffer with a transmit descriptor. Will set
* up all required antenna switch parameters, rate codes, and channel flags.
* Beacons are always sent out at the lowest rate, and are not retried.
@@ -68,21 +69,20 @@ static void ath_beacon_setup(struct ath_softc *sc,
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
- const struct ath9k_rate_table *rt;
+ struct ath_rate_table *rt;
int flags, antenna;
u8 rix, rate;
int ctsrate = 0;
int ctsduration = 0;
- DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
- __func__, skb, skb->len);
+ DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len);
/* setup descriptors */
ds = bf->bf_desc;
flags = ATH9K_TXDESC_NOACK;
- if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
ds->ds_link = bf->bf_daddr; /* self-linked */
flags |= ATH9K_TXDESC_VEOL;
@@ -96,7 +96,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
* SWBA's
* XXX assumes two antenna
*/
- antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
+ antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
}
ds->ds_data = bf->bf_buf_addr;
@@ -106,15 +106,15 @@ static void ath_beacon_setup(struct ath_softc *sc,
* XXX everything at min xmit rate
*/
rix = 0;
- rt = sc->sc_currates;
- rate = rt->info[rix].rateCode;
+ rt = sc->cur_rate_table;
+ rate = rt->info[rix].ratecode;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- rate |= rt->info[rix].shortPreamble;
+ rate |= rt->info[rix].short_preamble;
ath9k_hw_set11n_txdesc(ah, ds,
skb->len + FCS_LEN, /* frame length */
ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */
- avp->av_btxctl.txpower, /* txpower XXX */
+ MAX_RATE_POWER, /* FIXME */
ATH9K_TXKEYIX_INVALID, /* no encryption */
ATH9K_KEY_TYPE_CLEAR, /* no encryption */
flags /* no ack,
@@ -138,31 +138,26 @@ static void ath_beacon_setup(struct ath_softc *sc,
ctsrate, ctsduration, series, 4, 0);
}
-/*
- * Generate beacon frame and queue cab data for a vap.
- *
- * Updates the contents of the beacon frame. It is assumed that the buffer for
- * the beacon frame has been allocated in the ATH object, and simply needs to
- * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will
- * be added to the beacon frame at this point.
-*/
+/* Generate beacon frame and queue cab data for a vap */
static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
{
struct ath_buf *bf;
struct ath_vap *avp;
struct sk_buff *skb;
struct ath_txq *cabq;
+ struct ieee80211_vif *vif;
struct ieee80211_tx_info *info;
int cabq_depth;
- avp = sc->sc_vaps[if_id];
- ASSERT(avp);
+ vif = sc->sc_vaps[if_id];
+ ASSERT(vif);
- cabq = sc->sc_cabq;
+ avp = (void *)vif->drv_priv;
+ cabq = sc->beacon.cabq;
if (avp->av_bcbuf == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
- __func__, avp, avp->av_bcbuf);
+ DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
+ avp, avp->av_bcbuf);
return NULL;
}
@@ -170,11 +165,12 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
skb = (struct sk_buff *)bf->bf_mpdu;
if (skb) {
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb_end_pointer(skb) - skb->head,
+ skb->len,
PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
}
- skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+ skb = ieee80211_beacon_get(sc->hw, vif);
bf->bf_mpdu = skb;
if (skb == NULL)
return NULL;
@@ -186,17 +182,24 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
* TX frames)
*/
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- sc->seq_no += 0x10;
+ sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}
bf->bf_buf_addr = bf->bf_dmacontext =
pci_map_single(sc->pdev, skb->data,
- skb_end_pointer(skb) - skb->head,
+ skb->len,
PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "pci_dma_mapping_error() on beaconing\n");
+ return NULL;
+ }
- skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
/*
* if the CABQ traffic from previous DTIM is pending and the current
@@ -219,7 +222,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
if (sc->sc_nvaps > 1) {
ath_tx_draintxq(sc, cabq, false);
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: flush previous cabq traffic\n", __func__);
+ "flush previous cabq traffic\n");
}
}
@@ -232,7 +235,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
*/
while (skb) {
ath_tx_cabq(sc, skb);
- skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
}
return bf;
@@ -244,17 +247,20 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
*/
static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
{
+ struct ieee80211_vif *vif;
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
struct ath_vap *avp;
struct sk_buff *skb;
- avp = sc->sc_vaps[if_id];
- ASSERT(avp);
+ vif = sc->sc_vaps[if_id];
+ ASSERT(vif);
+
+ avp = (void *)vif->drv_priv;
if (avp->av_bcbuf == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
- __func__, avp, avp != NULL ? avp->av_bcbuf : NULL);
+ DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
+ avp, avp != NULL ? avp->av_bcbuf : NULL);
return;
}
bf = avp->av_bcbuf;
@@ -264,20 +270,12 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
ath_beacon_setup(sc, avp, bf);
/* NB: caller is known to have already stopped tx dma */
- ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
- ath9k_hw_txstart(ah, sc->sc_bhalq);
- DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__,
- sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc);
+ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
+ ath9k_hw_txstart(ah, sc->beacon.beaconq);
+ DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
+ sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
}
-/*
- * Setup a h/w transmit queue for beacons.
- *
- * This function allocates an information structure (struct ath9k_txq_info)
- * on the stack, sets some specific parameters (zero out channel width
- * min/max, and enable aifs). The info structure does not need to be
- * persistant.
-*/
int ath_beaconq_setup(struct ath_hal *ah)
{
struct ath9k_tx_queue_info qi;
@@ -290,35 +288,29 @@ int ath_beaconq_setup(struct ath_hal *ah)
return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
}
-
-/*
- * Allocate and setup an initial beacon frame.
- *
- * Allocate a beacon state variable for a specific VAP instance created on
- * the ATH interface. This routine also calculates the beacon "slot" for
- * staggared beacons in the mBSSID case.
-*/
int ath_beacon_alloc(struct ath_softc *sc, int if_id)
{
+ struct ieee80211_vif *vif;
struct ath_vap *avp;
struct ieee80211_hdr *hdr;
struct ath_buf *bf;
struct sk_buff *skb;
__le64 tstamp;
- avp = sc->sc_vaps[if_id];
- ASSERT(avp);
+ vif = sc->sc_vaps[if_id];
+ ASSERT(vif);
+
+ avp = (void *)vif->drv_priv;
/* Allocate a beacon descriptor if we haven't done so. */
if (!avp->av_bcbuf) {
/* Allocate beacon state for hostap/ibss. We know
* a buffer is available. */
-
- avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
+ avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf,
struct ath_buf, list);
list_del(&avp->av_bcbuf->list);
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
int slot;
/*
@@ -327,13 +319,13 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
*/
avp->av_bslot = 0;
for (slot = 0; slot < ATH_BCBUF; slot++)
- if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) {
+ if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) {
/*
* XXX hack, space out slots to better
* deal with misses
*/
if (slot+1 < ATH_BCBUF &&
- sc->sc_bslot[slot+1] ==
+ sc->beacon.bslot[slot+1] ==
ATH_IF_ID_ANY) {
avp->av_bslot = slot+1;
break;
@@ -341,8 +333,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
avp->av_bslot = slot;
/* NB: keep looking for a double slot */
}
- BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY);
- sc->sc_bslot[avp->av_bslot] = if_id;
+ BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
+ sc->beacon.bslot[avp->av_bslot] = if_id;
sc->sc_nbcnvaps++;
}
}
@@ -352,7 +344,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
if (bf->bf_mpdu != NULL) {
skb = (struct sk_buff *)bf->bf_mpdu;
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb_end_pointer(skb) - skb->head,
+ skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
@@ -363,15 +355,14 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
* FIXME: Fill avp->av_btxctl.txpower and
* avp->av_btxctl.shortPreamble
*/
- skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+ skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n",
- __func__);
+ DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
return -ENOMEM;
}
tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- sc->bc_tstamp = le64_to_cpu(tstamp);
+ sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
/*
* Calculate a TSF adjustment factor required for
@@ -402,36 +393,36 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: %s beacons, bslot %d intval %u tsfadjust %llu\n",
- __func__, "stagger",
+ "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
avp->av_bslot, intval, (unsigned long long)tsfadjust);
hdr = (struct ieee80211_hdr *)skb->data;
memcpy(&hdr[1], &val, sizeof(val));
}
+ bf->bf_mpdu = skb;
bf->bf_buf_addr = bf->bf_dmacontext =
pci_map_single(sc->pdev, skb->data,
- skb_end_pointer(skb) - skb->head,
+ skb->len,
PCI_DMA_TODEVICE);
- bf->bf_mpdu = skb;
+ if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "pci_dma_mapping_error() on beacon alloc\n");
+ return -ENOMEM;
+ }
return 0;
}
-/*
- * Reclaim beacon resources and return buffer to the pool.
- *
- * Checks the VAP to put the beacon frame buffer back to the ATH object
- * queue, and de-allocates any skbs that were sent as CAB traffic.
-*/
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
{
if (avp->av_bcbuf != NULL) {
struct ath_buf *bf;
if (avp->av_bslot != -1) {
- sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY;
+ sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
sc->sc_nbcnvaps--;
}
@@ -439,24 +430,17 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb_end_pointer(skb) - skb->head,
+ skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
- list_add_tail(&bf->list, &sc->sc_bbuf);
+ list_add_tail(&bf->list, &sc->beacon.bbuf);
avp->av_bcbuf = NULL;
}
}
-/*
- * Tasklet for Sending Beacons
- *
- * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame
- * contents are done as needed and the slot time is also adjusted based on
- * current state.
-*/
void ath9k_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -473,9 +457,7 @@ void ath9k_beacon_tasklet(unsigned long data)
if (sc->sc_flags & SC_OP_NO_RESET) {
show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
- &rx_clear,
- &rx_frame,
- &tx_frame);
+ &rx_clear, &rx_frame, &tx_frame);
}
/*
@@ -487,67 +469,65 @@ void ath9k_beacon_tasklet(unsigned long data)
*
* FIXME: Clean up this mess !!
*/
- if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
- sc->sc_bmisscount++;
+ if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
+ sc->beacon.bmisscnt++;
/* XXX: doth needs the chanchange IE countdown decremented.
* We should consider adding a mac80211 call to indicate
* a beacon miss so appropriate action could be taken
* (in that layer).
*/
- if (sc->sc_bmisscount < BSTUCK_THRESH) {
+ if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
if (sc->sc_flags & SC_OP_NO_RESET) {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: missed %u consecutive beacons\n",
- __func__, sc->sc_bmisscount);
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
if (show_cycles) {
/*
* Display cycle counter stats from HW
* to aide in debug of stickiness.
*/
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: busy times: rx_clear=%d, "
+ "busy times: rx_clear=%d, "
"rx_frame=%d, tx_frame=%d\n",
- __func__, rx_clear, rx_frame,
+ rx_clear, rx_frame,
tx_frame);
} else {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: unable to obtain "
- "busy times\n", __func__);
+ "unable to obtain "
+ "busy times\n");
}
} else {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: missed %u consecutive beacons\n",
- __func__, sc->sc_bmisscount);
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
}
- } else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
+ } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
if (sc->sc_flags & SC_OP_NO_RESET) {
- if (sc->sc_bmisscount == BSTUCK_THRESH) {
+ if (sc->beacon.bmisscnt == BSTUCK_THRESH) {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: beacon is officially "
- "stuck\n", __func__);
- ath9k_hw_dmaRegDump(ah);
+ "beacon is officially "
+ "stuck\n");
}
} else {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: beacon is officially stuck\n",
- __func__);
+ "beacon is officially stuck\n");
ath_bstuck_process(sc);
}
}
return;
}
- if (sc->sc_bmisscount != 0) {
+ if (sc->beacon.bmisscnt != 0) {
if (sc->sc_flags & SC_OP_NO_RESET) {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: resume beacon xmit after %u misses\n",
- __func__, sc->sc_bmisscount);
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
} else {
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: resume beacon xmit after %u misses\n",
- __func__, sc->sc_bmisscount);
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
}
- sc->sc_bmisscount = 0;
+ sc->beacon.bmisscnt = 0;
}
/*
@@ -562,11 +542,11 @@ void ath9k_beacon_tasklet(unsigned long data)
tsf = ath9k_hw_gettsf64(ah);
tsftu = TSF_TO_TU(tsf>>32, tsf);
slot = ((tsftu % intval) * ATH_BCBUF) / intval;
- if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
+ if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
- __func__, slot, (unsigned long long)tsf, tsftu,
+ "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
+ slot, (unsigned long long)tsf, tsftu,
intval, if_id);
bfaddr = 0;
@@ -594,48 +574,34 @@ void ath9k_beacon_tasklet(unsigned long data)
* set to ATH_BCBUF so this check is a noop.
*/
/* XXX locking */
- if (sc->sc_updateslot == UPDATE) {
- sc->sc_updateslot = COMMIT; /* commit next beacon */
- sc->sc_slotupdate = slot;
- } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
- ath_setslottime(sc); /* commit change to hardware */
-
+ if (sc->beacon.updateslot == UPDATE) {
+ sc->beacon.updateslot = COMMIT; /* commit next beacon */
+ sc->beacon.slotupdate = slot;
+ } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
+ ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
+ sc->beacon.updateslot = OK;
+ }
if (bfaddr != 0) {
/*
* Stop any current dma and put the new frame(s) on the queue.
* This should never fail since we check above that no frames
* are still pending on the queue.
*/
- if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) {
+ if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: beacon queue %u did not stop?\n",
- __func__, sc->sc_bhalq);
+ "beacon queue %u did not stop?\n", sc->beacon.beaconq);
/* NB: the HAL still stops DMA, so proceed */
}
/* NB: cabq traffic should already be queued and primed */
- ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr);
- ath9k_hw_txstart(ah, sc->sc_bhalq);
+ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
+ ath9k_hw_txstart(ah, sc->beacon.beaconq);
- sc->ast_be_xmit += bc; /* XXX per-vap? */
+ sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */
}
}
/*
- * Tasklet for Beacon Stuck processing
- *
- * Processing for Beacon Stuck.
- * Basically resets the chip.
-*/
-void ath_bstuck_process(struct ath_softc *sc)
-{
- DPRINTF(sc, ATH_DBG_BEACON,
- "%s: stuck beacon; resetting (bmiss count %u)\n",
- __func__, sc->sc_bmisscount);
- ath_reset(sc, false);
-}
-
-/*
* Configure the beacon and sleep timers.
*
* When operating as an AP this resets the TSF and sets
@@ -652,15 +618,21 @@ void ath_bstuck_process(struct ath_softc *sc)
*/
void ath_beacon_config(struct ath_softc *sc, int if_id)
{
+ struct ieee80211_vif *vif;
struct ath_hal *ah = sc->sc_ah;
struct ath_beacon_config conf;
- enum ath9k_opmode av_opmode;
+ struct ath_vap *avp;
+ enum nl80211_iftype opmode;
u32 nexttbtt, intval;
- if (if_id != ATH_IF_ID_ANY)
- av_opmode = sc->sc_vaps[if_id]->av_opmode;
- else
- av_opmode = sc->sc_ah->ah_opmode;
+ if (if_id != ATH_IF_ID_ANY) {
+ vif = sc->sc_vaps[if_id];
+ ASSERT(vif);
+ avp = (void *)vif->drv_priv;
+ opmode = avp->av_opmode;
+ } else {
+ opmode = sc->sc_ah->ah_opmode;
+ }
memset(&conf, 0, sizeof(struct ath_beacon_config));
@@ -672,10 +644,10 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
/* extract tstamp from last beacon and convert to TU */
- nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp);
+ nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
/* XXX conditionalize multi-bss support? */
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
/*
* For multi-bss ap support beacons are either staggered
* evenly over N slots or burst together. For the former
@@ -694,11 +666,11 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
else if (intval) /* NB: can be 0 for monitor mode */
nexttbtt = roundup(nexttbtt, intval);
- DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
- __func__, nexttbtt, intval, conf.beacon_interval);
+ DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n",
+ nexttbtt, intval, conf.beacon_interval);
- /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
- if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
+ /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) {
struct ath9k_beacon_state bs;
u64 tsf;
u32 tsftu;
@@ -782,7 +754,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
bs.bs_sleepduration = bs.bs_dtimperiod;
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: tsf %llu "
+ "tsf %llu "
"tsf:tu %u "
"intval %u "
"nexttbtt %u "
@@ -794,7 +766,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
"maxdur %u "
"next %u "
"timoffset %u\n",
- __func__,
(unsigned long long)tsf, tsftu,
bs.bs_intval,
bs.bs_nexttbtt,
@@ -818,7 +789,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
ath9k_hw_set_interrupts(ah, 0);
if (nexttbtt == intval)
intval |= ATH9K_BEACON_RESET_TSF;
- if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
/*
* Pull nexttbtt forward to reflect the current
* TSF
@@ -834,8 +805,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
}
#undef FUDGE
DPRINTF(sc, ATH_DBG_BEACON,
- "%s: IBSS nexttbtt %u intval %u (%u)\n",
- __func__, nexttbtt,
+ "IBSS nexttbtt %u intval %u (%u)\n",
+ nexttbtt,
intval & ~ATH9K_BEACON_RESET_TSF,
conf.beacon_interval);
@@ -850,7 +821,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
sc->sc_imask |= ATH9K_INT_SWBA;
ath_beaconq_config(sc);
- } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
+ } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
/*
* In AP mode we enable the beacon timers and
* SWBA interrupts to prepare beacon frames.
@@ -860,20 +831,18 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
ath_beaconq_config(sc);
}
ath9k_hw_beaconinit(ah, nexttbtt, intval);
- sc->sc_bmisscount = 0;
+ sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, sc->sc_imask);
/*
* When using a self-linked beacon descriptor in
* ibss mode load it once here.
*/
- if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC &&
(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
ath_beacon_start_adhoc(sc, 0);
}
}
-/* Function to collect beacon rssi data and resync beacon if necessary */
-
void ath_beacon_sync(struct ath_softc *sc, int if_id)
{
/*
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c
new file mode 100644
index 00000000000..3c7454fc51b
--- /dev/null
+++ b/drivers/net/wireless/ath9k/calib.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
+
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW -60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+ if (nf > ATH9K_NF_TOO_LOW) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "noise floor value detected (%d) is "
+ "lower than what we think is a "
+ "reasonable value (%d)\n",
+ nf, ATH9K_NF_TOO_LOW);
+ return false;
+ }
+ return true;
+}
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+ int16_t nfval;
+ int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+ int i, j;
+
+ for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+ sort[i] = nfCalBuffer[i];
+
+ for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+ for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+ if (sort[j] > sort[j - 1]) {
+ nfval = sort[j];
+ sort[j] = sort[j - 1];
+ sort[j - 1] = nfval;
+ }
+ }
+ }
+ nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+ return nfval;
+}
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+ int16_t *nfarray)
+{
+ int i;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+ if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+ h[i].currIndex = 0;
+
+ if (h[i].invalidNFcount > 0) {
+ if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
+ nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+ h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+ } else {
+ h[i].invalidNFcount--;
+ h[i].privNF = nfarray[i];
+ }
+ } else {
+ h[i].privNF =
+ ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+ }
+ }
+ return;
+}
+
+static void ath9k_hw_do_getnf(struct ath_hal *ah,
+ int16_t nfarray[NUM_NF_READINGS])
+{
+ int16_t nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 0] is %d\n", nf);
+ nfarray[0] = nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+ AR9280_PHY_CH1_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+ AR_PHY_CH1_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 1] is %d\n", nf);
+ nfarray[1] = nf;
+
+ if (!AR_SREV_9280(ah)) {
+ nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
+ AR_PHY_CH2_MINCCA_PWR);
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 2] is %d\n", nf);
+ nfarray[2] = nf;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+ AR9280_PHY_EXT_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+ AR_PHY_EXT_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 0] is %d\n", nf);
+ nfarray[3] = nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+ AR9280_PHY_CH1_EXT_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+ AR_PHY_CH1_EXT_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 1] is %d\n", nf);
+ nfarray[4] = nf;
+
+ if (!AR_SREV_9280(ah)) {
+ nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
+ AR_PHY_CH2_EXT_MINCCA_PWR);
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 2] is %d\n", nf);
+ nfarray[5] = nf;
+ }
+}
+
+static bool getNoiseFloorThresh(struct ath_hal *ah,
+ const struct ath9k_channel *chan,
+ int16_t *nft)
+{
+ switch (chan->chanmode) {
+ case CHANNEL_A:
+ case CHANNEL_A_HT20:
+ case CHANNEL_A_HT40PLUS:
+ case CHANNEL_A_HT40MINUS:
+ *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+ break;
+ case CHANNEL_B:
+ case CHANNEL_G:
+ case CHANNEL_G_HT20:
+ case CHANNEL_G_HT40PLUS:
+ case CHANNEL_G_HT40MINUS:
+ *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "invalid channel flags 0x%x\n", chan->channelFlags);
+ return false;
+ }
+
+ return true;
+}
+
+static void ath9k_hw_setup_calibration(struct ath_hal *ah,
+ struct hal_cal_list *currCal)
+{
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+ currCal->calData->calCountMax);
+
+ switch (currCal->calData->calType) {
+ case IQ_MISMATCH_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "starting IQ Mismatch Calibration\n");
+ break;
+ case ADC_GAIN_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "starting ADC Gain Calibration\n");
+ break;
+ case ADC_DC_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "starting ADC DC Calibration\n");
+ break;
+ case ADC_DC_INIT_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "starting Init ADC DC Calibration\n");
+ break;
+ }
+
+ REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+ struct hal_cal_list *currCal)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ ath9k_hw_setup_calibration(ah, currCal);
+
+ currCal->calState = CAL_RUNNING;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_Meas0.sign[i] = 0;
+ ahp->ah_Meas1.sign[i] = 0;
+ ahp->ah_Meas2.sign[i] = 0;
+ ahp->ah_Meas3.sign[i] = 0;
+ }
+
+ ahp->ah_CalSamples = 0;
+}
+
+static void ath9k_hw_per_calibration(struct ath_hal *ah,
+ struct ath9k_channel *ichan,
+ u8 rxchainmask,
+ struct hal_cal_list *currCal,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ *isCalDone = false;
+
+ if (currCal->calState == CAL_RUNNING) {
+ if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+ AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+ currCal->calData->calCollect(ah);
+ ahp->ah_CalSamples++;
+
+ if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
+ int i, numChains = 0;
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (rxchainmask & (1 << i))
+ numChains++;
+ }
+
+ currCal->calData->calPostProc(ah, numChains);
+ ichan->CalValid |= currCal->calData->calType;
+ currCal->calState = CAL_DONE;
+ *isCalDone = true;
+ } else {
+ ath9k_hw_setup_calibration(ah, currCal);
+ }
+ }
+ } else if (!(ichan->CalValid & currCal->calData->calType)) {
+ ath9k_hw_reset_calibration(ah, currCal);
+ }
+}
+
+static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum hal_cal_types calType)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ bool retval = false;
+
+ switch (calType & ahp->ah_suppCals) {
+ case IQ_MISMATCH_CAL:
+ if (!IS_CHAN_B(chan))
+ retval = true;
+ break;
+ case ADC_GAIN_CAL:
+ case ADC_DC_CAL:
+ if (!IS_CHAN_B(chan)
+ && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ retval = true;
+ break;
+ }
+
+ return retval;
+}
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalPowerMeasI[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalPowerMeasQ[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalIqCorrMeas[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
+ ahp->ah_totalPowerMeasQ[i],
+ ahp->ah_totalIqCorrMeas[i]);
+ }
+}
+
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcIOddPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcIEvenPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcQOddPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_totalAdcQEvenPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ahp->ah_CalSamples, i,
+ ahp->ah_totalAdcIOddPhase[i],
+ ahp->ah_totalAdcIEvenPhase[i],
+ ahp->ah_totalAdcQOddPhase[i],
+ ahp->ah_totalAdcQEvenPhase[i]);
+ }
+}
+
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ahp->ah_CalSamples, i,
+ ahp->ah_totalAdcDcOffsetIOddPhase[i],
+ ahp->ah_totalAdcDcOffsetIEvenPhase[i],
+ ahp->ah_totalAdcDcOffsetQOddPhase[i],
+ ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+ }
+}
+
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 powerMeasQ, powerMeasI, iqCorrMeas;
+ u32 qCoffDenom, iCoffDenom;
+ int32_t qCoff, iCoff;
+ int iqCorrNeg, i;
+
+ for (i = 0; i < numChains; i++) {
+ powerMeasI = ahp->ah_totalPowerMeasI[i];
+ powerMeasQ = ahp->ah_totalPowerMeasQ[i];
+ iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ahp->ah_totalIqCorrMeas[i]);
+
+ iqCorrNeg = 0;
+
+ if (iqCorrMeas > 0x80000000) {
+ iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+ iqCorrNeg = 1;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
+
+ iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+ qCoffDenom = powerMeasQ / 64;
+
+ if (powerMeasQ != 0) {
+ iCoff = iqCorrMeas / iCoffDenom;
+ qCoff = powerMeasI / qCoffDenom - 64;
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+ iCoff = iCoff & 0x3f;
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+ if (iqCorrNeg == 0x0)
+ iCoff = 0x40 - iCoff;
+
+ if (qCoff > 15)
+ qCoff = 15;
+ else if (qCoff <= -16)
+ qCoff = 16;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
+
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+ iCoff);
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+ qCoff);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n",
+ i);
+ }
+ }
+
+ REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+ u32 qGainMismatch, iGainMismatch, val, i;
+
+ for (i = 0; i < numChains; i++) {
+ iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
+ iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
+ qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
+ qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting ADC Gain Cal for Chain %d\n", i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+ iOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+ iEvenMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+ qOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+ qEvenMeasOffset);
+
+ if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+ iGainMismatch =
+ ((iEvenMeasOffset * 32) /
+ iOddMeasOffset) & 0x3f;
+ qGainMismatch =
+ ((qOddMeasOffset * 32) /
+ qEvenMeasOffset) & 0x3f;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_i = 0x%08x\n", i,
+ iGainMismatch);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_q = 0x%08x\n", i,
+ qGainMismatch);
+
+ val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+ val &= 0xfffff000;
+ val |= (qGainMismatch) | (iGainMismatch << 6);
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "ADC Gain Cal done for Chain %d\n", i);
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+ REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+ AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+ int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+ const struct hal_percal_data *calData =
+ ahp->ah_cal_list_curr->calData;
+ u32 numSamples =
+ (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+ for (i = 0; i < numChains; i++) {
+ iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
+ iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
+ qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
+ qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = %d\n", i,
+ iOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = %d\n", i,
+ iEvenMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = %d\n", i,
+ qOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = %d\n", i,
+ qEvenMeasOffset);
+
+ iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+ numSamples) & 0x1ff;
+ qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+ numSamples) & 0x1ff;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+ iDcMismatch);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+ qDcMismatch);
+
+ val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+ val &= 0xc0000fff;
+ val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "ADC DC Offset Cal done for Chain %d\n", i);
+ }
+
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+ REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+ AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *ichan =
+ ath9k_regd_check_channel(ah, chan);
+ struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+
+ *isCalDone = true;
+
+ if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+ return;
+
+ if (currCal == NULL)
+ return;
+
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "invalid channel %u/0x%x; no mapping\n",
+ chan->channel, chan->channelFlags);
+ return;
+ }
+
+
+ if (currCal->calState != CAL_DONE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Calibration state incorrect, %d\n",
+ currCal->calState);
+ return;
+ }
+
+
+ if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
+ return;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Resetting Cal %d state for channel %u/0x%x\n",
+ currCal->calData->calType, chan->channel,
+ chan->channelFlags);
+
+ ichan->CalValid &= ~currCal->calData->calType;
+ currCal->calState = CAL_WAITING;
+
+ *isCalDone = false;
+}
+
+void ath9k_hw_start_nfcal(struct ath_hal *ah)
+{
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_nfcal_hist *h;
+ int i, j;
+ int32_t val;
+ const u32 ar5416_cca_regs[6] = {
+ AR_PHY_CCA,
+ AR_PHY_CH1_CCA,
+ AR_PHY_CH2_CCA,
+ AR_PHY_EXT_CCA,
+ AR_PHY_CH1_EXT_CCA,
+ AR_PHY_CH2_EXT_CCA
+ };
+ u8 chainmask;
+
+ if (AR_SREV_9280(ah))
+ chainmask = 0x1B;
+ else
+ chainmask = 0x3F;
+
+#ifdef ATH_NF_PER_CHAN
+ h = chan->nfCalHist;
+#else
+ h = ah->nfCalHist;
+#endif
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ar5416_cca_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+ REG_WRITE(ah, ar5416_cca_regs[i], val);
+ }
+ }
+
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+ for (j = 0; j < 1000; j++) {
+ if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_NF) == 0)
+ break;
+ udelay(10);
+ }
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ar5416_cca_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (-50) << 1) & 0x1ff);
+ REG_WRITE(ah, ar5416_cca_regs[i], val);
+ }
+ }
+}
+
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ int16_t nf, nfThresh;
+ int16_t nfarray[NUM_NF_READINGS] = { 0 };
+ struct ath9k_nfcal_hist *h;
+ u8 chainmask;
+
+ if (AR_SREV_9280(ah))
+ chainmask = 0x1B;
+ else
+ chainmask = 0x3F;
+
+ chan->channelFlags &= (~CHANNEL_CW_INT);
+ if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF did not complete in calibration window\n");
+ nf = 0;
+ chan->rawNoiseFloor = nf;
+ return chan->rawNoiseFloor;
+ } else {
+ ath9k_hw_do_getnf(ah, nfarray);
+ nf = nfarray[0];
+ if (getNoiseFloorThresh(ah, chan, &nfThresh)
+ && nf > nfThresh) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "noise floor failed detected; "
+ "detected %d, threshold %d\n",
+ nf, nfThresh);
+ chan->channelFlags |= CHANNEL_CW_INT;
+ }
+ }
+
+#ifdef ATH_NF_PER_CHAN
+ h = chan->nfCalHist;
+#else
+ h = ah->nfCalHist;
+#endif
+
+ ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+ chan->rawNoiseFloor = h[0].privNF;
+
+ return chan->rawNoiseFloor;
+}
+
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+{
+ int i, j;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ ah->nfCalHist[i].currIndex = 0;
+ ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].invalidNFcount =
+ AR_PHY_CCA_FILTERWINDOW_LENGTH;
+ for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+ ah->nfCalHist[i].nfCalBuffer[j] =
+ AR_PHY_CCA_MAX_GOOD_VALUE;
+ }
+ }
+ return;
+}
+
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_channel *ichan;
+ s16 nf;
+
+ ichan = ath9k_regd_check_channel(ah, chan);
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "invalid channel %u/0x%x; no mapping\n",
+ chan->channel, chan->channelFlags);
+ return ATH_DEFAULT_NOISE_FLOOR;
+ }
+ if (ichan->rawNoiseFloor == 0) {
+ enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
+ nf = NOISE_FLOOR[mode];
+ } else
+ nf = ichan->rawNoiseFloor;
+
+ if (!ath9k_hw_nf_in_range(ah, nf))
+ nf = ATH_DEFAULT_NOISE_FLOOR;
+
+ return nf;
+}
+
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+ struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+ *isCalDone = true;
+
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "invalid channel %u/0x%x; no mapping\n",
+ chan->channel, chan->channelFlags);
+ return false;
+ }
+
+ if (currCal &&
+ (currCal->calState == CAL_RUNNING ||
+ currCal->calState == CAL_WAITING)) {
+ ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
+ isCalDone);
+ if (*isCalDone) {
+ ahp->ah_cal_list_curr = currCal = currCal->calNext;
+
+ if (currCal->calState == CAL_WAITING) {
+ *isCalDone = false;
+ ath9k_hw_reset_calibration(ah, currCal);
+ }
+ }
+ }
+
+ if (longcal) {
+ ath9k_hw_getnf(ah, ichan);
+ ath9k_hw_loadnf(ah, ah->ah_curchan);
+ ath9k_hw_start_nfcal(ah);
+
+ if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+ chan->channelFlags |= CHANNEL_CW_INT;
+ ichan->channelFlags &= ~CHANNEL_CW_INT;
+ }
+ }
+
+ return true;
+}
+
+static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah)
+{
+
+ u32 regVal;
+ int i, offset, offs_6_1, offs_0;
+ u32 ccomp_org, reg_field;
+ u32 regList[][2] = {
+ { 0x786c, 0 },
+ { 0x7854, 0 },
+ { 0x7820, 0 },
+ { 0x7824, 0 },
+ { 0x7868, 0 },
+ { 0x783c, 0 },
+ { 0x7838, 0 },
+ };
+
+ if (AR_SREV_9285_11(ah)) {
+ REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+ udelay(10);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1));
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal |= (0x1 << 27);
+ REG_WRITE(ah, 0x9808, regVal);
+
+ REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+ ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
+
+ REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+ udelay(30);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
+
+ for (i = 6; i > 0; i--) {
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= (1 << (19 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ udelay(1);
+ regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1 << (19 + i)));
+ reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
+ regVal |= (reg_field << (19 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ }
+
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
+ udelay(1);
+ reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
+ offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
+ offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
+
+ offset = (offs_6_1<<1) | offs_0;
+ offset = offset - 0;
+ offs_6_1 = offset>>1;
+ offs_0 = offset & 1;
+
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= 0x1;
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal &= (~(0x1 << 27));
+ REG_WRITE(ah, 0x9808, regVal);
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
+
+ if (AR_SREV_9285_11(ah))
+ REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+}
+
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_CAL);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "offset calibration failed to complete in 1ms; "
+ "noisy environment?\n");
+ return false;
+ }
+
+ if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
+ ath9k_hw_9285_pa_cal(ah);
+
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_NF);
+
+ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+
+ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+ if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
+ INIT_CAL(&ahp->ah_adcGainCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "enabling ADC Gain Calibration.\n");
+ }
+ if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
+ INIT_CAL(&ahp->ah_adcDcCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "enabling ADC DC Calibration.\n");
+ }
+ if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+ INIT_CAL(&ahp->ah_iqCalData);
+ INSERT_CAL(ahp, &ahp->ah_iqCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
+ }
+
+ ahp->ah_cal_list_curr = ahp->ah_cal_list;
+
+ if (ahp->ah_cal_list_curr)
+ ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
+ }
+
+ ichan->CalValid = 0;
+
+ return true;
+}
+
+const struct hal_percal_data iq_cal_multi_sample = {
+ IQ_MISMATCH_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_iqcal_collect,
+ ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data iq_cal_single_sample = {
+ IQ_MISMATCH_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_iqcal_collect,
+ ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data adc_gain_cal_multi_sample = {
+ ADC_GAIN_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_adc_gaincal_collect,
+ ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_gain_cal_single_sample = {
+ ADC_GAIN_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_adc_gaincal_collect,
+ ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_multi_sample = {
+ ADC_DC_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_single_sample = {
+ ADC_DC_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_init_dc_cal = {
+ ADC_DC_INIT_CAL,
+ MIN_CAL_SAMPLES,
+ INIT_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
deleted file mode 100644
index c5033f6f42a..00000000000
--- a/drivers/net/wireless/ath9k/core.c
+++ /dev/null
@@ -1,1886 +0,0 @@
-/*
- * Copyright (c) 2008, Atheros Communications Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- /* Implementation of the main "ATH" layer. */
-
-#include "core.h"
-#include "regd.h"
-
-static int ath_outdoor; /* enable outdoor use */
-
-static u32 ath_chainmask_sel_up_rssi_thres =
- ATH_CHAINMASK_SEL_UP_RSSI_THRES;
-static u32 ath_chainmask_sel_down_rssi_thres =
- ATH_CHAINMASK_SEL_DOWN_RSSI_THRES;
-static u32 ath_chainmask_sel_period =
- ATH_CHAINMASK_SEL_TIMEOUT;
-
-/* return bus cachesize in 4B word units */
-
-static void bus_read_cachesize(struct ath_softc *sc, int *csz)
-{
- u8 u8tmp;
-
- pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
- *csz = (int)u8tmp;
-
- /*
- * This check was put in to avoid "unplesant" consequences if
- * the bootrom has not fully initialized all PCI devices.
- * Sometimes the cache line size register is not set
- */
-
- if (*csz == 0)
- *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
-}
-
-/*
- * Set current operating mode
- *
- * This function initializes and fills the rate table in the ATH object based
- * on the operating mode.
-*/
-static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
-{
- const struct ath9k_rate_table *rt;
- int i;
-
- memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
- rt = ath9k_hw_getratetable(sc->sc_ah, mode);
- BUG_ON(!rt);
-
- for (i = 0; i < rt->rateCount; i++)
- sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
-
- memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap));
- for (i = 0; i < 256; i++) {
- u8 ix = rt->rateCodeToIndex[i];
-
- if (ix == 0xff)
- continue;
-
- sc->sc_hwmap[i].ieeerate =
- rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
- sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps;
-
- if (rt->info[ix].shortPreamble ||
- rt->info[ix].phy == PHY_OFDM) {
- /* XXX: Handle this */
- }
-
- /* NB: this uses the last entry if the rate isn't found */
- /* XXX beware of overlow */
- }
- sc->sc_currates = rt;
- sc->sc_curmode = mode;
- /*
- * All protection frames are transmited at 2Mb/s for
- * 11g, otherwise at 1Mb/s.
- * XXX select protection rate index from rate table.
- */
- sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
-}
-
-/*
- * Set up rate table (legacy rates)
- */
-static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
-{
- struct ath_hal *ah = sc->sc_ah;
- const struct ath9k_rate_table *rt = NULL;
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate;
- int i, maxrates;
-
- switch (band) {
- case IEEE80211_BAND_2GHZ:
- rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G);
- break;
- case IEEE80211_BAND_5GHZ:
- rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A);
- break;
- default:
- break;
- }
-
- if (rt == NULL)
- return;
-
- sband = &sc->sbands[band];
- rate = sc->rates[band];
-
- if (rt->rateCount > ATH_RATE_MAX)
- maxrates = ATH_RATE_MAX;
- else
- maxrates = rt->rateCount;
-
- for (i = 0; i < maxrates; i++) {
- rate[i].bitrate = rt->info[i].rateKbps / 100;
- rate[i].hw_value = rt->info[i].rateCode;
- sband->n_bitrates++;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Rate: %2dMbps, ratecode: %2d\n",
- __func__,
- rate[i].bitrate / 10,
- rate[i].hw_value);
- }
-}
-
-/*
- * Set up channel list
- */
-static int ath_setup_channels(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
- int nchan, i, a = 0, b = 0;
- u8 regclassids[ATH_REGCLASSIDS_MAX];
- u32 nregclass = 0;
- struct ieee80211_supported_band *band_2ghz;
- struct ieee80211_supported_band *band_5ghz;
- struct ieee80211_channel *chan_2ghz;
- struct ieee80211_channel *chan_5ghz;
- struct ath9k_channel *c;
-
- /* Fill in ah->ah_channels */
- if (!ath9k_regd_init_channels(ah,
- ATH_CHAN_MAX,
- (u32 *)&nchan,
- regclassids,
- ATH_REGCLASSIDS_MAX,
- &nregclass,
- CTRY_DEFAULT,
- false,
- 1)) {
- u32 rd = ah->ah_currentRD;
-
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to collect channel list; "
- "regdomain likely %u country code %u\n",
- __func__, rd, CTRY_DEFAULT);
- return -EINVAL;
- }
-
- band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
- band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
- chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
- chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
-
- for (i = 0; i < nchan; i++) {
- c = &ah->ah_channels[i];
- if (IS_CHAN_2GHZ(c)) {
- chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
- chan_2ghz[a].center_freq = c->channel;
- chan_2ghz[a].max_power = c->maxTxPower;
-
- if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
- chan_2ghz[a].flags |=
- IEEE80211_CHAN_NO_IBSS;
- if (c->channelFlags & CHANNEL_PASSIVE)
- chan_2ghz[a].flags |=
- IEEE80211_CHAN_PASSIVE_SCAN;
-
- band_2ghz->n_channels = ++a;
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: 2MHz channel: %d, "
- "channelFlags: 0x%x\n",
- __func__,
- c->channel,
- c->channelFlags);
- } else if (IS_CHAN_5GHZ(c)) {
- chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
- chan_5ghz[b].center_freq = c->channel;
- chan_5ghz[b].max_power = c->maxTxPower;
-
- if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
- chan_5ghz[b].flags |=
- IEEE80211_CHAN_NO_IBSS;
- if (c->channelFlags & CHANNEL_PASSIVE)
- chan_5ghz[b].flags |=
- IEEE80211_CHAN_PASSIVE_SCAN;
-
- band_5ghz->n_channels = ++b;
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: 5MHz channel: %d, "
- "channelFlags: 0x%x\n",
- __func__,
- c->channel,
- c->channelFlags);
- }
- }
-
- return 0;
-}
-
-/*
- * Determine mode from channel flags
- *
- * This routine will provide the enumerated WIRELESSS_MODE value based
- * on the settings of the channel flags. If no valid set of flags
- * exist, the lowest mode (11b) is selected.
-*/
-
-static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
-{
- if (chan->chanmode == CHANNEL_A)
- return ATH9K_MODE_11A;
- else if (chan->chanmode == CHANNEL_G)
- return ATH9K_MODE_11G;
- else if (chan->chanmode == CHANNEL_B)
- return ATH9K_MODE_11B;
- else if (chan->chanmode == CHANNEL_A_HT20)
- return ATH9K_MODE_11NA_HT20;
- else if (chan->chanmode == CHANNEL_G_HT20)
- return ATH9K_MODE_11NG_HT20;
- else if (chan->chanmode == CHANNEL_A_HT40PLUS)
- return ATH9K_MODE_11NA_HT40PLUS;
- else if (chan->chanmode == CHANNEL_A_HT40MINUS)
- return ATH9K_MODE_11NA_HT40MINUS;
- else if (chan->chanmode == CHANNEL_G_HT40PLUS)
- return ATH9K_MODE_11NG_HT40PLUS;
- else if (chan->chanmode == CHANNEL_G_HT40MINUS)
- return ATH9K_MODE_11NG_HT40MINUS;
-
- WARN_ON(1); /* should not get here */
-
- return ATH9K_MODE_11B;
-}
-
-/*
- * Stop the device, grabbing the top-level lock to protect
- * against concurrent entry through ath_init (which can happen
- * if another thread does a system call and the thread doing the
- * stop is preempted).
- */
-
-static int ath_stop(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
- __func__, sc->sc_flags & SC_OP_INVALID);
-
- /*
- * Shutdown the hardware and driver:
- * stop output from above
- * turn off timers
- * disable interrupts
- * clear transmit machinery
- * clear receive machinery
- * turn off the radio
- * reclaim beacon resources
- *
- * Note that some of this work is not possible if the
- * hardware is gone (invalid).
- */
-
- ath_draintxq(sc, false);
- if (!(sc->sc_flags & SC_OP_INVALID)) {
- ath_stoprecv(sc);
- ath9k_hw_phy_disable(ah);
- } else
- sc->sc_rxlink = NULL;
-
- return 0;
-}
-
-/*
- * Set the current channel
- *
- * Set/change channels. If the channel is really being changed, it's done
- * by reseting the chip. To accomplish this we must first cleanup any pending
- * DMA, then restart stuff after a la ath_init.
-*/
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
-{
- struct ath_hal *ah = sc->sc_ah;
- bool fastcc = true, stopped;
-
- if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */
- return -EIO;
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
- __func__,
- ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel,
- sc->sc_ah->ah_curchan->channelFlags),
- sc->sc_ah->ah_curchan->channel,
- ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
- hchan->channel, hchan->channelFlags);
-
- if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
- hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
- (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
- (sc->sc_flags & SC_OP_FULL_RESET)) {
- int status;
- /*
- * This is only performed if the channel settings have
- * actually changed.
- *
- * To switch channels clear any pending DMA operations;
- * wait long enough for the RX fifo to drain, reset the
- * hardware at the new frequency, and then re-enable
- * the relevant bits of the h/w.
- */
- ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
- ath_draintxq(sc, false); /* clear pending tx frames */
- stopped = ath_stoprecv(sc); /* turn off frame recv */
-
- /* XXX: do not flush receive queue here. We don't want
- * to flush data frames already in queue because of
- * changing channel. */
-
- if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
- fastcc = false;
-
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, hchan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask,
- sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing,
- fastcc, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset channel %u (%uMhz) "
- "flags 0x%x hal status %u\n", __func__,
- ath9k_hw_mhz2ieee(ah, hchan->channel,
- hchan->channelFlags),
- hchan->channel, hchan->channelFlags, status);
- spin_unlock_bh(&sc->sc_resetlock);
- return -EIO;
- }
- spin_unlock_bh(&sc->sc_resetlock);
-
- sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
- sc->sc_flags &= ~SC_OP_FULL_RESET;
-
- /* Re-enable rx framework */
- if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to restart recv logic\n", __func__);
- return -EIO;
- }
- /*
- * Change channels and update the h/w rate map
- * if we're switching; e.g. 11a to 11b/g.
- */
- ath_setcurmode(sc, ath_chan2mode(hchan));
-
- ath_update_txpow(sc); /* update tx power state */
- /*
- * Re-enable interrupts.
- */
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
- }
- return 0;
-}
-
-/**********************/
-/* Chainmask Handling */
-/**********************/
-
-static void ath_chainmask_sel_timertimeout(unsigned long data)
-{
- struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data;
- cm->switch_allowed = 1;
-}
-
-/* Start chainmask select timer */
-static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm)
-{
- cm->switch_allowed = 0;
- mod_timer(&cm->timer, ath_chainmask_sel_period);
-}
-
-/* Stop chainmask select timer */
-static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm)
-{
- cm->switch_allowed = 0;
- del_timer_sync(&cm->timer);
-}
-
-static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an)
-{
- struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
- memset(cm, 0, sizeof(struct ath_chainmask_sel));
-
- cm->cur_tx_mask = sc->sc_tx_chainmask;
- cm->cur_rx_mask = sc->sc_rx_chainmask;
- cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER;
- setup_timer(&cm->timer,
- ath_chainmask_sel_timertimeout, (unsigned long) cm);
-}
-
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
-{
- struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
-
- /*
- * Disable auto-swtiching in one of the following if conditions.
- * sc_chainmask_auto_sel is used for internal global auto-switching
- * enabled/disabled setting
- */
- if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) {
- cm->cur_tx_mask = sc->sc_tx_chainmask;
- return cm->cur_tx_mask;
- }
-
- if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER)
- return cm->cur_tx_mask;
-
- if (cm->switch_allowed) {
- /* Switch down from tx 3 to tx 2. */
- if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 &&
- ATH_RSSI_OUT(cm->tx_avgrssi) >=
- ath_chainmask_sel_down_rssi_thres) {
- cm->cur_tx_mask = sc->sc_tx_chainmask;
-
- /* Don't let another switch happen until
- * this timer expires */
- ath_chainmask_sel_timerstart(cm);
- }
- /* Switch up from tx 2 to 3. */
- else if (cm->cur_tx_mask == sc->sc_tx_chainmask &&
- ATH_RSSI_OUT(cm->tx_avgrssi) <=
- ath_chainmask_sel_up_rssi_thres) {
- cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3;
-
- /* Don't let another switch happen
- * until this timer expires */
- ath_chainmask_sel_timerstart(cm);
- }
- }
-
- return cm->cur_tx_mask;
-}
-
-/*
- * Update tx/rx chainmask. For legacy association,
- * hard code chainmask to 1x1, for 11n association, use
- * the chainmask configuration.
- */
-
-void ath_update_chainmask(struct ath_softc *sc, int is_ht)
-{
- sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
- if (is_ht) {
- sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
- sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
- } else {
- sc->sc_tx_chainmask = 1;
- sc->sc_rx_chainmask = 1;
- }
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
- __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
-}
-
-/*******/
-/* ANI */
-/*******/
-
-/*
- * 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.
- */
-
-static void ath_ani_calibrate(unsigned long data)
-{
- struct ath_softc *sc;
- struct ath_hal *ah;
- bool longcal = false;
- bool shortcal = false;
- bool aniflag = false;
- unsigned int timestamp = jiffies_to_msecs(jiffies);
- u32 cal_interval;
-
- sc = (struct ath_softc *)data;
- ah = sc->sc_ah;
-
- /*
- * don't calibrate when we're scanning.
- * we are most likely not on our home channel.
- */
- if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)
- return;
-
- /* Long calibration runs independently of short calibration. */
- if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
- longcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n",
- __func__, jiffies);
- sc->sc_ani.sc_longcal_timer = timestamp;
- }
-
- /* Short calibration applies only while sc_caldone is false */
- if (!sc->sc_ani.sc_caldone) {
- if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
- ATH_SHORT_CALINTERVAL) {
- shortcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n",
- __func__, jiffies);
- sc->sc_ani.sc_shortcal_timer = timestamp;
- sc->sc_ani.sc_resetcal_timer = timestamp;
- }
- } else {
- if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
- ATH_RESTART_CALINTERVAL) {
- ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
- &sc->sc_ani.sc_caldone);
- if (sc->sc_ani.sc_caldone)
- sc->sc_ani.sc_resetcal_timer = timestamp;
- }
- }
-
- /* Verify whether we must check ANI */
- if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
- ATH_ANI_POLLINTERVAL) {
- aniflag = true;
- sc->sc_ani.sc_checkani_timer = timestamp;
- }
-
- /* Skip all processing if there's nothing to do. */
- if (longcal || shortcal || aniflag) {
- /* Call ANI routine if necessary */
- if (aniflag)
- ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
- ah->ah_curchan);
-
- /* Perform calibration if necessary */
- if (longcal || shortcal) {
- bool iscaldone = false;
-
- if (ath9k_hw_calibrate(ah, ah->ah_curchan,
- sc->sc_rx_chainmask, longcal,
- &iscaldone)) {
- if (longcal)
- sc->sc_ani.sc_noise_floor =
- ath9k_hw_getchan_noise(ah,
- ah->ah_curchan);
-
- DPRINTF(sc, ATH_DBG_ANI,
- "%s: calibrate chan %u/%x nf: %d\n",
- __func__,
- ah->ah_curchan->channel,
- ah->ah_curchan->channelFlags,
- sc->sc_ani.sc_noise_floor);
- } else {
- DPRINTF(sc, ATH_DBG_ANY,
- "%s: calibrate chan %u/%x failed\n",
- __func__,
- ah->ah_curchan->channel,
- ah->ah_curchan->channelFlags);
- }
- sc->sc_ani.sc_caldone = iscaldone;
- }
- }
-
- /*
- * 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_ANI_POLLINTERVAL;
- if (!sc->sc_ani.sc_caldone)
- cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
-
- mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-}
-
-/******************/
-/* VAP management */
-/******************/
-
-int ath_vap_attach(struct ath_softc *sc,
- int if_id,
- struct ieee80211_vif *if_data,
- enum ath9k_opmode opmode)
-{
- struct ath_vap *avp;
-
- if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Invalid interface id = %u\n", __func__, if_id);
- return -EINVAL;
- }
-
- switch (opmode) {
- case ATH9K_M_STA:
- case ATH9K_M_IBSS:
- case ATH9K_M_MONITOR:
- break;
- case ATH9K_M_HOSTAP:
- /* XXX not right, beacon buffer is allocated on RUN trans */
- if (list_empty(&sc->sc_bbuf))
- return -ENOMEM;
- break;
- default:
- return -EINVAL;
- }
-
- /* create ath_vap */
- avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL);
- if (avp == NULL)
- return -ENOMEM;
-
- memset(avp, 0, sizeof(struct ath_vap));
- avp->av_if_data = if_data;
- /* Set the VAP opmode */
- avp->av_opmode = opmode;
- avp->av_bslot = -1;
-
- if (opmode == ATH9K_M_HOSTAP)
- ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
-
- sc->sc_vaps[if_id] = avp;
- sc->sc_nvaps++;
- /* Set the device opmode */
- sc->sc_ah->ah_opmode = opmode;
-
- /* default VAP configuration */
- avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
- avp->av_config.av_fixed_retryset = 0x03030303;
-
- return 0;
-}
-
-int ath_vap_detach(struct ath_softc *sc, int if_id)
-{
- struct ath_hal *ah = sc->sc_ah;
- struct ath_vap *avp;
-
- avp = sc->sc_vaps[if_id];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
- __func__, if_id);
- return -EINVAL;
- }
-
- /*
- * Quiesce the hardware while we remove the vap. In
- * particular we need to reclaim all references to the
- * vap state by any frames pending on the tx queues.
- *
- * XXX can we do this w/o affecting other vap's?
- */
- ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
- ath_draintxq(sc, false); /* stop xmit side */
- ath_stoprecv(sc); /* stop recv side */
- ath_flushrecv(sc); /* flush recv queue */
-
- kfree(avp);
- sc->sc_vaps[if_id] = NULL;
- sc->sc_nvaps--;
-
- return 0;
-}
-
-int ath_vap_config(struct ath_softc *sc,
- int if_id, struct ath_vap_config *if_config)
-{
- struct ath_vap *avp;
-
- if (if_id >= ATH_BCBUF) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Invalid interface id = %u\n", __func__, if_id);
- return -EINVAL;
- }
-
- avp = sc->sc_vaps[if_id];
- ASSERT(avp != NULL);
-
- if (avp)
- memcpy(&avp->av_config, if_config, sizeof(avp->av_config));
-
- return 0;
-}
-
-/********/
-/* Core */
-/********/
-
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
-{
- struct ath_hal *ah = sc->sc_ah;
- int status;
- int error = 0;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
- __func__, sc->sc_ah->ah_opmode);
-
- /*
- * Stop anything previously setup. This is safe
- * whether this is the first time through or not.
- */
- ath_stop(sc);
-
- /* Initialize chanmask selection */
- sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
- sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
- /* Reset SERDES registers */
- ath9k_hw_configpcipowersave(ah, 0);
-
- /*
- * The basic interface to setting the hardware in a good
- * state is ``reset''. On return the hardware is known to
- * be powered up and with interrupts disabled. This must
- * be followed by initialization of the appropriate bits
- * and then setup of the interrupt mask.
- */
-
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, initial_chan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask, sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing, false, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset hardware; hal status %u "
- "(freq %u flags 0x%x)\n", __func__, status,
- initial_chan->channel, initial_chan->channelFlags);
- error = -EIO;
- spin_unlock_bh(&sc->sc_resetlock);
- goto done;
- }
- spin_unlock_bh(&sc->sc_resetlock);
- /*
- * This is needed only to setup initial state
- * but it's best done after a reset.
- */
- ath_update_txpow(sc);
-
- /*
- * Setup the hardware after reset:
- * The receive engine is set going.
- * Frame transmit is handled entirely
- * in the frame output path; there's nothing to do
- * here except setup the interrupt mask.
- */
- if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to start recv logic\n", __func__);
- error = -EIO;
- goto done;
- }
- /* Setup our intr mask. */
- sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
- | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
- | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
-
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
- sc->sc_imask |= ATH9K_INT_GTT;
-
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
- sc->sc_imask |= ATH9K_INT_CST;
-
- /*
- * Enable MIB interrupts when there are hardware phy counters.
- * Note we only do this (at the moment) for station mode.
- */
- if (ath9k_hw_phycounters(ah) &&
- ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
- (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)))
- sc->sc_imask |= ATH9K_INT_MIB;
- /*
- * Some hardware processes the TIM IE and fires an
- * interrupt when the TIM bit is set. For hardware
- * that does, if not overridden by configuration,
- * enable the TIM interrupt when operating as station.
- */
- if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
- (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
- !sc->sc_config.swBeaconProcess)
- sc->sc_imask |= ATH9K_INT_TIM;
- /*
- * Don't enable interrupts here as we've not yet built our
- * vap and node data structures, which will be needed as soon
- * as we start receiving.
- */
- ath_setcurmode(sc, ath_chan2mode(initial_chan));
-
- /* XXX: we must make sure h/w is ready and clear invalid flag
- * before turning on interrupt. */
- sc->sc_flags &= ~SC_OP_INVALID;
-done:
- return error;
-}
-
-int ath_reset(struct ath_softc *sc, bool retry_tx)
-{
- struct ath_hal *ah = sc->sc_ah;
- int status;
- int error = 0;
-
- ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
- ath_draintxq(sc, retry_tx); /* stop xmit */
- ath_stoprecv(sc); /* stop recv */
- ath_flushrecv(sc); /* flush recv queue */
-
- /* Reset chip */
- spin_lock_bh(&sc->sc_resetlock);
- if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
- sc->sc_tx_chainmask, sc->sc_rx_chainmask,
- sc->sc_ht_extprotspacing, false, &status)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset hardware; hal status %u\n",
- __func__, status);
- error = -EIO;
- }
- spin_unlock_bh(&sc->sc_resetlock);
-
- if (ath_startrecv(sc) != 0) /* restart recv */
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to start recv logic\n", __func__);
-
- /*
- * We may be doing a reset in response to a request
- * that changes the channel so update any state that
- * might change as a result.
- */
- ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
-
- ath_update_txpow(sc);
-
- if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
-
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
-
- /* Restart the txq */
- if (retry_tx) {
- int i;
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (ATH_TXQ_SETUP(sc, i)) {
- spin_lock_bh(&sc->sc_txq[i].axq_lock);
- ath_txq_schedule(sc, &sc->sc_txq[i]);
- spin_unlock_bh(&sc->sc_txq[i].axq_lock);
- }
- }
- }
-
- return error;
-}
-
-int ath_suspend(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
-
- /* No I/O if device has been surprise removed */
- if (sc->sc_flags & SC_OP_INVALID)
- return -EIO;
-
- /* Shut off the interrupt before setting sc->sc_invalid to '1' */
- ath9k_hw_set_interrupts(ah, 0);
-
- /* XXX: we must make sure h/w will not generate any interrupt
- * before setting the invalid flag. */
- sc->sc_flags |= SC_OP_INVALID;
-
- /* disable HAL and put h/w to sleep */
- ath9k_hw_disable(sc->sc_ah);
-
- ath9k_hw_configpcipowersave(sc->sc_ah, 1);
-
- return 0;
-}
-
-/* Interrupt handler. Most of the actual processing is deferred.
- * It's the caller's responsibility to ensure the chip is awake. */
-
-irqreturn_t ath_isr(int irq, void *dev)
-{
- struct ath_softc *sc = dev;
- struct ath_hal *ah = sc->sc_ah;
- enum ath9k_int status;
- bool sched = false;
-
- do {
- if (sc->sc_flags & SC_OP_INVALID) {
- /*
- * The hardware is not ready/present, don't
- * touch anything. Note this can happen early
- * on if the IRQ is shared.
- */
- return IRQ_NONE;
- }
- if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
- return IRQ_NONE;
- }
-
- /*
- * Figure out the reason(s) for the interrupt. Note
- * that the hal returns a pseudo-ISR that may include
- * bits we haven't explicitly enabled so we mask the
- * value to insure we only process bits we requested.
- */
- ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
-
- status &= sc->sc_imask; /* discard unasked-for bits */
-
- /*
- * If there are no status bits set, then this interrupt was not
- * for me (should have been caught above).
- */
-
- if (!status)
- return IRQ_NONE;
-
- sc->sc_intrstatus = status;
-
- if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
- sched = true;
- } else if (status & ATH9K_INT_RXORN) {
- /* need a chip reset */
- sched = true;
- } else {
- if (status & ATH9K_INT_SWBA) {
- /* schedule a tasklet for beacon handling */
- tasklet_schedule(&sc->bcon_tasklet);
- }
- if (status & ATH9K_INT_RXEOL) {
- /*
- * NB: the hardware should re-read the link when
- * RXE bit is written, but it doesn't work
- * at least on older hardware revs.
- */
- sched = true;
- }
-
- if (status & ATH9K_INT_TXURN)
- /* bump tx trigger level */
- ath9k_hw_updatetxtriglevel(ah, true);
- /* XXX: optimize this */
- if (status & ATH9K_INT_RX)
- sched = true;
- if (status & ATH9K_INT_TX)
- sched = true;
- if (status & ATH9K_INT_BMISS)
- sched = true;
- /* carrier sense timeout */
- if (status & ATH9K_INT_CST)
- sched = true;
- if (status & ATH9K_INT_MIB) {
- /*
- * Disable interrupts until we service the MIB
- * interrupt; otherwise it will continue to
- * fire.
- */
- ath9k_hw_set_interrupts(ah, 0);
- /*
- * Let the hal handle the event. We assume
- * it will clear whatever condition caused
- * the interrupt.
- */
- ath9k_hw_procmibevent(ah, &sc->sc_halstats);
- ath9k_hw_set_interrupts(ah, sc->sc_imask);
- }
- if (status & ATH9K_INT_TIM_TIMER) {
- if (!(ah->ah_caps.hw_caps &
- ATH9K_HW_CAP_AUTOSLEEP)) {
- /* Clear RxAbort bit so that we can
- * receive frames */
- ath9k_hw_setrxabort(ah, 0);
- sched = true;
- }
- }
- }
- } while (0);
-
- if (sched) {
- /* turn off every interrupt except SWBA */
- ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
- tasklet_schedule(&sc->intr_tq);
- }
-
- return IRQ_HANDLED;
-}
-
-/* Deferred interrupt processing */
-
-static void ath9k_tasklet(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *)data;
- u32 status = sc->sc_intrstatus;
-
- if (status & ATH9K_INT_FATAL) {
- /* need a chip reset */
- ath_reset(sc, false);
- return;
- } else {
-
- if (status &
- (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
- /* XXX: fill me in */
- /*
- if (status & ATH9K_INT_RXORN) {
- }
- if (status & ATH9K_INT_RXEOL) {
- }
- */
- spin_lock_bh(&sc->sc_rxflushlock);
- ath_rx_tasklet(sc, 0);
- spin_unlock_bh(&sc->sc_rxflushlock);
- }
- /* XXX: optimize this */
- if (status & ATH9K_INT_TX)
- ath_tx_tasklet(sc);
- /* XXX: fill me in */
- /*
- if (status & ATH9K_INT_BMISS) {
- }
- if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) {
- if (status & ATH9K_INT_TIM) {
- }
- if (status & ATH9K_INT_DTIMSYNC) {
- }
- }
- */
- }
-
- /* re-enable hardware interrupt */
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
-}
-
-int ath_init(u16 devid, struct ath_softc *sc)
-{
- struct ath_hal *ah = NULL;
- int status;
- int error = 0, i;
- int csz = 0;
-
- /* XXX: hardware will not be ready until ath_open() being called */
- sc->sc_flags |= SC_OP_INVALID;
-
- sc->sc_debug = DBG_DEFAULT;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
-
- /* Initialize tasklet */
- tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
- tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
- (unsigned long)sc);
-
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- bus_read_cachesize(sc, &csz);
- /* XXX assert csz is non-zero */
- sc->sc_cachelsz = csz << 2; /* convert to bytes */
-
- spin_lock_init(&sc->sc_resetlock);
-
- ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
- if (ah == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to attach hardware; HAL status %u\n",
- __func__, status);
- error = -ENXIO;
- goto bad;
- }
- sc->sc_ah = ah;
-
- /* Initializes the noise floor to a reasonable default value.
- * Later on this will be updated during ANI processing. */
- sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-
- /* Get the hardware key cache size. */
- sc->sc_keymax = ah->ah_caps.keycache_size;
- if (sc->sc_keymax > ATH_KEYMAX) {
- DPRINTF(sc, ATH_DBG_KEYCACHE,
- "%s: Warning, using only %u entries in %u key cache\n",
- __func__, ATH_KEYMAX, sc->sc_keymax);
- sc->sc_keymax = ATH_KEYMAX;
- }
-
- /*
- * Reset the key cache since some parts do not
- * reset the contents on initial power up.
- */
- for (i = 0; i < sc->sc_keymax; i++)
- ath9k_hw_keyreset(ah, (u16) i);
- /*
- * Mark key cache slots associated with global keys
- * as in use. If we knew TKIP was not to be used we
- * could leave the +32, +64, and +32+64 slots free.
- * XXX only for splitmic.
- */
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- set_bit(i, sc->sc_keymap);
- set_bit(i + 32, sc->sc_keymap);
- set_bit(i + 64, sc->sc_keymap);
- set_bit(i + 32 + 64, sc->sc_keymap);
- }
- /*
- * Collect the channel list using the default country
- * code and including outdoor channels. The 802.11 layer
- * is resposible for filtering this list based on settings
- * like the phy mode.
- */
- error = ath_setup_channels(sc);
- if (error)
- goto bad;
-
- /* default to STA mode */
- sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
-
- /* Setup rate tables */
-
- ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
- ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
-
- /* NB: setup here so ath_rate_update is happy */
- ath_setcurmode(sc, ATH9K_MODE_11A);
-
- /*
- * Allocate hardware transmit queues: one queue for
- * beacon frames and one data queue for each QoS
- * priority. Note that the hal handles reseting
- * these queues at the needed time.
- */
- sc->sc_bhalq = ath_beaconq_setup(ah);
- if (sc->sc_bhalq == -1) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup a beacon xmit queue\n", __func__);
- error = -EIO;
- goto bad2;
- }
- sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
- if (sc->sc_cabq == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup CAB xmit queue\n", __func__);
- error = -EIO;
- goto bad2;
- }
-
- sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
- ath_cabq_update(sc);
-
- for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
- sc->sc_haltype2q[i] = -1;
-
- /* Setup data queues */
- /* NB: ensure BK queue is the lowest priority h/w queue */
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for BK traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
-
- if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for BE traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for VI traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
- if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to setup xmit queue for VO traffic\n",
- __func__);
- error = -EIO;
- goto bad2;
- }
-
- setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
-
- sc->sc_rc = ath_rate_attach(ah);
- if (sc->sc_rc == NULL) {
- error = -EIO;
- goto bad2;
- }
-
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)) {
- /*
- * Whether we should enable h/w TKIP MIC.
- * XXX: if we don't support WME TKIP MIC, then we wouldn't
- * report WMM capable, so it's always safe to turn on
- * TKIP MIC in this case.
- */
- ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
- 0, 1, NULL);
- }
-
- /*
- * Check whether the separate key cache entries
- * are required to handle both tx+rx MIC keys.
- * With split mic keys the number of stations is limited
- * to 27 otherwise 59.
- */
- if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_TKIP, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
- ATH9K_CIPHER_MIC, NULL)
- && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
- 0, NULL))
- sc->sc_splitmic = 1;
-
- /* turn on mcast key search if possible */
- if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
- (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
- 1, NULL);
-
- sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
- sc->sc_config.txpowlimit_override = 0;
-
- /* 11n Capabilities */
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
- sc->sc_flags |= SC_OP_TXAGGR;
- sc->sc_flags |= SC_OP_RXAGGR;
- }
-
- sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
- sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
- ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
- sc->sc_defant = ath9k_hw_getdefantenna(ah);
-
- ath9k_hw_getmac(ah, sc->sc_myaddr);
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
- ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
- ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
- ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
- }
- sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
-
- /* initialize beacon slots */
- for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
- sc->sc_bslot[i] = ATH_IF_ID_ANY;
-
- /* save MISC configurations */
- sc->sc_config.swBeaconProcess = 1;
-
-#ifdef CONFIG_SLOW_ANT_DIV
- /* range is 40 - 255, we use something in the middle */
- ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
-#endif
-
- return 0;
-bad2:
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-bad:
- if (ah)
- ath9k_hw_detach(ah);
- return error;
-}
-
-void ath_deinit(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
- int i;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
-
- tasklet_kill(&sc->intr_tq);
- tasklet_kill(&sc->bcon_tasklet);
- ath_stop(sc);
- if (!(sc->sc_flags & SC_OP_INVALID))
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- ath_rate_detach(sc->sc_rc);
- /* cleanup tx queues */
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- if (ATH_TXQ_SETUP(sc, i))
- ath_tx_cleanupq(sc, &sc->sc_txq[i]);
- ath9k_hw_detach(ah);
-}
-
-/*******************/
-/* Node Management */
-/*******************/
-
-struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id)
-{
- struct ath_vap *avp;
- struct ath_node *an;
- DECLARE_MAC_BUF(mac);
-
- avp = sc->sc_vaps[if_id];
- ASSERT(avp != NULL);
-
- /* mac80211 sta_notify callback is from an IRQ context, so no sleep */
- an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
- if (an == NULL)
- return NULL;
- memset(an, 0, sizeof(*an));
-
- an->an_sc = sc;
- memcpy(an->an_addr, addr, ETH_ALEN);
- atomic_set(&an->an_refcnt, 1);
-
- /* set up per-node tx/rx state */
- ath_tx_node_init(sc, an);
- ath_rx_node_init(sc, an);
-
- ath_chainmask_sel_init(sc, an);
- ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
- list_add(&an->list, &sc->node_list);
-
- return an;
-}
-
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
- unsigned long flags;
-
- DECLARE_MAC_BUF(mac);
-
- ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
- an->an_flags |= ATH_NODE_CLEAN;
- ath_tx_node_cleanup(sc, an, bh_flag);
- ath_rx_node_cleanup(sc, an);
-
- ath_tx_node_free(sc, an);
- ath_rx_node_free(sc, an);
-
- spin_lock_irqsave(&sc->node_lock, flags);
-
- list_del(&an->list);
-
- spin_unlock_irqrestore(&sc->node_lock, flags);
-
- kfree(an);
-}
-
-/* Finds a node and increases the refcnt if found */
-
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr)
-{
- struct ath_node *an = NULL, *an_found = NULL;
-
- if (list_empty(&sc->node_list)) /* FIXME */
- goto out;
- list_for_each_entry(an, &sc->node_list, list) {
- if (!compare_ether_addr(an->an_addr, addr)) {
- atomic_inc(&an->an_refcnt);
- an_found = an;
- break;
- }
- }
-out:
- return an_found;
-}
-
-/* Decrements the refcnt and if it drops to zero, detach the node */
-
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
- if (atomic_dec_and_test(&an->an_refcnt))
- ath_node_detach(sc, an, bh_flag);
-}
-
-/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr)
-{
- struct ath_node *an = NULL, *an_found = NULL;
-
- if (list_empty(&sc->node_list))
- return NULL;
-
- list_for_each_entry(an, &sc->node_list, list)
- if (!compare_ether_addr(an->an_addr, addr)) {
- an_found = an;
- break;
- }
-
- return an_found;
-}
-
-/*
- * Set up New Node
- *
- * Setup driver-specific state for a newly associated node. This routine
- * really only applies if compression or XR are enabled, there is no code
- * covering any other cases.
-*/
-
-void ath_newassoc(struct ath_softc *sc,
- struct ath_node *an, int isnew, int isuapsd)
-{
- int tidno;
-
- /* if station reassociates, tear down the aggregation state. */
- if (!isnew) {
- for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
- if (sc->sc_flags & SC_OP_TXAGGR)
- ath_tx_aggr_teardown(sc, an, tidno);
- if (sc->sc_flags & SC_OP_RXAGGR)
- ath_rx_aggr_teardown(sc, an, tidno);
- }
- }
- an->an_flags = 0;
-}
-
-/**************/
-/* Encryption */
-/**************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
-{
- ath9k_hw_keyreset(sc->sc_ah, keyix);
- if (freeslot)
- clear_bit(keyix, sc->sc_keymap);
-}
-
-int ath_keyset(struct ath_softc *sc,
- u16 keyix,
- struct ath9k_keyval *hk,
- const u8 mac[ETH_ALEN])
-{
- bool status;
-
- status = ath9k_hw_set_keycache_entry(sc->sc_ah,
- keyix, hk, mac, false);
-
- return status != false;
-}
-
-/***********************/
-/* TX Power/Regulatory */
-/***********************/
-
-/*
- * Set Transmit power in HAL
- *
- * This routine makes the actual HAL calls to set the new transmit power
- * limit.
-*/
-
-void ath_update_txpow(struct ath_softc *sc)
-{
- struct ath_hal *ah = sc->sc_ah;
- u32 txpow;
-
- if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
- ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
- /* read back in case value is clamped */
- ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
- sc->sc_curtxpow = txpow;
- }
-}
-
-/* Return the current country and domain information */
-void ath_get_currentCountry(struct ath_softc *sc,
- struct ath9k_country_entry *ctry)
-{
- ath9k_regd_get_current_country(sc->sc_ah, ctry);
-
- /* If HAL not specific yet, since it is band dependent,
- * use the one we passed in. */
- if (ctry->countryCode == CTRY_DEFAULT) {
- ctry->iso[0] = 0;
- ctry->iso[1] = 0;
- } else if (ctry->iso[0] && ctry->iso[1]) {
- if (!ctry->iso[2]) {
- if (ath_outdoor)
- ctry->iso[2] = 'O';
- else
- ctry->iso[2] = 'I';
- }
- }
-}
-
-/**************************/
-/* Slow Antenna Diversity */
-/**************************/
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
- struct ath_softc *sc,
- int32_t rssitrig)
-{
- int trig;
-
- /* antdivf_rssitrig can range from 40 - 0xff */
- trig = (rssitrig > 0xff) ? 0xff : rssitrig;
- trig = (rssitrig < 40) ? 40 : rssitrig;
-
- antdiv->antdiv_sc = sc;
- antdiv->antdivf_rssitrig = trig;
-}
-
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
- u8 num_antcfg,
- const u8 *bssid)
-{
- antdiv->antdiv_num_antcfg =
- num_antcfg < ATH_ANT_DIV_MAX_CFG ?
- num_antcfg : ATH_ANT_DIV_MAX_CFG;
- antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
- antdiv->antdiv_curcfg = 0;
- antdiv->antdiv_bestcfg = 0;
- antdiv->antdiv_laststatetsf = 0;
-
- memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid));
-
- antdiv->antdiv_start = 1;
-}
-
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv)
-{
- antdiv->antdiv_start = 0;
-}
-
-static int32_t ath_find_max_val(int32_t *val,
- u8 num_val, u8 *max_index)
-{
- u32 MaxVal = *val++;
- u32 cur_index = 0;
-
- *max_index = 0;
- while (++cur_index < num_val) {
- if (*val > MaxVal) {
- MaxVal = *val;
- *max_index = cur_index;
- }
-
- val++;
- }
-
- return MaxVal;
-}
-
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
- struct ieee80211_hdr *hdr,
- struct ath_rx_status *rx_stats)
-{
- struct ath_softc *sc = antdiv->antdiv_sc;
- struct ath_hal *ah = sc->sc_ah;
- u64 curtsf = 0;
- u8 bestcfg, curcfg = antdiv->antdiv_curcfg;
- __le16 fc = hdr->frame_control;
-
- if (antdiv->antdiv_start && ieee80211_is_beacon(fc)
- && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) {
- antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi;
- antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah);
- curtsf = antdiv->antdiv_lastbtsf[curcfg];
- } else {
- return;
- }
-
- switch (antdiv->antdiv_state) {
- case ATH_ANT_DIV_IDLE:
- if ((antdiv->antdiv_lastbrssi[curcfg] <
- antdiv->antdivf_rssitrig)
- && ((curtsf - antdiv->antdiv_laststatetsf) >
- ATH_ANT_DIV_MIN_IDLE_US)) {
-
- curcfg++;
- if (curcfg == antdiv->antdiv_num_antcfg)
- curcfg = 0;
-
- if (!ath9k_hw_select_antconfig(ah, curcfg)) {
- antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg;
- antdiv->antdiv_curcfg = curcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
- }
- }
- break;
-
- case ATH_ANT_DIV_SCAN:
- if ((curtsf - antdiv->antdiv_laststatetsf) <
- ATH_ANT_DIV_MIN_SCAN_US)
- break;
-
- curcfg++;
- if (curcfg == antdiv->antdiv_num_antcfg)
- curcfg = 0;
-
- if (curcfg == antdiv->antdiv_bestcfg) {
- ath_find_max_val(antdiv->antdiv_lastbrssi,
- antdiv->antdiv_num_antcfg, &bestcfg);
- if (!ath9k_hw_select_antconfig(ah, bestcfg)) {
- antdiv->antdiv_bestcfg = bestcfg;
- antdiv->antdiv_curcfg = bestcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
- }
- } else {
- if (!ath9k_hw_select_antconfig(ah, curcfg)) {
- antdiv->antdiv_curcfg = curcfg;
- antdiv->antdiv_laststatetsf = curtsf;
- antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
- }
- }
-
- break;
- }
-}
-
-/***********************/
-/* Descriptor Handling */
-/***********************/
-
-/*
- * Set up DMA descriptors
- *
- * This function will allocate both the DMA descriptor structure, and the
- * buffers it contains. These are used to contain the descriptors used
- * by the system.
-*/
-
-int ath_descdma_setup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head,
- const char *name,
- int nbuf,
- int ndesc)
-{
-#define DS2PHYS(_dd, _ds) \
- ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
- struct ath_desc *ds;
- struct ath_buf *bf;
- int i, bsize, error;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
- __func__, name, nbuf, ndesc);
-
- /* ath_desc must be a multiple of DWORDs */
- if ((sizeof(struct ath_desc) % 4) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
- __func__);
- ASSERT((sizeof(struct ath_desc) % 4) == 0);
- error = -ENOMEM;
- goto fail;
- }
-
- dd->dd_name = name;
- dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
- /*
- * Need additional DMA memory because we can't use
- * descriptors that cross the 4K page boundary. Assume
- * one skipped descriptor per 4K page.
- */
- if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
- u32 ndesc_skipped =
- ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
- u32 dma_len;
-
- while (ndesc_skipped) {
- dma_len = ndesc_skipped * sizeof(struct ath_desc);
- dd->dd_desc_len += dma_len;
-
- ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
- };
- }
-
- /* allocate descriptors */
- dd->dd_desc = pci_alloc_consistent(sc->pdev,
- dd->dd_desc_len,
- &dd->dd_desc_paddr);
- if (dd->dd_desc == NULL) {
- error = -ENOMEM;
- goto fail;
- }
- ds = dd->dd_desc;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
- __func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
- /* allocate buffers */
- bsize = sizeof(struct ath_buf) * nbuf;
- bf = kmalloc(bsize, GFP_KERNEL);
- if (bf == NULL) {
- error = -ENOMEM;
- goto fail2;
- }
- memset(bf, 0, bsize);
- dd->dd_bufptr = bf;
-
- INIT_LIST_HEAD(head);
- for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(dd, ds);
-
- if (!(sc->sc_ah->ah_caps.hw_caps &
- ATH9K_HW_CAP_4KB_SPLITTRANS)) {
- /*
- * Skip descriptor addresses which can cause 4KB
- * boundary crossing (addr + length) with a 32 dword
- * descriptor fetch.
- */
- while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
- ASSERT((caddr_t) bf->bf_desc <
- ((caddr_t) dd->dd_desc +
- dd->dd_desc_len));
-
- ds += ndesc;
- bf->bf_desc = ds;
- bf->bf_daddr = DS2PHYS(dd, ds);
- }
- }
- list_add_tail(&bf->list, head);
- }
- return 0;
-fail2:
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-fail:
- memset(dd, 0, sizeof(*dd));
- return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-/*
- * Cleanup DMA descriptors
- *
- * This function will free the DMA block that was allocated for the descriptor
- * pool. Since this was allocated as one "chunk", it is freed in the same
- * manner.
-*/
-
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head)
-{
- /* Free memory associated with descriptors */
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
-
- INIT_LIST_HEAD(head);
- kfree(dd->dd_bufptr);
- memset(dd, 0, sizeof(*dd));
-}
-
-/*************/
-/* Utilities */
-/*************/
-
-int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case 0:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
- break;
- case 1:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
- break;
- case 2:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
- break;
- case 3:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
- break;
- default:
- qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
- break;
- }
-
- return qnum;
-}
-
-int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
-{
- int qnum;
-
- switch (queue) {
- case ATH9K_WME_AC_VO:
- qnum = 0;
- break;
- case ATH9K_WME_AC_VI:
- qnum = 1;
- break;
- case ATH9K_WME_AC_BE:
- qnum = 2;
- break;
- case ATH9K_WME_AC_BK:
- qnum = 3;
- break;
- default:
- qnum = -1;
- break;
- }
-
- return qnum;
-}
-
-
-/*
- * Expand time stamp to TSF
- *
- * Extend 15-bit time stamp from rx descriptor to
- * a full 64-bit TSF using the current h/w TSF.
-*/
-
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
-{
- u64 tsf;
-
- tsf = ath9k_hw_gettsf64(sc->sc_ah);
- if ((tsf & 0x7fff) < rstamp)
- tsf -= 0x8000;
- return (tsf & ~0x7fff) | rstamp;
-}
-
-/*
- * Set Default Antenna
- *
- * Call into the HAL to set the default antenna to use. Not really valid for
- * MIMO technology.
-*/
-
-void ath_setdefantenna(void *context, u32 antenna)
-{
- struct ath_softc *sc = (struct ath_softc *)context;
- struct ath_hal *ah = sc->sc_ah;
-
- /* XXX block beacon interrupts */
- ath9k_hw_setantenna(ah, antenna);
- sc->sc_defant = antenna;
- sc->sc_rxotherant = 0;
-}
-
-/*
- * Set Slot Time
- *
- * This will wake up the chip if required, and set the slot time for the
- * frame (maximum transmit time). Slot time is assumed to be already set
- * in the ATH object member sc_slottime
-*/
-
-void ath_setslottime(struct ath_softc *sc)
-{
- ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
- sc->sc_updateslot = OK;
-}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index cb3e61e57c4..4ca2aed236e 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -17,27 +17,8 @@
#ifndef CORE_H
#define CORE_H
-#include <linux/version.h>
-#include <linux/autoconf.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <asm/byteorder.h>
-#include <linux/scatterlist.h>
-#include <asm/page.h>
#include <net/mac80211.h>
#include <linux/leds.h>
#include <linux/rfkill.h>
@@ -47,10 +28,6 @@
struct ath_node;
-/******************/
-/* Utility macros */
-/******************/
-
/* Macro to expand scalars to 64-bit objects */
#define ito64(x) (sizeof(x) == 8) ? \
@@ -84,94 +61,125 @@ struct ath_node;
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
-#define ATH9K_BH_STATUS_INTACT 0
-#define ATH9K_BH_STATUS_CHANGE 1
-
-#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
-
-static inline unsigned long get_timestamp(void)
-{
- return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
-}
+#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-/*************/
-/* Debugging */
-/*************/
-
enum ATH_DEBUG {
ATH_DBG_RESET = 0x00000001,
- ATH_DBG_PHY_IO = 0x00000002,
- ATH_DBG_REG_IO = 0x00000004,
- ATH_DBG_QUEUE = 0x00000008,
- ATH_DBG_EEPROM = 0x00000010,
- ATH_DBG_NF_CAL = 0x00000020,
- ATH_DBG_CALIBRATE = 0x00000040,
- ATH_DBG_CHANNEL = 0x00000080,
- ATH_DBG_INTERRUPT = 0x00000100,
- ATH_DBG_REGULATORY = 0x00000200,
- ATH_DBG_ANI = 0x00000400,
- ATH_DBG_POWER_MGMT = 0x00000800,
- ATH_DBG_XMIT = 0x00001000,
- ATH_DBG_BEACON = 0x00002000,
- ATH_DBG_RATE = 0x00004000,
- ATH_DBG_CONFIG = 0x00008000,
- ATH_DBG_KEYCACHE = 0x00010000,
- ATH_DBG_AGGR = 0x00020000,
- ATH_DBG_FATAL = 0x00040000,
+ ATH_DBG_REG_IO = 0x00000002,
+ ATH_DBG_QUEUE = 0x00000004,
+ ATH_DBG_EEPROM = 0x00000008,
+ ATH_DBG_CALIBRATE = 0x00000010,
+ ATH_DBG_CHANNEL = 0x00000020,
+ ATH_DBG_INTERRUPT = 0x00000040,
+ ATH_DBG_REGULATORY = 0x00000080,
+ ATH_DBG_ANI = 0x00000100,
+ ATH_DBG_POWER_MGMT = 0x00000200,
+ ATH_DBG_XMIT = 0x00000400,
+ ATH_DBG_BEACON = 0x00001000,
+ ATH_DBG_CONFIG = 0x00002000,
+ ATH_DBG_KEYCACHE = 0x00004000,
+ ATH_DBG_FATAL = 0x00008000,
ATH_DBG_ANY = 0xffffffff
};
#define DBG_DEFAULT (ATH_DBG_FATAL)
-#define DPRINTF(sc, _m, _fmt, ...) do { \
- if (sc->sc_debug & (_m)) \
- printk(_fmt , ##__VA_ARGS__); \
- } while (0)
+#ifdef CONFIG_ATH9K_DEBUG
+
+/**
+ * struct ath_interrupt_stats - Contains statistics about interrupts
+ * @total: Total no. of interrupts generated so far
+ * @rxok: RX with no errors
+ * @rxeol: RX with no more RXDESC available
+ * @rxorn: RX FIFO overrun
+ * @txok: TX completed at the requested rate
+ * @txurn: TX FIFO underrun
+ * @mib: MIB regs reaching its threshold
+ * @rxphyerr: RX with phy errors
+ * @rx_keycache_miss: RX with key cache misses
+ * @swba: Software Beacon Alert
+ * @bmiss: Beacon Miss
+ * @bnr: Beacon Not Ready
+ * @cst: Carrier Sense TImeout
+ * @gtt: Global TX Timeout
+ * @tim: RX beacon TIM occurrence
+ * @cabend: RX End of CAB traffic
+ * @dtimsync: DTIM sync lossage
+ * @dtim: RX Beacon with DTIM
+ */
+struct ath_interrupt_stats {
+ u32 total;
+ u32 rxok;
+ u32 rxeol;
+ u32 rxorn;
+ u32 txok;
+ u32 txeol;
+ u32 txurn;
+ u32 mib;
+ u32 rxphyerr;
+ u32 rx_keycache_miss;
+ u32 swba;
+ u32 bmiss;
+ u32 bnr;
+ u32 cst;
+ u32 gtt;
+ u32 tim;
+ u32 cabend;
+ u32 dtimsync;
+ u32 dtim;
+};
+
+struct ath_stats {
+ struct ath_interrupt_stats istats;
+};
+
+struct ath9k_debug {
+ int debug_mask;
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_phy;
+ struct dentry *debugfs_dma;
+ struct dentry *debugfs_interrupt;
+ struct ath_stats stats;
+};
+
+void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
+int ath9k_init_debug(struct ath_softc *sc);
+void ath9k_exit_debug(struct ath_softc *sc);
+void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
+
+#else
+
+static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
+ const char *fmt, ...)
+{
+}
+
+static inline int ath9k_init_debug(struct ath_softc *sc)
+{
+ return 0;
+}
-/***************************/
-/* Load-time Configuration */
-/***************************/
+static inline void ath9k_exit_debug(struct ath_softc *sc)
+{
+}
+
+static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
+ enum ath9k_int status)
+{
+}
+
+#endif /* CONFIG_ATH9K_DEBUG */
-/* Per-instance load-time (note: NOT run-time) configurations
- * for Atheros Device */
struct ath_config {
u32 ath_aggr_prot;
u16 txpowlimit;
u16 txpowlimit_override;
- u8 cabqReadytime; /* Cabq Readytime % */
- u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */
-};
-
-/***********************/
-/* Chainmask Selection */
-/***********************/
-
-#define ATH_CHAINMASK_SEL_TIMEOUT 6000
-/* Default - Number of last RSSI values that is used for
- * chainmask selection */
-#define ATH_CHAINMASK_SEL_RSSI_CNT 10
-/* Means use 3x3 chainmask instead of configured chainmask */
-#define ATH_CHAINMASK_SEL_3X3 7
-/* Default - Rssi threshold below which we have to switch to 3x3 */
-#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20
-/* Default - Rssi threshold above which we have to switch to
- * user configured values */
-#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35
-/* Struct to store the chainmask select related info */
-struct ath_chainmask_sel {
- struct timer_list timer;
- int cur_tx_mask; /* user configured or 3x3 */
- int cur_rx_mask; /* user configured or 3x3 */
- int tx_avgrssi;
- u8 switch_allowed:1, /* timer will set this */
- cm_sel_enabled : 1;
+ u8 cabqReadytime;
+ u8 swBeaconProcess;
};
-int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an);
-void ath_update_chainmask(struct ath_softc *sc, int is_ht);
-
/*************************/
/* Descriptor Management */
/*************************/
@@ -200,15 +208,14 @@ enum buffer_type {
};
struct ath_buf_state {
- int bfs_nframes; /* # frames in aggregate */
- u16 bfs_al; /* length of aggregate */
- u16 bfs_frmlen; /* length of frame */
- int bfs_seqno; /* sequence number */
- int bfs_tidno; /* tid of this frame */
- int bfs_retries; /* current retries */
- struct ath_rc_series bfs_rcs[4]; /* rate series */
- u32 bf_type; /* BUF_* (enum buffer_type) */
- /* key type use to encrypt this frame */
+ int bfs_nframes; /* # frames in aggregate */
+ u16 bfs_al; /* length of aggregate */
+ u16 bfs_frmlen; /* length of frame */
+ int bfs_seqno; /* sequence number */
+ int bfs_tidno; /* tid of this frame */
+ int bfs_retries; /* current retries */
+ u32 bf_type; /* BUF_* (enum buffer_type) */
+ u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
@@ -219,6 +226,7 @@ struct ath_buf_state {
#define bf_seqno bf_state.bfs_seqno
#define bf_tidno bf_state.bfs_tidno
#define bf_rcs bf_state.bfs_rcs
+#define bf_keyix bf_state.bfs_keyix
#define bf_keytype bf_state.bfs_keytype
#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
@@ -242,9 +250,7 @@ struct ath_buf {
an aggregate) */
struct ath_buf *bf_lastfrm; /* last buf of this frame */
struct ath_buf *bf_next; /* next subframe in the aggregate */
- struct ath_buf *bf_rifslast; /* last buf for RIFS burst */
void *bf_mpdu; /* enclosing frame structure */
- void *bf_node; /* pointer to the node */
struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
@@ -254,13 +260,6 @@ struct ath_buf {
dma_addr_t bf_dmacontext;
};
-/*
- * reset the rx buffer.
- * any new fields added to the athbuf and require
- * reset need to be added to this macro.
- * currently bf_status is the only one requires that
- * requires reset.
- */
#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0)
/* hw processing complete, desc processed by hal */
@@ -281,159 +280,81 @@ struct ath_descdma {
dma_addr_t dd_dmacontext;
};
-/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */
-
-struct ath_rx_context {
- struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */
-};
-#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb)
-
-int ath_descdma_setup(struct ath_softc *sc,
- struct ath_descdma *dd,
- struct list_head *head,
- const char *name,
- int nbuf,
- int ndesc);
-int ath_desc_alloc(struct ath_softc *sc);
-void ath_desc_free(struct ath_softc *sc);
-void ath_descdma_cleanup(struct ath_softc *sc,
- struct ath_descdma *dd,
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+ struct list_head *head, const char *name,
+ int nbuf, int ndesc);
+void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
struct list_head *head);
-/******/
-/* RX */
-/******/
-
-#define ATH_MAX_ANTENNA 3
-#define ATH_RXBUF 512
-#define ATH_RX_TIMEOUT 40 /* 40 milliseconds */
-#define WME_NUM_TID 16
-#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */
-#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */
-
-enum ATH_RX_TYPE {
- ATH_RX_NON_CONSUMED = 0,
- ATH_RX_CONSUMED
-};
-
-/* per frame rx status block */
-struct ath_recv_status {
- u64 tsf; /* mac tsf */
- int8_t rssi; /* RSSI (noise floor ajusted) */
- int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int8_t abs_rssi; /* absolute RSSI */
- u8 rateieee; /* data rate received (IEEE rate code) */
- u8 ratecode; /* phy rate code */
- int rateKbps; /* data rate received (Kbps) */
- int antenna; /* rx antenna */
- int flags; /* status of associated skb */
-#define ATH_RX_FCS_ERROR 0x01
-#define ATH_RX_MIC_ERROR 0x02
-#define ATH_RX_DECRYPT_ERROR 0x04
-#define ATH_RX_RSSI_VALID 0x08
-/* if any of ctl,extn chainrssis are valid */
-#define ATH_RX_CHAIN_RSSI_VALID 0x10
-/* if extn chain rssis are valid */
-#define ATH_RX_RSSI_EXTN_VALID 0x20
-/* set if 40Mhz, clear if 20Mhz */
-#define ATH_RX_40MHZ 0x40
-/* set if short GI, clear if full GI */
-#define ATH_RX_SHORT_GI 0x80
-};
-
-struct ath_rxbuf {
- struct sk_buff *rx_wbuf;
- unsigned long rx_time; /* system time when received */
- struct ath_recv_status rx_status; /* cached rx status */
-};
-
-/* Per-TID aggregate receiver state for a node */
-struct ath_arx_tid {
- struct ath_node *an;
- struct ath_rxbuf *rxbuf; /* re-ordering buffer */
- struct timer_list timer;
- spinlock_t tidlock;
- int baw_head; /* seq_next at head */
- int baw_tail; /* tail of block-ack window */
- int seq_reset; /* need to reset start sequence */
- int addba_exchangecomplete;
- u16 seq_next; /* next expected sequence */
- u16 baw_size; /* block-ack window size */
-};
-
-/* Per-node receiver aggregate state */
-struct ath_arx {
- struct ath_arx_tid tid[WME_NUM_TID];
-};
-
-int ath_startrecv(struct ath_softc *sc);
-bool ath_stoprecv(struct ath_softc *sc);
-void ath_flushrecv(struct ath_softc *sc);
-u32 ath_calcrxfilter(struct ath_softc *sc);
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
-void ath_handle_rx_intr(struct ath_softc *sc);
-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);
-int ath_rx_input(struct ath_softc *sc,
- struct ath_node *node,
- int is_ampdu,
- struct sk_buff *skb,
- struct ath_recv_status *rx_status,
- enum ATH_RX_TYPE *status);
-int _ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix);
-int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
- struct ath_recv_status *status);
-
-/******/
-/* TX */
-/******/
+/***********/
+/* RX / TX */
+/***********/
+#define ATH_MAX_ANTENNA 3
+#define ATH_RXBUF 512
+#define WME_NUM_TID 16
#define ATH_TXBUF 512
-/* max number of transmit attempts (tries) */
#define ATH_TXMAXTRY 13
-/* max number of 11n transmit attempts (tries) */
#define ATH_11N_TXMAXTRY 10
-/* max number of tries for management and control frames */
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
+
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
(((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
WME_AC_VO)
+#define WME_AC_BE 0
+#define WME_AC_BK 1
+#define WME_AC_VI 2
+#define WME_AC_VO 3
+#define WME_NUM_AC 4
+
+#define ADDBA_EXCHANGE_ATTEMPTS 10
+#define ATH_AGGR_DELIM_SZ 4
+#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM 10
+/* minimum h/w qdepth to be sustained to maximize aggregation */
+#define ATH_AGGR_MIN_QDEPTH 2
+#define ATH_AMPDU_SUBFRAME_DEFAULT 32
+#define IEEE80211_SEQ_SEQ_SHIFT 4
+#define IEEE80211_SEQ_MAX 4096
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
+
+/* return whether a bit at index _n in bitmap _bm is set
+ * _sz is the size of the bitmap */
+#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \
+ ((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
+
+/* return block-ack bitmap index given sequence and starting sequence */
+#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
+
+/* returns delimiter padding required given the packet length */
+#define ATH_AGGR_GET_NDELIM(_len) \
+ (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
+ (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 4095) < (_bawsz))
-/* Wireless Multimedia Extension Defines */
-#define WME_AC_BE 0 /* best effort */
-#define WME_AC_BK 1 /* background */
-#define WME_AC_VI 2 /* video */
-#define WME_AC_VO 3 /* voice */
-#define WME_NUM_AC 4
+#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum)
+#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low)
+#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
+#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
-enum ATH_SM_PWRSAV{
- ATH_SM_ENABLE,
- ATH_SM_PWRSAV_STATIC,
- ATH_SM_PWRSAV_DYNAMIC,
+enum ATH_AGGR_STATUS {
+ ATH_AGGR_DONE,
+ ATH_AGGR_BAW_CLOSED,
+ ATH_AGGR_LIMITED,
+ ATH_AGGR_SHORTPKT,
+ ATH_AGGR_8K_LIMITED,
};
-/*
- * Data transmit queue state. One of these exists for each
- * hardware transmit queue. Packets sent to us from above
- * are assigned to queues based on their priority. Not all
- * devices support a complete set of hardware transmit queues.
- * For those devices the array sc_ac2q will map multiple
- * priorities to fewer hardware queues (typically all to one
- * hardware queue).
- */
struct ath_txq {
u32 axq_qnum; /* hardware q number */
u32 *axq_link; /* link ptr in last TX desc */
@@ -443,10 +364,6 @@ struct ath_txq {
u32 axq_depth; /* queue depth */
u8 axq_aggr_depth; /* aggregates queued */
u32 axq_totalqueued; /* total ever queued */
-
- /* count to determine if descriptor should generate int on this txq. */
- u32 axq_intrcnt;
-
bool stopped; /* Is mac80211 queue stopped ? */
struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/
@@ -460,6 +377,10 @@ struct ath_txq {
struct list_head axq_acq;
};
+#define AGGR_CLEANUP BIT(1)
+#define AGGR_ADDBA_COMPLETE BIT(2)
+#define AGGR_ADDBA_PROGRESS BIT(3)
+
/* per TID aggregate tx state for a destination */
struct ath_atx_tid {
struct list_head list; /* round-robin tid entry */
@@ -475,9 +396,7 @@ struct ath_atx_tid {
int baw_tail; /* next unused tx buffer slot */
int sched;
int paused;
- int cleanup_inprogress;
- u32 addba_exchangecomplete:1;
- int32_t addba_exchangeinprogress;
+ u8 state;
int addba_exchangeattempts;
};
@@ -490,32 +409,10 @@ struct ath_atx_ac {
struct list_head tid_q; /* queue of TIDs with buffers */
};
-/* per dest tx state */
-struct ath_atx {
- struct ath_atx_tid tid[WME_NUM_TID];
- struct ath_atx_ac ac[WME_NUM_AC];
-};
-
/* per-frame tx control block */
struct ath_tx_control {
- struct ath_node *an;
+ struct ath_txq *txq;
int if_id;
- int qnum;
- u32 ht:1;
- u32 ps:1;
- u32 use_minrate:1;
- enum ath9k_pkt_type atype;
- enum ath9k_key_type keytype;
- u32 flags;
- u16 seqno;
- u16 tidno;
- u16 txpower;
- u16 frmlen;
- u32 keyix;
- int min_rate;
- int mcast_rate;
- struct ath_softc *dev;
- dma_addr_t dmacontext;
};
/* per frame tx status block */
@@ -528,21 +425,63 @@ struct ath_xmit_status {
#define ATH_TX_BAR 0x04
};
+/* All RSSI values are noise floor adjusted */
struct ath_tx_stat {
- int rssi; /* RSSI (noise floor ajusted) */
- int rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
- int rateieee; /* data rate xmitted (IEEE rate code) */
- int rateKbps; /* data rate xmitted (Kbps) */
- int ratecode; /* phy rate code */
- int flags; /* validity flags */
-/* if any of ctl,extn chain rssis are valid */
-#define ATH_TX_CHAIN_RSSI_VALID 0x01
-/* if extn chain rssis are valid */
-#define ATH_TX_RSSI_EXTN_VALID 0x02
+ int rssi;
+ int rssictl[ATH_MAX_ANTENNA];
+ int rssiextn[ATH_MAX_ANTENNA];
+ int rateieee;
+ int rateKbps;
+ int ratecode;
+ int flags;
u32 airtime; /* time on air per final tx rate */
};
+struct aggr_rifs_param {
+ int param_max_frames;
+ int param_max_len;
+ int param_rl;
+ int param_al;
+ struct ath_rc_series *param_rcs;
+};
+
+struct ath_node {
+ struct ath_softc *an_sc;
+ struct ath_atx_tid tid[WME_NUM_TID];
+ struct ath_atx_ac ac[WME_NUM_AC];
+ u16 maxampdu;
+ u8 mpdudensity;
+};
+
+struct ath_tx {
+ u16 seq_no;
+ u32 txqsetup;
+ int hwq_map[ATH9K_WME_AC_VO+1];
+ spinlock_t txbuflock;
+ struct list_head txbuf;
+ struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
+ struct ath_descdma txdma;
+};
+
+struct ath_rx {
+ u8 defant;
+ u8 rxotherant;
+ u32 *rxlink;
+ int bufsize;
+ unsigned int rxfilter;
+ spinlock_t rxflushlock;
+ spinlock_t rxbuflock;
+ struct list_head rxbuf;
+ struct ath_descdma rxdma;
+};
+
+int ath_startrecv(struct ath_softc *sc);
+bool ath_stoprecv(struct ath_softc *sc);
+void ath_flushrecv(struct ath_softc *sc);
+u32 ath_calcrxfilter(struct ath_softc *sc);
+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);
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_setup(struct ath_softc *sc, int haltype);
@@ -550,139 +489,51 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx);
void ath_tx_draintxq(struct ath_softc *sc,
struct ath_txq *txq, bool retry_tx);
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_tx_node_cleanup(struct ath_softc *sc,
- struct ath_node *an, bool bh_flag);
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
int ath_tx_cleanup(struct ath_softc *sc);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_tx_control *txctl);
void ath_tx_tasklet(struct ath_softc *sc);
u32 ath_txq_depth(struct ath_softc *sc, int qnum);
u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
-void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- struct ath_xmit_status *tx_status, struct ath_node *an);
void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
+void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
+void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-/**********************/
-/* Node / Aggregation */
-/**********************/
-
-/* indicates the node is clened up */
-#define ATH_NODE_CLEAN 0x1
-/* indicates the node is 80211 power save */
-#define ATH_NODE_PWRSAVE 0x2
-
-#define ADDBA_EXCHANGE_ATTEMPTS 10
-#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
-#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
-/* number of delimiters for encryption padding */
-#define ATH_AGGR_ENCRYPTDELIM 10
-/* minimum h/w qdepth to be sustained to maximize aggregation */
-#define ATH_AGGR_MIN_QDEPTH 2
-#define ATH_AMPDU_SUBFRAME_DEFAULT 32
-#define IEEE80211_SEQ_SEQ_SHIFT 4
-#define IEEE80211_SEQ_MAX 4096
-#define IEEE80211_MIN_AMPDU_BUF 0x8
-
-/* return whether a bit at index _n in bitmap _bm is set
- * _sz is the size of the bitmap */
-#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \
- ((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
-
-/* return block-ack bitmap index given sequence and starting sequence */
-#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
-
-/* returns delimiter padding required given the packet length */
-#define ATH_AGGR_GET_NDELIM(_len) \
- (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
- (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
-
-#define BAW_WITHIN(_start, _bawsz, _seqno) \
- ((((_seqno) - (_start)) & 4095) < (_bawsz))
-
-#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum)
-#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low)
-#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
-#define ATH_AN_2_TID(_an, _tidno) (&(_an)->an_aggr.tx.tid[(_tidno)])
-
-enum ATH_AGGR_STATUS {
- ATH_AGGR_DONE,
- ATH_AGGR_BAW_CLOSED,
- ATH_AGGR_LIMITED,
- ATH_AGGR_SHORTPKT,
- ATH_AGGR_8K_LIMITED,
-};
-
-enum ATH_AGGR_CHECK {
- AGGR_NOT_REQUIRED,
- AGGR_REQUIRED,
- AGGR_CLEANUP_PROGRESS,
- AGGR_EXCHANGE_PROGRESS,
- AGGR_EXCHANGE_DONE
-};
+/********/
+/* VAPs */
+/********/
-struct aggr_rifs_param {
- int param_max_frames;
- int param_max_len;
- int param_rl;
- int param_al;
- struct ath_rc_series *param_rcs;
-};
+/*
+ * Define the scheme that we select MAC address for multiple
+ * BSS on the same radio. The very first VAP will just use the MAC
+ * address from the EEPROM. For the next 3 VAPs, we set the
+ * U/L bit (bit 1) in MAC address, and use the next two bits as the
+ * index of the VAP.
+ */
-/* Per-node aggregation state */
-struct ath_node_aggr {
- struct ath_atx tx; /* node transmit state */
- struct ath_arx rx; /* node receive state */
-};
+#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
+ ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
-/* driver-specific node state */
-struct ath_node {
- struct list_head list;
- struct ath_softc *an_sc;
- atomic_t an_refcnt;
- struct ath_chainmask_sel an_chainmask_sel;
- struct ath_node_aggr an_aggr;
- u8 an_smmode; /* SM Power save mode */
- u8 an_flags;
- u8 an_addr[ETH_ALEN];
+struct ath_vap {
+ int av_bslot;
+ enum nl80211_iftype av_opmode;
+ struct ath_buf *av_bcbuf;
+ struct ath_tx_control av_btxctl;
};
-void ath_tx_resume_tid(struct ath_softc *sc,
- struct ath_atx_tid *tid);
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
- struct ath_node *an, u8 tidno);
-void ath_tx_aggr_teardown(struct ath_softc *sc,
- struct ath_node *an, u8 tidno);
-void ath_rx_aggr_teardown(struct ath_softc *sc,
- struct ath_node *an, u8 tidno);
-int ath_rx_aggr_start(struct ath_softc *sc,
- const u8 *addr,
- u16 tid,
- u16 *ssn);
-int ath_rx_aggr_stop(struct ath_softc *sc,
- const u8 *addr,
- u16 tid);
-int ath_tx_aggr_start(struct ath_softc *sc,
- const u8 *addr,
- u16 tid,
- u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc,
- const u8 *addr,
- u16 tid);
-void ath_newassoc(struct ath_softc *sc,
- struct ath_node *node, int isnew, int isuapsd);
-struct ath_node *ath_node_attach(struct ath_softc *sc,
- u8 addr[ETH_ALEN], int if_id);
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]);
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
-
/*******************/
/* Beacon Handling */
/*******************/
@@ -693,12 +544,11 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
* number of beacon intervals, the game's up.
*/
#define BSTUCK_THRESH (9 * ATH_BCBUF)
-#define ATH_BCBUF 4 /* number of beacon buffers */
-#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */
+#define ATH_BCBUF 1
+#define ATH_DEFAULT_BINTVAL 100 /* TU */
#define ATH_DEFAULT_BMISS_LIMIT 10
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
-/* beacon configuration */
struct ath_beacon_config {
u16 beacon_interval;
u16 listen_interval;
@@ -712,93 +562,32 @@ struct ath_beacon_config {
} u; /* last received beacon/probe response timestamp of this BSS. */
};
+struct ath_beacon {
+ enum {
+ OK, /* no change needed */
+ UPDATE, /* update pending */
+ COMMIT /* beacon sent, commit change */
+ } updateslot; /* slot time update fsm */
+
+ u32 beaconq;
+ u32 bmisscnt;
+ u32 ast_be_xmit;
+ u64 bc_tstamp;
+ int bslot[ATH_BCBUF];
+ int slottime;
+ int slotupdate;
+ struct ath9k_tx_queue_info beacon_qi;
+ struct ath_descdma bdma;
+ struct ath_txq *cabq;
+ struct list_head bbuf;
+};
+
void ath9k_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, int if_id);
int ath_beaconq_setup(struct ath_hal *ah);
int ath_beacon_alloc(struct ath_softc *sc, int if_id);
-void ath_bstuck_process(struct ath_softc *sc);
void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
void ath_beacon_sync(struct ath_softc *sc, int if_id);
-void ath_get_beaconconfig(struct ath_softc *sc,
- int if_id,
- struct ath_beacon_config *conf);
-/********/
-/* VAPs */
-/********/
-
-/*
- * Define the scheme that we select MAC address for multiple
- * BSS on the same radio. The very first VAP will just use the MAC
- * address from the EEPROM. For the next 3 VAPs, we set the
- * U/L bit (bit 1) in MAC address, and use the next two bits as the
- * index of the VAP.
- */
-
-#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
- ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
-
-/* VAP configuration (from protocol layer) */
-struct ath_vap_config {
- u32 av_fixed_rateset;
- u32 av_fixed_retryset;
-};
-
-/* driver-specific vap state */
-struct ath_vap {
- struct ieee80211_vif *av_if_data;
- enum ath9k_opmode av_opmode; /* VAP operational mode */
- struct ath_buf *av_bcbuf; /* beacon buffer */
- struct ath_tx_control av_btxctl; /* txctl information for beacon */
- int av_bslot; /* beacon slot index */
- struct ath_vap_config av_config;/* vap configuration parameters*/
- struct ath_rate_node *rc_node;
-};
-
-int ath_vap_attach(struct ath_softc *sc,
- int if_id,
- struct ieee80211_vif *if_data,
- enum ath9k_opmode opmode);
-int ath_vap_detach(struct ath_softc *sc, int if_id);
-int ath_vap_config(struct ath_softc *sc,
- int if_id, struct ath_vap_config *if_config);
-
-/*********************/
-/* Antenna diversity */
-/*********************/
-
-#define ATH_ANT_DIV_MAX_CFG 2
-#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */
-#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */
-
-enum ATH_ANT_DIV_STATE{
- ATH_ANT_DIV_IDLE,
- ATH_ANT_DIV_SCAN, /* evaluating antenna */
-};
-
-struct ath_antdiv {
- struct ath_softc *antdiv_sc;
- u8 antdiv_start;
- enum ATH_ANT_DIV_STATE antdiv_state;
- u8 antdiv_num_antcfg;
- u8 antdiv_curcfg;
- u8 antdiv_bestcfg;
- int32_t antdivf_rssitrig;
- int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG];
- u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG];
- u64 antdiv_laststatetsf;
- u8 antdiv_bssid[ETH_ALEN];
-};
-
-void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
- struct ath_softc *sc, int32_t rssitrig);
-void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
- u8 num_antcfg,
- const u8 *bssid);
-void ath_slow_ant_div_stop(struct ath_antdiv *antdiv);
-void ath_slow_ant_div(struct ath_antdiv *antdiv,
- struct ieee80211_hdr *wh,
- struct ath_rx_status *rx_stats);
-void ath_setdefantenna(void *sc, u32 antenna);
/*******/
/* ANI */
@@ -863,7 +652,7 @@ struct ath_rfkill {
#define DEFAULT_CACHELINE 32
#define ATH_DEFAULT_NOISE_FLOOR -95
#define ATH_REGCLASSIDS_MAX 10
-#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
+#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
#define ATH_MAX_SW_RETRIES 10
#define ATH_CHAN_MAX 255
#define IEEE80211_WEP_NKID 4 /* number of key ids */
@@ -876,34 +665,12 @@ struct ath_rfkill {
* Different parts have different size key caches. We handle
* up to ATH_KEYMAX entries (could dynamically allocate state).
*/
-#define ATH_KEYMAX 128 /* max key cache size we handle */
+#define ATH_KEYMAX 128 /* max key cache size we handle */
#define ATH_IF_ID_ANY 0xff
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
-
-#define RSSI_LPF_THRESHOLD -20
-#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
-#define ATH_RATE_DUMMY_MARKER 0
-#define ATH_RSSI_LPF_LEN 10
-#define ATH_RSSI_DUMMY_MARKER 0x127
-
-#define ATH_EP_MUL(x, mul) ((x) * (mul))
-#define ATH_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-#define ATH_RSSI_OUT(x) \
- (((x) != ATH_RSSI_DUMMY_MARKER) ? \
- (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER)
-#define ATH_RSSI_IN(x) \
- (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
-#define ATH_LPF_RSSI(x, y, len) \
- ((x != ATH_RSSI_DUMMY_MARKER) ? \
- (((x) * ((len) - 1) + (y)) / (len)) : (y))
-#define ATH_RSSI_LPF(x, y) do { \
- if ((y) >= RSSI_LPF_THRESHOLD) \
- x = ATH_LPF_RSSI((x), \
- ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
- } while (0)
-
+#define ATH_RSSI_DUMMY_MARKER 0x127
+#define ATH_RATE_DUMMY_MARKER 0
enum PROT_MODE {
PROT_M_NONE = 0,
@@ -911,19 +678,6 @@ enum PROT_MODE {
PROT_M_CTSONLY
};
-enum RATE_TYPE {
- NORMAL_RATE = 0,
- HALF_RATE,
- QUARTER_RATE
-};
-
-struct ath_ht_info {
- enum ath9k_ht_macmode tx_chan_width;
- u16 maxampdu;
- u8 mpdudensity;
- u8 ext_chan_offset;
-};
-
#define SC_OP_INVALID BIT(0)
#define SC_OP_BEACONS BIT(1)
#define SC_OP_RXAGGR BIT(2)
@@ -944,141 +698,57 @@ struct ath_softc {
struct pci_dev *pdev;
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
- struct ath_config sc_config;
struct ath_hal *sc_ah;
- struct ath_rate_softc *sc_rc;
void __iomem *mem;
+ spinlock_t sc_resetlock;
+ struct mutex mutex;
u8 sc_curbssid[ETH_ALEN];
u8 sc_myaddr[ETH_ALEN];
u8 sc_bssidmask[ETH_ALEN];
-
- int sc_debug;
u32 sc_intrstatus;
u32 sc_flags; /* SC_OP_* */
- unsigned int rx_filter;
u16 sc_curtxpow;
u16 sc_curaid;
u16 sc_cachelsz;
- int sc_slotupdate; /* slot to next advance fsm */
- int sc_slottime;
- int sc_bslot[ATH_BCBUF];
+ u8 sc_nbcnvaps;
+ u16 sc_nvaps;
u8 sc_tx_chainmask;
u8 sc_rx_chainmask;
+ u32 sc_keymax;
+ DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);
+ u8 sc_splitmic;
+ u8 sc_protrix;
enum ath9k_int sc_imask;
- enum wireless_mode sc_curmode; /* current phy mode */
enum PROT_MODE sc_protmode;
-
- u8 sc_nbcnvaps; /* # of vaps sending beacons */
- u16 sc_nvaps; /* # of active virtual ap's */
- struct ath_vap *sc_vaps[ATH_BCBUF];
-
- u8 sc_mcastantenna;
- u8 sc_defant; /* current default antenna */
- u8 sc_rxotherant; /* rx's on non-default antenna */
-
- struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
- struct list_head node_list;
- struct ath_ht_info sc_ht_info;
enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
+ enum ath9k_ht_macmode tx_chan_width;
-#ifdef CONFIG_SLOW_ANT_DIV
- struct ath_antdiv sc_antdiv;
-#endif
- enum {
- OK, /* no change needed */
- UPDATE, /* update pending */
- COMMIT /* beacon sent, commit change */
- } sc_updateslot; /* slot time update fsm */
-
- /* Crypto */
- u32 sc_keymax; /* size of key cache */
- DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */
- u8 sc_splitmic; /* split TKIP MIC keys */
-
- /* RX */
- struct list_head sc_rxbuf;
- struct ath_descdma sc_rxdma;
- int sc_rxbufsize; /* rx size based on mtu */
- u32 *sc_rxlink; /* link ptr in last RX desc */
-
- /* TX */
- struct list_head sc_txbuf;
- struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES];
- struct ath_descdma sc_txdma;
- u32 sc_txqsetup;
- u32 sc_txintrperiod; /* tx interrupt batching */
- int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */
- u16 seq_no; /* TX sequence number */
-
- /* Beacon */
- struct ath9k_tx_queue_info sc_beacon_qi;
- struct ath_descdma sc_bdma;
- struct ath_txq *sc_cabq;
- struct list_head sc_bbuf;
- u32 sc_bhalq;
- u32 sc_bmisscount;
- u32 ast_be_xmit; /* beacons transmitted */
- u64 bc_tstamp;
-
- /* Rate */
+ struct ath_config sc_config;
+ struct ath_rx rx;
+ struct ath_tx tx;
+ struct ath_beacon beacon;
+ struct ieee80211_vif *sc_vaps[ATH_BCBUF];
struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
- const struct ath9k_rate_table *sc_currates;
- u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */
- u8 sc_protrix; /* protection rate index */
- struct {
- u32 rateKbps; /* transfer rate in kbs */
- u8 ieeerate; /* IEEE rate */
- } sc_hwmap[256]; /* h/w rate ix mappings */
-
- /* Channel, Band */
+ struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
+ struct ath_rate_table *cur_rate_table;
struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
-
- /* Locks */
- spinlock_t sc_rxflushlock;
- spinlock_t sc_rxbuflock;
- spinlock_t sc_txbuflock;
- spinlock_t sc_resetlock;
- spinlock_t node_lock;
-
- /* LEDs */
struct ath_led radio_led;
struct ath_led assoc_led;
struct ath_led tx_led;
struct ath_led rx_led;
-
- /* Rfkill */
struct ath_rfkill rf_kill;
-
- /* ANI */
struct ath_ani sc_ani;
+ struct ath9k_node_stats sc_halstats;
+#ifdef CONFIG_ATH9K_DEBUG
+ struct ath9k_debug sc_debug;
+#endif
};
-int ath_init(u16 devid, struct ath_softc *sc);
-void ath_deinit(struct ath_softc *sc);
-int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-int ath_suspend(struct ath_softc *sc);
-irqreturn_t ath_isr(int irq, void *dev);
int ath_reset(struct ath_softc *sc, bool retry_tx);
-int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
-
-/*********************/
-/* Utility Functions */
-/*********************/
-
-void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot);
-int ath_keyset(struct ath_softc *sc,
- u16 keyix,
- struct ath9k_keyval *hk,
- const u8 mac[ETH_ALEN]);
int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
-void ath_setslottime(struct ath_softc *sc);
-void ath_update_txpow(struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
-void ath_get_currentCountry(struct ath_softc *sc,
- struct ath9k_country_entry *ctry);
-u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c
new file mode 100644
index 00000000000..a80ed576830
--- /dev/null
+++ b/drivers/net/wireless/ath9k/debug.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "reg.h"
+#include "hw.h"
+
+static unsigned int ath9k_debug = DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+
+void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
+{
+ if (!sc)
+ return;
+
+ if (sc->sc_debug.debug_mask & dbg_mask) {
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "ath9k: ");
+ vprintk(fmt, args);
+ va_end(args);
+ }
+}
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t read_file_dma(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hal *ah = sc->sc_ah;
+ char buf[1024];
+ unsigned int len = 0;
+ u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
+ int i, qcuOffset = 0, dcuOffset = 0;
+ u32 *qcuBase = &val[0], *dcuBase = &val[4];
+
+ REG_WRITE(ah, AR_MACMISC,
+ ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+ (AR_MACMISC_MISC_OBS_BUS_1 <<
+ AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "Raw DMA Debug values:\n");
+
+ for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
+ if (i % 4 == 0)
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+ len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
+ i, val[i]);
+ }
+
+ len += snprintf(buf + len, sizeof(buf) - len, "\n\n");
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+
+ for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
+ if (i == 8) {
+ qcuOffset = 0;
+ qcuBase++;
+ }
+
+ if (i == 6) {
+ dcuOffset = 0;
+ dcuBase++;
+ }
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%2d %2x %1x %2x %2x\n",
+ i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+ (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
+ val[2] & (0x7 << (i * 3)) >> (i * 3),
+ (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+ }
+
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "qcu_stitch state: %2x qcu_fetch state: %2x\n",
+ (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "qcu_complete state: %2x dcu_complete state: %2x\n",
+ (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "dcu_arb state: %2x dcu_fp state: %2x\n",
+ (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
+ (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
+ (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
+ (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
+
+ len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
+ REG_READ(ah, AR_OBS_BUS_1));
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_dma = {
+ .read = read_file_dma,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
+{
+ if (status)
+ sc->sc_debug.stats.istats.total++;
+ if (status & ATH9K_INT_RX)
+ sc->sc_debug.stats.istats.rxok++;
+ if (status & ATH9K_INT_RXEOL)
+ sc->sc_debug.stats.istats.rxeol++;
+ if (status & ATH9K_INT_RXORN)
+ sc->sc_debug.stats.istats.rxorn++;
+ if (status & ATH9K_INT_TX)
+ sc->sc_debug.stats.istats.txok++;
+ if (status & ATH9K_INT_TXURN)
+ sc->sc_debug.stats.istats.txurn++;
+ if (status & ATH9K_INT_MIB)
+ sc->sc_debug.stats.istats.mib++;
+ if (status & ATH9K_INT_RXPHY)
+ sc->sc_debug.stats.istats.rxphyerr++;
+ if (status & ATH9K_INT_RXKCM)
+ sc->sc_debug.stats.istats.rx_keycache_miss++;
+ if (status & ATH9K_INT_SWBA)
+ sc->sc_debug.stats.istats.swba++;
+ if (status & ATH9K_INT_BMISS)
+ sc->sc_debug.stats.istats.bmiss++;
+ if (status & ATH9K_INT_BNR)
+ sc->sc_debug.stats.istats.bnr++;
+ if (status & ATH9K_INT_CST)
+ sc->sc_debug.stats.istats.cst++;
+ if (status & ATH9K_INT_GTT)
+ sc->sc_debug.stats.istats.gtt++;
+ if (status & ATH9K_INT_TIM)
+ sc->sc_debug.stats.istats.tim++;
+ if (status & ATH9K_INT_CABEND)
+ sc->sc_debug.stats.istats.cabend++;
+ if (status & ATH9K_INT_DTIMSYNC)
+ sc->sc_debug.stats.istats.dtimsync++;
+ if (status & ATH9K_INT_DTIM)
+ sc->sc_debug.stats.istats.dtim++;
+}
+
+static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_interrupt = {
+ .read = read_file_interrupt,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+int ath9k_init_debug(struct ath_softc *sc)
+{
+ sc->sc_debug.debug_mask = ath9k_debug;
+
+ sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!sc->sc_debug.debugfs_root)
+ goto err;
+
+ sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
+ sc->sc_debug.debugfs_root);
+ if (!sc->sc_debug.debugfs_phy)
+ goto err;
+
+ sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+ sc->sc_debug.debugfs_phy, sc, &fops_dma);
+ if (!sc->sc_debug.debugfs_dma)
+ goto err;
+
+ sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt",
+ S_IRUGO,
+ sc->sc_debug.debugfs_phy,
+ sc, &fops_interrupt);
+ if (!sc->sc_debug.debugfs_interrupt)
+ goto err;
+
+ return 0;
+err:
+ ath9k_exit_debug(sc);
+ return -ENOMEM;
+}
+
+void ath9k_exit_debug(struct ath_softc *sc)
+{
+ debugfs_remove(sc->sc_debug.debugfs_interrupt);
+ debugfs_remove(sc->sc_debug.debugfs_dma);
+ debugfs_remove(sc->sc_debug.debugfs_phy);
+ debugfs_remove(sc->sc_debug.debugfs_root);
+}
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
new file mode 100644
index 00000000000..acd6c5374d4
--- /dev/null
+++ b/drivers/net/wireless/ath9k/eeprom.c
@@ -0,0 +1,2824 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+ u32 reg, u32 mask,
+ u32 shift, u32 val)
+{
+ u32 regVal;
+
+ regVal = REG_READ(ah, reg) & ~mask;
+ regVal |= (val << shift) & mask;
+
+ REG_WRITE(ah, reg, regVal);
+
+ if (ah->ah_config.analog_shiftreg)
+ udelay(100);
+
+ return;
+}
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+
+ if (fbin == AR5416_BCHAN_UNUSED)
+ return fbin;
+
+ return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static inline int16_t ath9k_hw_interpolate(u16 target,
+ u16 srcLeft, u16 srcRight,
+ int16_t targetLeft,
+ int16_t targetRight)
+{
+ int16_t rv;
+
+ if (srcRight == srcLeft) {
+ rv = targetLeft;
+ } else {
+ rv = (int16_t) (((target - srcLeft) * targetRight +
+ (srcRight - target) * targetLeft) /
+ (srcRight - srcLeft));
+ }
+ return rv;
+}
+
+static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
+ u16 listSize, u16 *indexL,
+ u16 *indexR)
+{
+ u16 i;
+
+ if (target <= pList[0]) {
+ *indexL = *indexR = 0;
+ return true;
+ }
+ if (target >= pList[listSize - 1]) {
+ *indexL = *indexR = (u16) (listSize - 1);
+ return true;
+ }
+
+ for (i = 0; i < listSize - 1; i++) {
+ if (pList[i] == target) {
+ *indexL = *indexR = i;
+ return true;
+ }
+ if (target < pList[i + 1]) {
+ *indexL = i;
+ *indexR = (u16) (i + 1);
+ return false;
+ }
+ }
+ return false;
+}
+
+static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+ (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+ if (!ath9k_hw_wait(ah,
+ AR_EEPROM_STATUS_DATA,
+ AR_EEPROM_STATUS_DATA_BUSY |
+ AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+ return false;
+ }
+
+ *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+ AR_EEPROM_STATUS_DATA_VAL);
+
+ return true;
+}
+
+static int ath9k_hw_flash_map(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+
+ if (!ahp->ah_cal_mem) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "cannot remap eeprom region \n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ *data = ioread16(ahp->ah_cal_mem + off);
+
+ return true;
+}
+
+static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+ if (ath9k_hw_use_flash(ah))
+ return ath9k_hw_flash_read(ah, off, data);
+ else
+ return ath9k_hw_eeprom_read(ah, off, data);
+}
+
+static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah)
+{
+#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+ u16 *eep_data;
+ int addr, eep_start_loc = 0;
+
+ eep_start_loc = 64;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
+ }
+
+ eep_data = (u16 *)eep;
+
+ for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+#undef SIZE_EEPROM_4K
+}
+
+static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah)
+{
+#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ u16 *eep_data;
+ int addr, ar5416_eep_start_loc = 0x100;
+
+ eep_data = (u16 *)eep;
+
+ for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+ eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Unable to read eeprom region\n");
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+#undef SIZE_EEPROM_DEF
+}
+
+static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = {
+ ath9k_hw_fill_def_eeprom,
+ ath9k_hw_fill_4k_eeprom
+};
+
+static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_fill_eeprom[ahp->ah_eep_map](ah);
+}
+
+static int ath9k_hw_check_def_eeprom(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep =
+ (struct ar5416_eeprom_def *) &ahp->ah_eeprom.def;
+ u16 *eepdata, temp, magic, magic2;
+ u32 sum = 0, el;
+ bool need_swap = false;
+ int i, addr, size;
+
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Reading Magic # failed\n");
+ return false;
+ }
+
+ if (!ath9k_hw_use_flash(ah)) {
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ size = sizeof(struct ar5416_eeprom_def);
+ need_swap = true;
+ eepdata = (u16 *) (&ahp->ah_eeprom);
+
+ for (addr = 0; addr < size / sizeof(u16); addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "0x%04X ", *eepdata);
+
+ if (((addr + 1) % 6) == 0)
+ DPRINTF(ah->ah_sc,
+ ATH_DBG_EEPROM, "\n");
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
+
+ if (need_swap)
+ el = swab16(ahp->ah_eeprom.def.baseEepHeader.length);
+ else
+ el = ahp->ah_eeprom.def.baseEepHeader.length;
+
+ if (el > sizeof(struct ar5416_eeprom_def))
+ el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *)(&ahp->ah_eeprom);
+
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ u32 integer, j;
+ u16 word;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing \n");
+
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+ struct modal_eep_header *pModal =
+ &eep->modalHeader[j];
+ integer = swab32(pModal->antCtrlCommon);
+ pModal->antCtrlCommon = integer;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ integer = swab32(pModal->antCtrlChain[i]);
+ pModal->antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(pModal->spurChans[i].spurChan);
+ pModal->spurChans[i].spurChan = word;
+ }
+ }
+ }
+
+ if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
+ ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ar5416_get_eep_ver(ahp));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah)
+{
+#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep =
+ (struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k;
+ u16 *eepdata, temp, magic, magic2;
+ u32 sum = 0, el;
+ bool need_swap = false;
+ int i, addr;
+
+
+ if (!ath9k_hw_use_flash(ah)) {
+
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Reading Magic # failed\n");
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
+
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ need_swap = true;
+ eepdata = (u16 *) (&ahp->ah_eeprom);
+
+ for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "0x%04X ", *eepdata);
+
+ if (((addr + 1) % 6) == 0)
+ DPRINTF(ah->ah_sc,
+ ATH_DBG_EEPROM, "\n");
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
+
+ if (need_swap)
+ el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length);
+ else
+ el = ahp->ah_eeprom.map4k.baseEepHeader.length;
+
+ if (el > sizeof(struct ar5416_eeprom_def))
+ el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *)(&ahp->ah_eeprom);
+
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ u32 integer;
+ u16 word;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing \n");
+
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ integer = swab32(eep->modalHeader.antCtrlCommon);
+ eep->modalHeader.antCtrlCommon = integer;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ integer = swab32(eep->modalHeader.antCtrlChain[i]);
+ eep->modalHeader.antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(eep->modalHeader.spurChans[i].spurChan);
+ eep->modalHeader.spurChans[i].spurChan = word;
+ }
+ }
+
+ if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER ||
+ ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ar5416_get_eep4k_ver(ahp));
+ return -EINVAL;
+ }
+
+ return 0;
+#undef EEPROM_4K_SIZE
+}
+
+static int (*ath9k_check_eeprom[]) (struct ath_hal *) = {
+ ath9k_hw_check_def_eeprom,
+ ath9k_hw_check_4k_eeprom
+};
+
+static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_check_eeprom[ahp->ah_eep_map](ah);
+}
+
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+ u8 *pVpdList, u16 numIntercepts,
+ u8 *pRetVpdList)
+{
+ u16 i, k;
+ u8 currPwr = pwrMin;
+ u16 idxL = 0, idxR = 0;
+
+ for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+ ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+ numIntercepts, &(idxL),
+ &(idxR));
+ if (idxR < 1)
+ idxR = 1;
+ if (idxL == numIntercepts - 1)
+ idxL = (u16) (numIntercepts - 2);
+ if (pPwrList[idxL] == pPwrList[idxR])
+ k = pVpdList[idxL];
+ else
+ k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+ (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+ (pPwrList[idxR] - pPwrList[idxL]));
+ pRetVpdList[i] = (u8) k;
+ currPwr += 2;
+ }
+
+ return true;
+}
+
+static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_4k *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+#define TMP_VAL_VPD_TABLE \
+ ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+#define PD_GAIN_BOUNDARY_DEFAULT 58;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index(
+ (u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)), bChans, numPiers,
+ &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR5416_EEP4K_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t)((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1)))
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT;
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+
+ return;
+#undef TMP_VAL_VPD_TABLE
+}
+
+static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap, int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries, u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans, numPiers, &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8)(ath9k_hw_interpolate((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
+ }
+ }
+ }
+
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+ k = 0;
+
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t)(0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t)((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+ tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+ }
+
+ vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex) &&
+ (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+ (ss - maxIndex + 1) * vpdStep));
+ pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+ 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR5416_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+
+ return;
+}
+
+static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_leg *powInfo,
+ u16 numChannels,
+ struct cal_target_power_leg *pNewPower,
+ u16 numRates, bool isExtTarget)
+{
+ struct chan_centers centers;
+ u16 clo, chi;
+ int i;
+ int matchIndex = -1, lowIndex = -1;
+ u16 freq;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+ if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = 0;
+ } else {
+ for (i = 0; (i < numChannels) &&
+ (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = i;
+ break;
+ } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) &&
+ (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan)))) {
+ lowIndex = i - 1;
+ break;
+ }
+ }
+ if ((matchIndex == -1) && (lowIndex == -1))
+ matchIndex = i - 1;
+ }
+
+ if (matchIndex != -1) {
+ *pNewPower = powInfo[matchIndex];
+ } else {
+ clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+ IS_CHAN_2GHZ(chan));
+ chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+ IS_CHAN_2GHZ(chan));
+
+ for (i = 0; i < numRates; i++) {
+ pNewPower->tPow2x[i] =
+ (u8)ath9k_hw_interpolate(freq, clo, chi,
+ powInfo[lowIndex].tPow2x[i],
+ powInfo[lowIndex + 1].tPow2x[i]);
+ }
+ }
+}
+
+static void ath9k_hw_get_target_powers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_ht *powInfo,
+ u16 numChannels,
+ struct cal_target_power_ht *pNewPower,
+ u16 numRates, bool isHt40Target)
+{
+ struct chan_centers centers;
+ u16 clo, chi;
+ int i;
+ int matchIndex = -1, lowIndex = -1;
+ u16 freq;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+ if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+ matchIndex = 0;
+ } else {
+ for (i = 0; (i < numChannels) &&
+ (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = i;
+ break;
+ } else
+ if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) &&
+ (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan)))) {
+ lowIndex = i - 1;
+ break;
+ }
+ }
+ if ((matchIndex == -1) && (lowIndex == -1))
+ matchIndex = i - 1;
+ }
+
+ if (matchIndex != -1) {
+ *pNewPower = powInfo[matchIndex];
+ } else {
+ clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+ IS_CHAN_2GHZ(chan));
+ chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+ IS_CHAN_2GHZ(chan));
+
+ for (i = 0; i < numRates; i++) {
+ pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+ clo, chi,
+ powInfo[lowIndex].tPow2x[i],
+ powInfo[lowIndex + 1].tPow2x[i]);
+ }
+ }
+}
+
+static u16 ath9k_hw_get_max_edge_power(u16 freq,
+ struct cal_ctl_edges *pRdEdgesPower,
+ bool is2GHz, int num_band_edges)
+{
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ int i;
+
+ for (i = 0; (i < num_band_edges) &&
+ (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+ twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+ break;
+ } else if ((i > 0) &&
+ (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+ is2GHz))) {
+ if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+ is2GHz) < freq &&
+ pRdEdgesPower[i - 1].flag) {
+ twiceMaxEdgePower =
+ pRdEdgesPower[i - 1].tPower;
+ }
+ break;
+ }
+ }
+
+ return twiceMaxEdgePower;
+}
+
+static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+ struct cal_data_per_freq *pRawDataset;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+ u16 numPiers, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+ u32 reg32, regOffset, regChainOffset;
+ int16_t modalIdx;
+
+ modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+ xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ pdGainOverlap_t2 =
+ pEepData->modalHeader[modalIdx].pdGainOverlap;
+ } else {
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR5416_NUM_2G_CAL_PIERS;
+ } else {
+ pCalBChans = pEepData->calFreqPier5G;
+ numPiers = AR5416_NUM_5G_CAL_PIERS;
+ }
+
+ numXpdGain = 0;
+
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR5416_PD_GAINS_IN_MASK - i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_5416_V20_OR_LATER(ah) &&
+ (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+ (i != 0)) {
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ } else
+ regChainOffset = i * 0x1000;
+
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ if (IS_CHAN_2GHZ(chan))
+ pRawDataset = pEepData->calPierData2G[i];
+ else
+ pRawDataset = pEepData->calPierData5G[i];
+
+ ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset, pCalBChans,
+ numPiers, pdGainOverlap_t2,
+ &tMinCalPower, gainBoundaries,
+ pdadcValues, numXpdGain);
+
+ if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+
+ regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+ ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+ ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+ ((pdadcValues[4 * j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "PDADC: Chain %d | PDADC %3d "
+ "Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d "
+ "Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+
+ return true;
+}
+
+static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+ struct cal_data_per_freq_4k *pRawDataset;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+ u16 numPiers, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+ u32 reg32, regOffset, regChainOffset;
+
+ xpdMask = pEepData->modalHeader.xpdGain;
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ pdGainOverlap_t2 =
+ pEepData->modalHeader.pdGainOverlap;
+ } else {
+ pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ }
+
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR5416_NUM_2G_CAL_PIERS;
+
+ numXpdGain = 0;
+
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16)(AR5416_PD_GAINS_IN_MASK - i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_5416_V20_OR_LATER(ah) &&
+ (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+ (i != 0)) {
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ } else
+ regChainOffset = i * 0x1000;
+
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ pRawDataset = pEepData->calPierData2G[i];
+
+ ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset, pCalBChans,
+ numPiers, pdGainOverlap_t2,
+ &tMinCalPower, gainBoundaries,
+ pdadcValues, numXpdGain);
+
+ if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+
+ regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+ ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+ ((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+ ((pdadcValues[4 * j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+
+ *pTxPowerIndexOffset = 0;
+
+ return true;
+}
+
+static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */
+
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+ int i;
+ int16_t twiceLargestAntenna;
+ struct cal_ctl_data *rep;
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+ struct cal_target_power_leg targetPowerOfdmExt = {
+ 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+ 0, { 0, 0, 0, 0 }
+ };
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11a[] =
+ { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+ u16 ctlModesFor11g[] =
+ { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+ CTL_2GHT40
+ };
+ u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u16 twiceMinEdgePower;
+
+ tx_chainmask = ahp->ah_txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = max(
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+ twiceLargestAntenna = max((u8)twiceLargestAntenna,
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+ twiceLargestAntenna = (int16_t)min(AntennaReduction -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+ if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+ }
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+ break;
+ case 2:
+ scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+ break;
+ case 3:
+ scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+ break;
+ }
+
+ scaledPower = max((u16)0, scaledPower);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+ SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR5416_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ } else {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+ SUB_NUM_CTL_MODES_AT_5G_40;
+ pCtlMode = ctlModesFor11a;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower5GHT20,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower5GHT40,
+ AR5416_NUM_5G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+ "EXT_ADDITIVE %d\n",
+ ctlMode, numCtlModes, isHt40CtlMode,
+ (pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+ for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+ "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+ "chan %d\n",
+ i, cfgCtl, pCtlMode[ctlMode],
+ pEepData->ctlIndex[i], chan->channel);
+
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+ rep = &(pEepData->ctlData[i]);
+
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+ rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+ IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " MATCH-EE_IDX %d: ch %d is2 %d "
+ "2xMinEdge %d chainmask %d chains %d\n",
+ i, freq, IS_CHAN_2GHZ(chan),
+ twiceMinEdgePower, tx_chainmask,
+ ar5416_get_ntxchains
+ (tx_chainmask));
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower = min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " SEL-Min ctlMode %d pCtlMode %d "
+ "2xMaxEdge %d sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+ targetPowerCck.tPow2x[i] =
+ min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+ targetPowerOfdm.tPow2x[i] =
+ min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+ targetPowerHt20.tPow2x[i] =
+ min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] = min((u16)
+ targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11A_EXT:
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] = min((u16)
+ targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ targetPowerHt40.tPow2x[i] =
+ min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] =
+ targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+ targetPowerCck.tPow2x[2];
+ ;
+ ratesArray[rate11s] = ratesArray[rate11l] =
+ targetPowerCck.tPow2x[3];
+ ;
+ }
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ ratesArray[rateHt40_0 + i] =
+ targetPowerHt40.tPow2x[i];
+ }
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rateExtCck] =
+ targetPowerCckExt.tPow2x[0];
+ }
+ }
+ return true;
+}
+
+static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+ int i;
+ int16_t twiceLargestAntenna;
+ struct cal_ctl_data_4k *rep;
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+ struct cal_target_power_leg targetPowerOfdmExt = {
+ 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+ 0, { 0, 0, 0, 0 }
+ };
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+ u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11g[] =
+ { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+ CTL_2GHT40
+ };
+ u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u16 twiceMinEdgePower;
+
+ tx_chainmask = ahp->ah_txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
+
+ twiceLargestAntenna = (int16_t)min(AntennaReduction -
+ twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+ if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+ }
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+ scaledPower = max((u16)0, scaledPower);
+
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4, false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4, false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT40,
+ AR5416_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt, 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt, 4, true);
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+ (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ar5416_get_eep_ver(ahp) == 14 &&
+ ar5416_get_eep_rev(ahp) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+ "EXT_ADDITIVE %d\n",
+ ctlMode, numCtlModes, isHt40CtlMode,
+ (pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+ for (i = 0; (i < AR5416_NUM_CTLS) &&
+ pEepData->ctlIndex[i]; i++) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+ "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+ "chan %d\n",
+ i, cfgCtl, pCtlMode[ctlMode],
+ pEepData->ctlIndex[i], chan->channel);
+
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i]) ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) |
+ SD_NO_CTL))) {
+ rep = &(pEepData->ctlData[i]);
+
+ twiceMinEdgePower =
+ ath9k_hw_get_max_edge_power(freq,
+ rep->ctlEdges[ar5416_get_ntxchains
+ (tx_chainmask) - 1],
+ IS_CHAN_2GHZ(chan),
+ AR5416_EEP4K_NUM_BAND_EDGES);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " MATCH-EE_IDX %d: ch %d is2 %d "
+ "2xMinEdge %d chainmask %d chains %d\n",
+ i, freq, IS_CHAN_2GHZ(chan),
+ twiceMinEdgePower, tx_chainmask,
+ ar5416_get_ntxchains
+ (tx_chainmask));
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower =
+ min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
+ twiceMaxEdgePower = twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " SEL-Min ctlMode %d pCtlMode %d "
+ "2xMaxEdge %d sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
+ i++) {
+ targetPowerCck.tPow2x[i] =
+ min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11G:
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
+ i++) {
+ targetPowerOfdm.tPow2x[i] =
+ min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_2GHT20:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
+ i++) {
+ targetPowerHt20.tPow2x[i] =
+ min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] = min((u16)
+ targetPowerCckExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] = min((u16)
+ targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
+ break;
+ case CTL_2GHT40:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
+ i++) {
+ targetPowerHt40.tPow2x[i] =
+ min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3];
+
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ ratesArray[rateHt40_0 + i] =
+ targetPowerHt40.tPow2x[i];
+ }
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+ }
+ return true;
+}
+
+static int ath9k_hw_def_set_txpower(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def;
+ struct modal_eep_header *pModal =
+ &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ }
+
+ if (!ath9k_hw_set_def_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set "
+ "tx power per rate table\n");
+ return -EIO;
+ }
+
+ if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set power table\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+ ratesArray[i] = AR5416_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+ if (IS_CHAN_HT40(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+ ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+ | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+ i = rate6mb;
+
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ah_maxPowerLevel =
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ else
+ ah->ah_maxPowerLevel = ratesArray[i];
+
+ return 0;
+}
+
+static int ath9k_hw_4k_set_txpower(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ }
+
+ if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set "
+ "tx power per rate table\n");
+ return -EIO;
+ }
+
+ if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set power table\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+ ratesArray[i] = AR5416_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+ if (IS_CHAN_2GHZ(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+ if (IS_CHAN_HT40(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0));
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0));
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+ }
+
+ i = rate6mb;
+
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ah_maxPowerLevel =
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ else
+ ah->ah_maxPowerLevel = ratesArray[i];
+
+ return 0;
+}
+
+static int (*ath9k_set_txpower[]) (struct ath_hal *,
+ struct ath9k_channel *,
+ u16, u8, u8, u8) = {
+ ath9k_hw_def_set_txpower,
+ ath9k_hw_4k_set_txpower
+};
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl,
+ twiceAntennaReduction, twiceMaxRegulatoryPower,
+ powerLimit);
+}
+
+static void ath9k_hw_set_def_addac(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
+ struct modal_eep_header *pModal;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ u8 biaslevel;
+
+ if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+ return;
+
+ if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+ return;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ if (pModal->xpaBiasLvl != 0xff) {
+ biaslevel = pModal->xpaBiasLvl;
+ } else {
+ u16 resetFreqBin, freqBin, freqCount = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ resetFreqBin = FREQ2FBIN(centers.synth_center,
+ IS_CHAN_2GHZ(chan));
+ freqBin = XPA_LVL_FREQ(0) & 0xff;
+ biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
+
+ freqCount++;
+
+ while (freqCount < 3) {
+ if (XPA_LVL_FREQ(freqCount) == 0x0)
+ break;
+
+ freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
+ if (resetFreqBin >= freqBin)
+ biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
+ else
+ break;
+ freqCount++;
+ }
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac,
+ 7, 1) & (~0x18)) | biaslevel << 3;
+ } else {
+ INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac,
+ 6, 1) & (~0xc0)) | biaslevel << 6;
+ }
+#undef XPA_LVL_FREQ
+}
+
+static void ath9k_hw_set_4k_addac(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_4k_header *pModal;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+ u8 biaslevel;
+
+ if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+ return;
+
+ if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+ return;
+
+ pModal = &eep->modalHeader;
+
+ if (pModal->xpaBiasLvl != 0xff) {
+ biaslevel = pModal->xpaBiasLvl;
+ INI_RA(&ahp->ah_iniAddac, 7, 1) =
+ (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+ }
+}
+
+static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = {
+ ath9k_hw_set_def_addac,
+ ath9k_hw_set_4k_addac
+};
+
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ath9k_set_addac[ahp->ah_eep_map](ah, chan);
+}
+
+
+
+/* XXX: Clean me up, make me more legible */
+static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_header *pModal;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ int i, regChainOffset;
+ u8 txRxAttenLocal;
+ u16 ant_config;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+ ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_9280(ah)) {
+ if (i >= 2)
+ break;
+ }
+
+ if (AR_SREV_5416_V20_OR_LATER(ah) &&
+ (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+ && (i != 0))
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ else
+ regChainOffset = i * 0x1000;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[i]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_TIMING_CTRL4(0) +
+ regChainOffset) &
+ ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+ if ((eep->baseEepHeader.version &
+ AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->
+ bswMargin[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+ pModal->
+ bswAtten[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->
+ xatten2Margin[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->
+ xatten2Db[i]);
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+ | SM(pModal->
+ bswMargin[i],
+ AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+ | SM(pModal->bswAtten[i],
+ AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+ }
+ }
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN,
+ txRxAttenLocal);
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN,
+ pModal->rxTxMarginCh[i]);
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_RXGAIN + regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset) &
+ ~AR_PHY_RXGAIN_TXRX_ATTEN) |
+ SM(txRxAttenLocal,
+ AR_PHY_RXGAIN_TXRX_ATTEN));
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+ SM(pModal->rxTxMarginCh[i],
+ AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+ }
+ }
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (IS_CHAN_2GHZ(chan)) {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_OB,
+ AR_AN_RF2G1_CH0_OB_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_DB,
+ AR_AN_RF2G1_CH0_DB_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_OB,
+ AR_AN_RF2G1_CH1_OB_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_DB,
+ AR_AN_RF2G1_CH1_DB_S,
+ pModal->db_ch1);
+ } else {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_OB5,
+ AR_AN_RF5G1_CH0_OB5_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_DB5,
+ AR_AN_RF5G1_CH0_DB5_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_OB5,
+ AR_AN_RF5G1_CH1_OB5_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_DB5,
+ AR_AN_RF5G1_CH1_DB5_S,
+ pModal->db_ch1);
+ }
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_XPABIAS_LVL,
+ AR_AN_TOP2_XPABIAS_LVL_S,
+ pModal->xpaBiasLvl);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_LOCALBIAS,
+ AR_AN_TOP2_LOCALBIAS_S,
+ pModal->local_bias);
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n",
+ pModal->force_xpaon);
+ REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+ pModal->force_xpaon);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+ pModal->switchSettling);
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+ pModal->adcDesiredSize);
+
+ if (!AR_SREV_9280_10_OR_LATER(ah))
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_PGA,
+ pModal->pgaDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+ | SM(pModal->txEndToXpaOff,
+ AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+ pModal->txEndToRxOn);
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+ AR_PHY_EXT_CCA0_THRESH62,
+ pModal->thresh62);
+ } else {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CCA_THRESH62,
+ pModal->thresh62);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_DATA_START,
+ pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ pModal->txFrameToPaOn);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH,
+ pModal->swSettleHt40);
+ }
+
+ return true;
+}
+
+static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_4k_header *pModal;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+ int regChainOffset;
+ u8 txRxAttenLocal;
+ u16 ant_config = 0;
+ u8 ob[5], db1[5], db2[5];
+ u8 ant_div_control1, ant_div_control2;
+ u32 regVal;
+
+
+ pModal = &eep->modalHeader;
+
+ txRxAttenLocal = 23;
+
+ ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config);
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+ regChainOffset = 0;
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[0]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+ ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[0];
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+ if (AR_SREV_9285_11(ah))
+ REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+
+ /* Initialize Ant Diversity settings from EEPROM */
+ if (pModal->version == 3) {
+ ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
+ ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
+ regVal = REG_READ(ah, 0x99ac);
+ regVal &= (~(0x7f000000));
+ regVal |= ((ant_div_control1 & 0x1) << 24);
+ regVal |= (((ant_div_control1 >> 1) & 0x1) << 29);
+ regVal |= (((ant_div_control1 >> 2) & 0x1) << 30);
+ regVal |= ((ant_div_control2 & 0x3) << 25);
+ regVal |= (((ant_div_control2 >> 2) & 0x3) << 27);
+ REG_WRITE(ah, 0x99ac, regVal);
+ regVal = REG_READ(ah, 0x99ac);
+ regVal = REG_READ(ah, 0xa208);
+ regVal &= (~(0x1 << 13));
+ regVal |= (((ant_div_control1 >> 3) & 0x1) << 13);
+ REG_WRITE(ah, 0xa208, regVal);
+ regVal = REG_READ(ah, 0xa208);
+ }
+
+ if (pModal->version >= 2) {
+ ob[0] = (pModal->ob_01 & 0xf);
+ ob[1] = (pModal->ob_01 >> 4) & 0xf;
+ ob[2] = (pModal->ob_234 & 0xf);
+ ob[3] = ((pModal->ob_234 >> 4) & 0xf);
+ ob[4] = ((pModal->ob_234 >> 8) & 0xf);
+
+ db1[0] = (pModal->db1_01 & 0xf);
+ db1[1] = ((pModal->db1_01 >> 4) & 0xf);
+ db1[2] = (pModal->db1_234 & 0xf);
+ db1[3] = ((pModal->db1_234 >> 4) & 0xf);
+ db1[4] = ((pModal->db1_234 >> 8) & 0xf);
+
+ db2[0] = (pModal->db2_01 & 0xf);
+ db2[1] = ((pModal->db2_01 >> 4) & 0xf);
+ db2[2] = (pModal->db2_234 & 0xf);
+ db2[3] = ((pModal->db2_234 >> 4) & 0xf);
+ db2[4] = ((pModal->db2_234 >> 8) & 0xf);
+
+ } else if (pModal->version == 1) {
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Model version is set to 1 \n");
+ ob[0] = (pModal->ob_01 & 0xf);
+ ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf;
+ db1[0] = (pModal->db1_01 & 0xf);
+ db1[1] = db1[2] = db1[3] =
+ db1[4] = ((pModal->db1_01 >> 4) & 0xf);
+ db2[0] = (pModal->db2_01 & 0xf);
+ db2[1] = db2[2] = db2[3] =
+ db2[4] = ((pModal->db2_01 >> 4) & 0xf);
+ } else {
+ int i;
+ for (i = 0; i < 5; i++) {
+ ob[i] = pModal->ob_01;
+ db1[i] = pModal->db1_01;
+ db2[i] = pModal->db1_01;
+ }
+ }
+
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
+ ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
+
+
+ if (AR_SREV_9285_11(ah))
+ REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+ pModal->switchSettling);
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+ pModal->adcDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
+ SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) |
+ SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+ pModal->txEndToRxOn);
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+ pModal->thresh62);
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+ pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ pModal->txFrameToPaOn);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH,
+ pModal->swSettleHt40);
+ }
+
+ return true;
+}
+
+static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *,
+ struct ath9k_channel *) = {
+ ath9k_hw_eeprom_set_def_board_values,
+ ath9k_hw_eeprom_set_4k_board_values
+};
+
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan);
+}
+
+static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u8 index, u16 *config)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ switch (index) {
+ case 0:
+ *config = pModal->antCtrlCommon & 0xFFFF;
+ return 0;
+ case 1:
+ if (pBase->version >= 0x0E0D) {
+ if (pModal->useAnt1) {
+ *config =
+ ((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
+ return 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u8 index, u16 *config)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &eep->modalHeader;
+
+ switch (index) {
+ case 0:
+ *config = pModal->antCtrlCommon & 0xFFFF;
+ return 0;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *,
+ struct ath9k_channel *,
+ u8, u16 *) = {
+ ath9k_hw_get_def_eeprom_antenna_cfg,
+ ath9k_hw_get_4k_eeprom_antenna_cfg
+};
+
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u8 index, u16 *config)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan,
+ index, config);
+}
+
+static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah,
+ enum ieee80211_band freq_band)
+{
+ return 1;
+}
+
+static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah,
+ enum ieee80211_band freq_band)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]);
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+ u8 num_ant_config;
+
+ num_ant_config = 1;
+
+ if (pBase->version >= 0x0E0D)
+ if (pModal->useAnt1)
+ num_ant_config += 1;
+
+ return num_ant_config;
+}
+
+static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *,
+ enum ieee80211_band) = {
+ ath9k_hw_get_def_num_ant_config,
+ ath9k_hw_get_4k_num_ant_config
+};
+
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+ enum ieee80211_band freq_band)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band);
+}
+
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz)
+{
+#define EEP_MAP4K_SPURCHAN \
+ (ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan)
+#define EEP_DEF_SPURCHAN \
+ (ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u16 spur_val = AR_NO_SPUR;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+
+ switch (ah->ah_config.spurmode) {
+ case SPUR_DISABLE:
+ break;
+ case SPUR_ENABLE_IOCTL:
+ spur_val = ah->ah_config.spurchans[i][is2GHz];
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+ spur_val = EEP_MAP4K_SPURCHAN;
+ else
+ spur_val = EEP_DEF_SPURCHAN;
+ break;
+
+ }
+
+ return spur_val;
+#undef EEP_DEF_SPURCHAN
+#undef EEP_MAP4K_SPURCHAN
+}
+
+static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah,
+ enum eeprom_param param)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k;
+ struct modal_eep_4k_header *pModal = &eep->modalHeader;
+ struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+
+ switch (param) {
+ case EEP_NFTHRESH_2:
+ return pModal[1].noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_OB_2:
+ return pModal->ob_01;
+ case EEP_DB_2:
+ return pModal->db1_01;
+ case EEP_MINOR_REV:
+ return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ default:
+ return 0;
+ }
+}
+
+static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah,
+ enum eeprom_param param)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def;
+ struct modal_eep_header *pModal = eep->modalHeader;
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ switch (param) {
+ case EEP_NFTHRESH_5:
+ return pModal[0].noiseFloorThreshCh[0];
+ case EEP_NFTHRESH_2:
+ return pModal[1].noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_OB_5:
+ return pModal[0].ob;
+ case EEP_DB_5:
+ return pModal[0].db;
+ case EEP_OB_2:
+ return pModal[1].ob;
+ case EEP_DB_2:
+ return pModal[1].db;
+ case EEP_MINOR_REV:
+ return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ case EEP_RXGAIN_TYPE:
+ return pBase->rxGainType;
+ case EEP_TXGAIN_TYPE:
+ return pBase->txGainType;
+
+ default:
+ return 0;
+ }
+}
+
+static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = {
+ ath9k_hw_get_eeprom_def,
+ ath9k_hw_get_eeprom_4k
+};
+
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
+ enum eeprom_param param)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ath9k_get_eeprom[ahp->ah_eep_map](ah, param);
+}
+
+int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+{
+ int status;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (ath9k_hw_use_flash(ah))
+ ath9k_hw_flash_map(ah);
+
+ if (AR_SREV_9285(ah))
+ ahp->ah_eep_map = EEP_MAP_4KBITS;
+ else
+ ahp->ah_eep_map = EEP_MAP_DEFAULT;
+
+ if (!ath9k_hw_fill_eeprom(ah))
+ return -EIO;
+
+ status = ath9k_hw_check_eeprom(ah);
+
+ return status;
+}
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 98bc25c9b3c..34474edefc9 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -23,277 +23,93 @@
#include "phy.h"
#include "initvals.h"
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah);
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains);
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah,
- u8 numChains);
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah,
- u8 numChains);
-
static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
-static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
-
-static const struct hal_percal_data iq_cal_multi_sample = {
- IQ_MISMATCH_CAL,
- MAX_CAL_SAMPLES,
- PER_MIN_LOG_COUNT,
- ath9k_hw_iqcal_collect,
- ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data iq_cal_single_sample = {
- IQ_MISMATCH_CAL,
- MIN_CAL_SAMPLES,
- PER_MAX_LOG_COUNT,
- ath9k_hw_iqcal_collect,
- ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data adc_gain_cal_multi_sample = {
- ADC_GAIN_CAL,
- MAX_CAL_SAMPLES,
- PER_MIN_LOG_COUNT,
- ath9k_hw_adc_gaincal_collect,
- ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_gain_cal_single_sample = {
- ADC_GAIN_CAL,
- MIN_CAL_SAMPLES,
- PER_MAX_LOG_COUNT,
- ath9k_hw_adc_gaincal_collect,
- ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_multi_sample = {
- ADC_DC_CAL,
- MAX_CAL_SAMPLES,
- PER_MIN_LOG_COUNT,
- ath9k_hw_adc_dccal_collect,
- ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_single_sample = {
- ADC_DC_CAL,
- MIN_CAL_SAMPLES,
- PER_MAX_LOG_COUNT,
- ath9k_hw_adc_dccal_collect,
- ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_init_dc_cal = {
- ADC_DC_INIT_CAL,
- MIN_CAL_SAMPLES,
- INIT_LOG_COUNT,
- ath9k_hw_adc_dccal_collect,
- ath9k_hw_adc_dccal_calibrate
-};
-
-static struct ath9k_rate_table ar5416_11a_table = {
- 8,
- {0},
- {
- {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
- {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
- {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
- },
-};
-
-static struct ath9k_rate_table ar5416_11b_table = {
- 4,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
- },
-};
-
-static struct ath9k_rate_table ar5416_11g_table = {
- 12,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
- {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
- {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
- {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
- },
-};
-
-static struct ath9k_rate_table ar5416_11ng_table = {
- 28,
- {0},
- {
- {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
- {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
- {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
- {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
-
- {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
- {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
- {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
- {true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
- {true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
- {true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
- {true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
- {true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
- {true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
- {true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
- {true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
- {true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
- {true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
- {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
- {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
- {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
- {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
- {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
- {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
- },
-};
-
-static struct ath9k_rate_table ar5416_11na_table = {
- 24,
- {0},
- {
- {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
- {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
- {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
- {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
- {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
- {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
- {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
- {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
- {true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
- {true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
- {true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
- {true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
- {true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
- {true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
- {true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
- {true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
- {true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
- {true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
- {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
- {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
- {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
- {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
- {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
- {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
- },
-};
-
-static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
- const struct ath9k_channel *chan)
-{
- if (IS_CHAN_CCK(chan))
- return ATH9K_MODE_11A;
- if (IS_CHAN_G(chan))
- return ATH9K_MODE_11G;
- return ATH9K_MODE_11A;
-}
-static bool ath9k_hw_wait(struct ath_hal *ah,
- u32 reg,
- u32 mask,
- u32 val)
-{
- int i;
+extern struct hal_percal_data iq_cal_multi_sample;
+extern struct hal_percal_data iq_cal_single_sample;
+extern struct hal_percal_data adc_gain_cal_multi_sample;
+extern struct hal_percal_data adc_gain_cal_single_sample;
+extern struct hal_percal_data adc_dc_cal_multi_sample;
+extern struct hal_percal_data adc_dc_cal_single_sample;
+extern struct hal_percal_data adc_init_dc_cal;
- for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
- if ((REG_READ(ah, reg) & mask) == val)
- return true;
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode);
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+ struct ar5416_eeprom_def *pEepData,
+ u32 reg, u32 value);
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
- udelay(AH_TIME_QUANTUM);
- }
- DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
- "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
- __func__, reg, REG_READ(ah, reg), mask, val);
- return false;
-}
+/********************/
+/* Helper Functions */
+/********************/
-static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off,
- u16 *data)
+static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
{
- (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
- if (!ath9k_hw_wait(ah,
- AR_EEPROM_STATUS_DATA,
- AR_EEPROM_STATUS_DATA_BUSY |
- AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
- return false;
- }
-
- *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
- AR_EEPROM_STATUS_DATA_VAL);
-
- return true;
+ if (ah->ah_curchan != NULL)
+ return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
+ else
+ return clks / CLOCK_RATE[ATH9K_MODE_11B];
}
-static int ath9k_hw_flash_map(struct ath_hal *ah)
+static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+ struct ath9k_channel *chan = ah->ah_curchan;
- if (!ahp->ah_cal_mem) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: cannot remap eeprom region \n", __func__);
- return -EIO;
- }
+ if (chan && IS_CHAN_HT40(chan))
+ return ath9k_hw_mac_usec(ah, clks) / 2;
+ else
+ return ath9k_hw_mac_usec(ah, clks);
+}
- return 0;
+static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
+{
+ if (ah->ah_curchan != NULL)
+ return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
+ ah->ah_curchan)];
+ else
+ return usecs * CLOCK_RATE[ATH9K_MODE_11B];
}
-static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off,
- u16 *data)
+static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
- *data = ioread16(ahp->ah_cal_mem + off);
- return true;
+ if (chan && IS_CHAN_HT40(chan))
+ return ath9k_hw_mac_clks(ah, usecs) * 2;
+ else
+ return ath9k_hw_mac_clks(ah, usecs);
}
-static void ath9k_hw_read_revisions(struct ath_hal *ah)
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+ const struct ath9k_channel *chan)
{
- u32 val;
-
- val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+ if (IS_CHAN_B(chan))
+ return ATH9K_MODE_11B;
+ if (IS_CHAN_G(chan))
+ return ATH9K_MODE_11G;
- if (val == 0xFF) {
- val = REG_READ(ah, AR_SREV);
+ return ATH9K_MODE_11A;
+}
- ah->ah_macVersion =
- (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
+{
+ int i;
- ah->ah_macRev = MS(val, AR_SREV_REVISION2);
- ah->ah_isPciExpress =
- (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+ for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
+ if ((REG_READ(ah, reg) & mask) == val)
+ return true;
- } else {
- if (!AR_SREV_9100(ah))
- ah->ah_macVersion = MS(val, AR_SREV_VERSION);
+ udelay(AH_TIME_QUANTUM);
+ }
- ah->ah_macRev = val & AR_SREV_REVISION;
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+ reg, REG_READ(ah, reg), mask, val);
- if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
- ah->ah_isPciExpress = true;
- }
+ return false;
}
u32 ath9k_hw_reverse_bits(u32 val, u32 n)
@@ -308,596 +124,215 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n)
return retval;
}
-static void ath9k_hw_set_defaults(struct ath_hal *ah)
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+ u16 flags, u16 *low,
+ u16 *high)
{
- int i;
-
- ah->ah_config.dma_beacon_response_time = 2;
- ah->ah_config.sw_beacon_response_time = 10;
- ah->ah_config.additional_swba_backoff = 0;
- ah->ah_config.ack_6mb = 0x0;
- ah->ah_config.cwm_ignore_extcca = 0;
- ah->ah_config.pcie_powersave_enable = 0;
- ah->ah_config.pcie_l1skp_enable = 0;
- ah->ah_config.pcie_clock_req = 0;
- ah->ah_config.pcie_power_reset = 0x100;
- ah->ah_config.pcie_restore = 0;
- ah->ah_config.pcie_waen = 0;
- ah->ah_config.analog_shiftreg = 1;
- ah->ah_config.ht_enable = 1;
- ah->ah_config.ofdm_trig_low = 200;
- ah->ah_config.ofdm_trig_high = 500;
- ah->ah_config.cck_trig_high = 200;
- ah->ah_config.cck_trig_low = 100;
- ah->ah_config.enable_ani = 1;
- ah->ah_config.noise_immunity_level = 4;
- ah->ah_config.ofdm_weaksignal_det = 1;
- ah->ah_config.cck_weaksignal_thr = 0;
- ah->ah_config.spur_immunity_level = 2;
- ah->ah_config.firstep_level = 0;
- ah->ah_config.rssi_thr_high = 40;
- ah->ah_config.rssi_thr_low = 7;
- ah->ah_config.diversity_control = 0;
- ah->ah_config.antenna_switch_swap = 0;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
- ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
- ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
+ if (flags & CHANNEL_5GHZ) {
+ *low = pCap->low_5ghz_chan;
+ *high = pCap->high_5ghz_chan;
+ return true;
}
-
- ah->ah_config.intr_mitigation = 0;
-}
-
-static void ath9k_hw_override_ini(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- if (!AR_SREV_5416_V20_OR_LATER(ah)
- || AR_SREV_9280_10_OR_LATER(ah))
- return;
-
- REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
-}
-
-static void ath9k_hw_init_bb(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- u32 synthDelay;
-
- synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_CCK(chan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
-
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
-
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
-}
-
-static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
- enum ath9k_opmode opmode)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- ahp->ah_maskReg = AR_IMR_TXERR |
- AR_IMR_TXURN |
- AR_IMR_RXERR |
- AR_IMR_RXORN |
- AR_IMR_BCNMISC;
-
- if (ahp->ah_intrMitigation)
- ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
- else
- ahp->ah_maskReg |= AR_IMR_RXOK;
-
- ahp->ah_maskReg |= AR_IMR_TXOK;
-
- if (opmode == ATH9K_M_HOSTAP)
- ahp->ah_maskReg |= AR_IMR_MIB;
-
- REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
- REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
-
- if (!AR_SREV_9100(ah)) {
- REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
- REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+ if ((flags & CHANNEL_2GHZ)) {
+ *low = pCap->low_2ghz_chan;
+ *high = pCap->high_2ghz_chan;
+ return true;
}
+ return false;
}
-static void ath9k_hw_init_qos(struct ath_hal *ah)
-{
- REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
- REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
-
- REG_WRITE(ah, AR_QOS_NO_ACK,
- SM(2, AR_QOS_NO_ACK_TWO_BIT) |
- SM(5, AR_QOS_NO_ACK_BIT_OFF) |
- SM(0, AR_QOS_NO_ACK_BYTE_OFF));
-
- REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
- REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
- REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
- REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
- REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
-}
-
-static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
- u32 reg,
- u32 mask,
- u32 shift,
- u32 val)
-{
- u32 regVal;
-
- regVal = REG_READ(ah, reg) & ~mask;
- regVal |= (val << shift) & mask;
-
- REG_WRITE(ah, reg, regVal);
-
- if (ah->ah_config.analog_shiftreg)
- udelay(100);
-
- return;
-}
-
-static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp,
- enum ieee80211_band freq_band)
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+ struct ath_rate_table *rates,
+ u32 frameLen, u16 rateix,
+ bool shortPreamble)
{
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
- struct base_eep_header *pBase = &eep->baseEepHeader;
- u8 num_ant_config;
-
- num_ant_config = 1;
-
- if (pBase->version >= 0x0E0D)
- if (pModal->useAnt1)
- num_ant_config += 1;
-
- return num_ant_config;
-}
+ u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
+ u32 kbps;
-static int
-ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp,
- struct ath9k_channel *chan,
- u8 index,
- u16 *config)
-{
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- struct modal_eep_header *pModal =
- &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
- struct base_eep_header *pBase = &eep->baseEepHeader;
+ kbps = rates->info[rateix].ratekbps;
- switch (index) {
- case 0:
- *config = pModal->antCtrlCommon & 0xFFFF;
+ if (kbps == 0)
return 0;
- case 1:
- if (pBase->version >= 0x0E0D) {
- if (pModal->useAnt1) {
- *config =
- ((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
- return 0;
- }
+
+ switch (rates->info[rateix].phy) {
+ case WLAN_RC_PHY_CCK:
+ phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
+ if (shortPreamble && rates->info[rateix].short_preamble)
+ phyTime >>= 1;
+ numBits = frameLen << 3;
+ txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
+ break;
+ case WLAN_RC_PHY_OFDM:
+ if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
+ bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME_QUARTER
+ + OFDM_PREAMBLE_TIME_QUARTER
+ + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
+ } else if (ah->ah_curchan &&
+ IS_CHAN_HALF_RATE(ah->ah_curchan)) {
+ bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME_HALF +
+ OFDM_PREAMBLE_TIME_HALF
+ + (numSymbols * OFDM_SYMBOL_TIME_HALF);
+ } else {
+ bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+ + (numSymbols * OFDM_SYMBOL_TIME);
}
break;
default:
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "Unknown phy %u (rate ix %u)\n",
+ rates->info[rateix].phy, rateix);
+ txTime = 0;
break;
}
- return -EINVAL;
-}
-
-static inline bool ath9k_hw_nvram_read(struct ath_hal *ah,
- u32 off,
- u16 *data)
-{
- if (ath9k_hw_use_flash(ah))
- return ath9k_hw_flash_read(ah, off, data);
- else
- return ath9k_hw_eeprom_read(ah, off, data);
+ return txTime;
}
-static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- u16 *eep_data;
- int addr, ar5416_eep_start_loc = 0;
-
- if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: Reading from EEPROM, not flash\n", __func__);
- ar5416_eep_start_loc = 256;
- }
- if (AR_SREV_9100(ah))
- ar5416_eep_start_loc = 256;
-
- eep_data = (u16 *) eep;
- for (addr = 0;
- addr < sizeof(struct ar5416_eeprom) / sizeof(u16);
- addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
- eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: Unable to read eeprom region \n",
- __func__);
- return false;
+ if (flags & CHANNEL_2GHZ) {
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ else
+ return 15 + ((freq - 2512) / 20);
+ } else if (flags & CHANNEL_5GHZ) {
+ if (ath9k_regd_is_public_safety_sku(ah) &&
+ IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+ return ((freq * 10) +
+ (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
+ } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
+ return (freq - 4000) / 5;
+ } else {
+ return (freq - 5000) / 5;
+ }
+ } else {
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ if (freq < 5000) {
+ if (ath9k_regd_is_public_safety_sku(ah)
+ && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+ return ((freq * 10) +
+ (((freq % 5) ==
+ 2) ? 5 : 0) - 49400) / 5;
+ } else if (freq > 4900) {
+ return (freq - 4000) / 5;
+ } else {
+ return 15 + ((freq - 2512) / 20);
+ }
}
- eep_data++;
+ return (freq - 5000) / 5;
}
- return true;
}
-/* XXX: Clean me up, make me more legible */
-static bool
-ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
- struct ath9k_channel *chan)
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct chan_centers *centers)
{
- struct modal_eep_header *pModal;
- int i, regChainOffset;
+ int8_t extoff;
struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- u8 txRxAttenLocal;
- u16 ant_config;
- pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+ if (!IS_CHAN_HT40(chan)) {
+ centers->ctl_center = centers->ext_center =
+ centers->synth_center = chan->channel;
+ return;
+ }
- txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+ if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+ (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+ centers->synth_center =
+ chan->channel + HT40_CHANNEL_CENTER_SHIFT;
+ extoff = 1;
+ } else {
+ centers->synth_center =
+ chan->channel - HT40_CHANNEL_CENTER_SHIFT;
+ extoff = -1;
+ }
- ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config);
- REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+ centers->ctl_center =
+ centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+ centers->ext_center =
+ centers->synth_center + (extoff *
+ ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
+ HT40_CHANNEL_CENTER_SHIFT : 15));
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (AR_SREV_9280(ah)) {
- if (i >= 2)
- break;
- }
+}
- if (AR_SREV_5416_V20_OR_LATER(ah) &&
- (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
- && (i != 0))
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- else
- regChainOffset = i * 0x1000;
-
- REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
- pModal->antCtrlChain[i]);
-
- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
- (REG_READ(ah,
- AR_PHY_TIMING_CTRL4(0) +
- regChainOffset) &
- ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
- SM(pModal->iqCalICh[i],
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
- SM(pModal->iqCalQCh[i],
- AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
- if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
- if ((eep->baseEepHeader.version &
- AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_3) {
- txRxAttenLocal = pModal->txRxAttenCh[i];
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
- pModal->
- bswMargin[i]);
- REG_RMW_FIELD(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN1_DB,
- pModal->
- bswAtten[i]);
- REG_RMW_FIELD(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
- pModal->
- xatten2Margin[i]);
- REG_RMW_FIELD(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- AR_PHY_GAIN_2GHZ_XATTEN2_DB,
- pModal->
- xatten2Db[i]);
- } else {
- REG_WRITE(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- (REG_READ(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
- | SM(pModal->
- bswMargin[i],
- AR_PHY_GAIN_2GHZ_BSW_MARGIN));
- REG_WRITE(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- (REG_READ(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
- | SM(pModal->bswAtten[i],
- AR_PHY_GAIN_2GHZ_BSW_ATTEN));
- }
- }
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah,
- AR_PHY_RXGAIN +
- regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_ATTEN,
- txRxAttenLocal);
- REG_RMW_FIELD(ah,
- AR_PHY_RXGAIN +
- regChainOffset,
- AR9280_PHY_RXGAIN_TXRX_MARGIN,
- pModal->rxTxMarginCh[i]);
- } else {
- REG_WRITE(ah,
- AR_PHY_RXGAIN + regChainOffset,
- (REG_READ(ah,
- AR_PHY_RXGAIN +
- regChainOffset) &
- ~AR_PHY_RXGAIN_TXRX_ATTEN) |
- SM(txRxAttenLocal,
- AR_PHY_RXGAIN_TXRX_ATTEN));
- REG_WRITE(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset,
- (REG_READ(ah,
- AR_PHY_GAIN_2GHZ +
- regChainOffset) &
- ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
- SM(pModal->rxTxMarginCh[i],
- AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
- }
- }
- }
+/******************/
+/* Chip Revisions */
+/******************/
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (IS_CHAN_2GHZ(chan)) {
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
- AR_AN_RF2G1_CH0_OB,
- AR_AN_RF2G1_CH0_OB_S,
- pModal->ob);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
- AR_AN_RF2G1_CH0_DB,
- AR_AN_RF2G1_CH0_DB_S,
- pModal->db);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
- AR_AN_RF2G1_CH1_OB,
- AR_AN_RF2G1_CH1_OB_S,
- pModal->ob_ch1);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
- AR_AN_RF2G1_CH1_DB,
- AR_AN_RF2G1_CH1_DB_S,
- pModal->db_ch1);
- } else {
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
- AR_AN_RF5G1_CH0_OB5,
- AR_AN_RF5G1_CH0_OB5_S,
- pModal->ob);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
- AR_AN_RF5G1_CH0_DB5,
- AR_AN_RF5G1_CH0_DB5_S,
- pModal->db);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
- AR_AN_RF5G1_CH1_OB5,
- AR_AN_RF5G1_CH1_OB5_S,
- pModal->ob_ch1);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
- AR_AN_RF5G1_CH1_DB5,
- AR_AN_RF5G1_CH1_DB5_S,
- pModal->db_ch1);
- }
- ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
- AR_AN_TOP2_XPABIAS_LVL,
- AR_AN_TOP2_XPABIAS_LVL_S,
- pModal->xpaBiasLvl);
- ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
- AR_AN_TOP2_LOCALBIAS,
- AR_AN_TOP2_LOCALBIAS_S,
- pModal->local_bias);
- DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n",
- pModal->force_xpaon);
- REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
- pModal->force_xpaon);
- }
+static void ath9k_hw_read_revisions(struct ath_hal *ah)
+{
+ u32 val;
- REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
- pModal->switchSettling);
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
- pModal->adcDesiredSize);
+ val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
- if (!AR_SREV_9280_10_OR_LATER(ah))
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
- AR_PHY_DESIRED_SZ_PGA,
- pModal->pgaDesiredSize);
-
- REG_WRITE(ah, AR_PHY_RF_CTL4,
- SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
- | SM(pModal->txEndToXpaOff,
- AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
- | SM(pModal->txFrameToXpaOn,
- AR_PHY_RF_CTL4_FRAME_XPAA_ON)
- | SM(pModal->txFrameToXpaOn,
- AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
- pModal->txEndToRxOn);
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
- pModal->thresh62);
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
- AR_PHY_EXT_CCA0_THRESH62,
- pModal->thresh62);
+ if (val == 0xFF) {
+ val = REG_READ(ah, AR_SREV);
+ ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+ ah->ah_macRev = MS(val, AR_SREV_REVISION2);
+ ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
} else {
- REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
- pModal->thresh62);
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
- AR_PHY_EXT_CCA_THRESH62,
- pModal->thresh62);
- }
+ if (!AR_SREV_9100(ah))
+ ah->ah_macVersion = MS(val, AR_SREV_VERSION);
- if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
- AR_PHY_TX_END_DATA_START,
- pModal->txFrameToDataStart);
- REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
- pModal->txFrameToPaOn);
- }
+ ah->ah_macRev = val & AR_SREV_REVISION;
- if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_3) {
- if (IS_CHAN_HT40(chan))
- REG_RMW_FIELD(ah, AR_PHY_SETTLING,
- AR_PHY_SETTLING_SWITCH,
- pModal->swSettleHt40);
+ if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
+ ah->ah_isPciExpress = true;
}
-
- return true;
}
-static int ath9k_hw_check_eeprom(struct ath_hal *ah)
+static int ath9k_hw_get_radiorev(struct ath_hal *ah)
{
- u32 sum = 0, el;
- u16 *eepdata;
+ u32 val;
int i;
- struct ath_hal_5416 *ahp = AH5416(ah);
- bool need_swap = false;
- struct ar5416_eeprom *eep =
- (struct ar5416_eeprom *) &ahp->ah_eeprom;
-
- if (!ath9k_hw_use_flash(ah)) {
- u16 magic, magic2;
- int addr;
-
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
- &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: Reading Magic # failed\n", __func__);
- return false;
- }
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
- __func__, magic);
-
- if (magic != AR5416_EEPROM_MAGIC) {
- magic2 = swab16(magic);
-
- if (magic2 == AR5416_EEPROM_MAGIC) {
- need_swap = true;
- eepdata = (u16 *) (&ahp->ah_eeprom);
-
- for (addr = 0;
- addr <
- sizeof(struct ar5416_eeprom) /
- sizeof(u16); addr++) {
- u16 temp;
-
- temp = swab16(*eepdata);
- *eepdata = temp;
- eepdata++;
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "0x%04X ", *eepdata);
- if (((addr + 1) % 6) == 0)
- DPRINTF(ah->ah_sc,
- ATH_DBG_EEPROM,
- "\n");
- }
- } else {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid EEPROM Magic. "
- "endianness missmatch.\n");
- return -EINVAL;
- }
- }
- }
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
-
- if (need_swap)
- el = swab16(ahp->ah_eeprom.baseEepHeader.length);
- else
- el = ahp->ah_eeprom.baseEepHeader.length;
-
- if (el > sizeof(struct ar5416_eeprom))
- el = sizeof(struct ar5416_eeprom) / sizeof(u16);
- else
- el = el / sizeof(u16);
-
- eepdata = (u16 *) (&ahp->ah_eeprom);
-
- for (i = 0; i < el; i++)
- sum ^= *eepdata++;
-
- if (need_swap) {
- u32 integer, j;
- u16 word;
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing \n");
-
- word = swab16(eep->baseEepHeader.length);
- eep->baseEepHeader.length = word;
-
- word = swab16(eep->baseEepHeader.checksum);
- eep->baseEepHeader.checksum = word;
-
- word = swab16(eep->baseEepHeader.version);
- eep->baseEepHeader.version = word;
-
- word = swab16(eep->baseEepHeader.regDmn[0]);
- eep->baseEepHeader.regDmn[0] = word;
-
- word = swab16(eep->baseEepHeader.regDmn[1]);
- eep->baseEepHeader.regDmn[1] = word;
-
- word = swab16(eep->baseEepHeader.rfSilent);
- eep->baseEepHeader.rfSilent = word;
-
- word = swab16(eep->baseEepHeader.blueToothOptions);
- eep->baseEepHeader.blueToothOptions = word;
+ REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
- word = swab16(eep->baseEepHeader.deviceCap);
- eep->baseEepHeader.deviceCap = word;
+ for (i = 0; i < 8; i++)
+ REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+ val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+ val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
- for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
- struct modal_eep_header *pModal =
- &eep->modalHeader[j];
- integer = swab32(pModal->antCtrlCommon);
- pModal->antCtrlCommon = integer;
+ return ath9k_hw_reverse_bits(val, 8);
+}
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- integer = swab32(pModal->antCtrlChain[i]);
- pModal->antCtrlChain[i] = integer;
- }
+/************************************/
+/* HW Attach, Detach, Init Routines */
+/************************************/
- for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
- word = swab16(pModal->spurChans[i].spurChan);
- pModal->spurChans[i].spurChan = word;
- }
- }
- }
+static void ath9k_hw_disablepcie(struct ath_hal *ah)
+{
+ if (!AR_SREV_9100(ah))
+ return;
- if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
- ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ar5416_get_eep_ver(ahp));
- return -EINVAL;
- }
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
- return 0;
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
}
static bool ath9k_hw_chip_test(struct ath_hal *ah)
@@ -905,9 +340,9 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah)
u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
u32 regHold[2];
u32 patternData[4] = { 0x55555555,
- 0xaaaaaaaa,
- 0x66666666,
- 0x99999999 };
+ 0xaaaaaaaa,
+ 0x66666666,
+ 0x99999999 };
int i, j;
for (i = 0; i < 2; i++) {
@@ -921,9 +356,9 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah)
rdData = REG_READ(ah, addr);
if (rdData != wrData) {
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "%s: address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- __func__, addr, wrData, rdData);
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -933,9 +368,9 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah)
rdData = REG_READ(ah, addr);
if (wrData != rdData) {
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "%s: address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- __func__, addr, wrData, rdData);
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -945,213 +380,65 @@ static bool ath9k_hw_chip_test(struct ath_hal *ah)
return true;
}
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
-{
- u32 bits = REG_READ(ah, AR_RX_FILTER);
- u32 phybits = REG_READ(ah, AR_PHY_ERR);
-
- if (phybits & AR_PHY_ERR_RADAR)
- bits |= ATH9K_RX_FILTER_PHYRADAR;
- if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
- bits |= ATH9K_RX_FILTER_PHYERR;
- return bits;
-}
-
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
-{
- u32 phybits;
-
- REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
- phybits = 0;
- if (bits & ATH9K_RX_FILTER_PHYRADAR)
- phybits |= AR_PHY_ERR_RADAR;
- if (bits & ATH9K_RX_FILTER_PHYERR)
- phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
- REG_WRITE(ah, AR_PHY_ERR, phybits);
-
- if (phybits)
- REG_WRITE(ah, AR_RXCFG,
- REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
- else
- REG_WRITE(ah, AR_RXCFG,
- REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
-}
-
-bool ath9k_hw_setcapability(struct ath_hal *ah,
- enum ath9k_capability_type type,
- u32 capability,
- u32 setting,
- int *status)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 v;
-
- switch (type) {
- case ATH9K_CAP_TKIP_MIC:
- if (setting)
- ahp->ah_staId1Defaults |=
- AR_STA_ID1_CRPT_MIC_ENABLE;
- else
- ahp->ah_staId1Defaults &=
- ~AR_STA_ID1_CRPT_MIC_ENABLE;
- return true;
- case ATH9K_CAP_DIVERSITY:
- v = REG_READ(ah, AR_PHY_CCK_DETECT);
- if (setting)
- v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- else
- v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
- REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
- return true;
- case ATH9K_CAP_MCAST_KEYSRCH:
- if (setting)
- ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
- else
- ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
- return true;
- case ATH9K_CAP_TSF_ADJUST:
- if (setting)
- ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
- else
- ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
- return true;
- default:
- return false;
- }
-}
-
-void ath9k_hw_dmaRegDump(struct ath_hal *ah)
+static const char *ath9k_hw_devname(u16 devid)
{
- u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
- int qcuOffset = 0, dcuOffset = 0;
- u32 *qcuBase = &val[0], *dcuBase = &val[4];
- int i;
-
- REG_WRITE(ah, AR_MACMISC,
- ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
- (AR_MACMISC_MISC_OBS_BUS_1 <<
- AR_MACMISC_MISC_OBS_BUS_MSB_S)));
-
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
- for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
- if (i % 4 == 0)
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
-
- val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
-
- for (i = 0; i < ATH9K_NUM_QUEUES;
- i++, qcuOffset += 4, dcuOffset += 5) {
- if (i == 8) {
- qcuOffset = 0;
- qcuBase++;
- }
-
- if (i == 6) {
- dcuOffset = 0;
- dcuBase++;
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "%2d %2x %1x %2x %2x\n",
- i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
- (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset +
- 3),
- val[2] & (0x7 << (i * 3)) >> (i * 3),
- (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ return "Atheros 5416";
+ case AR5416_DEVID_PCIE:
+ return "Atheros 5418";
+ case AR9160_DEVID_PCI:
+ return "Atheros 9160";
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ return "Atheros 9280";
+ case AR9285_DEVID_PCIE:
+ return "Atheros 9285";
}
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "qcu_stitch state: %2x qcu_fetch state: %2x\n",
- (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "qcu_complete state: %2x dcu_complete state: %2x\n",
- (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "dcu_arb state: %2x dcu_fp state: %2x\n",
- (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
- (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
- (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
- (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
-
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
- REG_READ(ah, AR_OBS_BUS_1));
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "AR_CR 0x%x \n", REG_READ(ah, AR_CR));
+ return NULL;
}
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
- u32 *rxc_pcnt,
- u32 *rxf_pcnt,
- u32 *txf_pcnt)
+static void ath9k_hw_set_defaults(struct ath_hal *ah)
{
- static u32 cycles, rx_clear, rx_frame, tx_frame;
- u32 good = 1;
+ int i;
- u32 rc = REG_READ(ah, AR_RCCNT);
- u32 rf = REG_READ(ah, AR_RFCNT);
- u32 tf = REG_READ(ah, AR_TFCNT);
- u32 cc = REG_READ(ah, AR_CCCNT);
+ ah->ah_config.dma_beacon_response_time = 2;
+ ah->ah_config.sw_beacon_response_time = 10;
+ ah->ah_config.additional_swba_backoff = 0;
+ ah->ah_config.ack_6mb = 0x0;
+ ah->ah_config.cwm_ignore_extcca = 0;
+ ah->ah_config.pcie_powersave_enable = 0;
+ ah->ah_config.pcie_l1skp_enable = 0;
+ ah->ah_config.pcie_clock_req = 0;
+ ah->ah_config.pcie_power_reset = 0x100;
+ ah->ah_config.pcie_restore = 0;
+ ah->ah_config.pcie_waen = 0;
+ ah->ah_config.analog_shiftreg = 1;
+ ah->ah_config.ht_enable = 1;
+ ah->ah_config.ofdm_trig_low = 200;
+ ah->ah_config.ofdm_trig_high = 500;
+ ah->ah_config.cck_trig_high = 200;
+ ah->ah_config.cck_trig_low = 100;
+ ah->ah_config.enable_ani = 1;
+ ah->ah_config.noise_immunity_level = 4;
+ ah->ah_config.ofdm_weaksignal_det = 1;
+ ah->ah_config.cck_weaksignal_thr = 0;
+ ah->ah_config.spur_immunity_level = 2;
+ ah->ah_config.firstep_level = 0;
+ ah->ah_config.rssi_thr_high = 40;
+ ah->ah_config.rssi_thr_low = 7;
+ ah->ah_config.diversity_control = 0;
+ ah->ah_config.antenna_switch_swap = 0;
- if (cycles == 0 || cycles > cc) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: cycle counter wrap. ExtBusy = 0\n",
- __func__);
- good = 0;
- } else {
- u32 cc_d = cc - cycles;
- u32 rc_d = rc - rx_clear;
- u32 rf_d = rf - rx_frame;
- u32 tf_d = tf - tx_frame;
-
- if (cc_d != 0) {
- *rxc_pcnt = rc_d * 100 / cc_d;
- *rxf_pcnt = rf_d * 100 / cc_d;
- *txf_pcnt = tf_d * 100 / cc_d;
- } else {
- good = 0;
- }
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
+ ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
}
- cycles = cc;
- rx_frame = rf;
- rx_clear = rc;
- tx_frame = tf;
-
- return good;
+ ah->ah_config.intr_mitigation = 1;
}
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
-{
- u32 macmode;
-
- if (mode == ATH9K_HT_MACMODE_2040 &&
- !ah->ah_config.cwm_ignore_extcca)
- macmode = AR_2040_JOINED_RX_CLEAR;
- else
- macmode = 0;
-
- REG_WRITE(ah, AR_2040_MODE, macmode);
-}
-
-static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
-{
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
-}
-
-
static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
struct ath_softc *sc,
void __iomem *mem,
@@ -1165,20 +452,16 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
if (ahp == NULL) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: cannot allocate memory for state block\n",
- __func__);
+ "Cannot allocate memory for state block\n");
*status = -ENOMEM;
return NULL;
}
ah = &ahp->ah;
-
ah->ah_sc = sc;
ah->ah_sh = mem;
-
ah->ah_magic = AR5416_MAGIC;
ah->ah_countryCode = CTRY_DEFAULT;
-
ah->ah_devid = devid;
ah->ah_subvendorid = 0;
@@ -1190,12 +473,10 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
ah->ah_powerLimit = MAX_RATE_POWER;
ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
-
ahp->ah_atimWindow = 0;
ahp->ah_diversityControl = ah->ah_config.diversity_control;
ahp->ah_antennaSwitchSwap =
ah->ah_config.antenna_switch_swap;
-
ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
ahp->ah_beaconInterval = 100;
ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
@@ -1210,163 +491,6 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
return ahp;
}
-static int ath9k_hw_eeprom_attach(struct ath_hal *ah)
-{
- int status;
-
- if (ath9k_hw_use_flash(ah))
- ath9k_hw_flash_map(ah);
-
- if (!ath9k_hw_fill_eeprom(ah))
- return -EIO;
-
- status = ath9k_hw_check_eeprom(ah);
-
- return status;
-}
-
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
- enum eeprom_param param)
-{
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- struct modal_eep_header *pModal = eep->modalHeader;
- struct base_eep_header *pBase = &eep->baseEepHeader;
-
- switch (param) {
- case EEP_NFTHRESH_5:
- return -pModal[0].noiseFloorThreshCh[0];
- case EEP_NFTHRESH_2:
- return -pModal[1].noiseFloorThreshCh[0];
- case AR_EEPROM_MAC(0):
- return pBase->macAddr[0] << 8 | pBase->macAddr[1];
- case AR_EEPROM_MAC(1):
- return pBase->macAddr[2] << 8 | pBase->macAddr[3];
- case AR_EEPROM_MAC(2):
- return pBase->macAddr[4] << 8 | pBase->macAddr[5];
- case EEP_REG_0:
- return pBase->regDmn[0];
- case EEP_REG_1:
- return pBase->regDmn[1];
- case EEP_OP_CAP:
- return pBase->deviceCap;
- case EEP_OP_MODE:
- return pBase->opCapFlags;
- case EEP_RF_SILENT:
- return pBase->rfSilent;
- case EEP_OB_5:
- return pModal[0].ob;
- case EEP_DB_5:
- return pModal[0].db;
- case EEP_OB_2:
- return pModal[1].ob;
- case EEP_DB_2:
- return pModal[1].db;
- case EEP_MINOR_REV:
- return pBase->version & AR5416_EEP_VER_MINOR_MASK;
- case EEP_TX_MASK:
- return pBase->txMask;
- case EEP_RX_MASK:
- return pBase->rxMask;
- default:
- return 0;
- }
-}
-
-static int ath9k_hw_get_radiorev(struct ath_hal *ah)
-{
- u32 val;
- int i;
-
- REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
- for (i = 0; i < 8; i++)
- REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
- val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
- val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
- return ath9k_hw_reverse_bits(val, 8);
-}
-
-static int ath9k_hw_init_macaddr(struct ath_hal *ah)
-{
- u32 sum;
- int i;
- u16 eeval;
- struct ath_hal_5416 *ahp = AH5416(ah);
- DECLARE_MAC_BUF(mac);
-
- sum = 0;
- for (i = 0; i < 3; i++) {
- eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i));
- sum += eeval;
- ahp->ah_macaddr[2 * i] = eeval >> 8;
- ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
- }
- if (sum == 0 || sum == 0xffff * 3) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: mac address read failed: %s\n", __func__,
- print_mac(mac, ahp->ah_macaddr));
- return -EADDRNOTAVAIL;
- }
-
- return 0;
-}
-
-static inline int16_t ath9k_hw_interpolate(u16 target,
- u16 srcLeft,
- u16 srcRight,
- int16_t targetLeft,
- int16_t targetRight)
-{
- int16_t rv;
-
- if (srcRight == srcLeft) {
- rv = targetLeft;
- } else {
- rv = (int16_t) (((target - srcLeft) * targetRight +
- (srcRight - target) * targetLeft) /
- (srcRight - srcLeft));
- }
- return rv;
-}
-
-static inline u16 ath9k_hw_fbin2freq(u8 fbin,
- bool is2GHz)
-{
-
- if (fbin == AR5416_BCHAN_UNUSED)
- return fbin;
-
- return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
-}
-
-static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah,
- u16 i,
- bool is2GHz)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416_eeprom *eep =
- (struct ar5416_eeprom *) &ahp->ah_eeprom;
- u16 spur_val = AR_NO_SPUR;
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
-
- switch (ah->ah_config.spurmode) {
- case SPUR_DISABLE:
- break;
- case SPUR_ENABLE_IOCTL:
- spur_val = ah->ah_config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
- break;
- case SPUR_ENABLE_EEPROM:
- spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
- break;
-
- }
- return spur_val;
-}
-
static int ath9k_hw_rfattach(struct ath_hal *ah)
{
bool rfStatus = false;
@@ -1375,8 +499,7 @@ static int ath9k_hw_rfattach(struct ath_hal *ah)
rfStatus = ath9k_hw_init_rf(ah, &ecode);
if (!rfStatus) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: RF setup failed, status %u\n", __func__,
- ecode);
+ "RF setup failed, status %u\n", ecode);
return ecode;
}
@@ -1401,9 +524,9 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah)
break;
default:
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: 5G Radio Chip Rev 0x%02X is not "
+ "5G Radio Chip Rev 0x%02X is not "
"supported by this driver\n",
- __func__, ah->ah_analog5GhzRev);
+ ah->ah_analog5GhzRev);
return -EOPNOTSUPP;
}
@@ -1412,1473 +535,76 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah)
return 0;
}
-static void ath9k_hw_init_pll(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- u32 pll;
-
- if (AR_SREV_9100(ah)) {
- if (chan && IS_CHAN_5GHZ(chan))
- pll = 0x1450;
- else
- pll = 0x1458;
- } else {
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
- if (chan && IS_CHAN_HALF_RATE(chan))
- pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
- else if (chan && IS_CHAN_QUARTER_RATE(chan))
- pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
- if (chan && IS_CHAN_5GHZ(chan)) {
- pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
-
-
- if (AR_SREV_9280_20(ah)) {
- if (((chan->channel % 20) == 0)
- || ((chan->channel % 10) == 0))
- pll = 0x2850;
- else
- pll = 0x142c;
- }
- } else {
- pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
- }
-
- } else if (AR_SREV_9160_10_OR_LATER(ah)) {
-
- pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
- if (chan && IS_CHAN_HALF_RATE(chan))
- pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
- else if (chan && IS_CHAN_QUARTER_RATE(chan))
- pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
- if (chan && IS_CHAN_5GHZ(chan))
- pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
- else
- pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
- } else {
- pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
-
- if (chan && IS_CHAN_HALF_RATE(chan))
- pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
- else if (chan && IS_CHAN_QUARTER_RATE(chan))
- pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
-
- if (chan && IS_CHAN_5GHZ(chan))
- pll |= SM(0xa, AR_RTC_PLL_DIV);
- else
- pll |= SM(0xb, AR_RTC_PLL_DIV);
- }
- }
- REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
-
- udelay(RTC_PLL_SETTLE_DELAY);
-
- REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
-}
-
-static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
-{
- u32 phymode;
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
- | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
-
- if (IS_CHAN_HT40(chan)) {
- phymode |= AR_PHY_FC_DYN2040_EN;
-
- if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
- (chan->chanmode == CHANNEL_G_HT40PLUS))
- phymode |= AR_PHY_FC_DYN2040_PRI_CH;
-
- if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
- phymode |= AR_PHY_FC_DYN2040_EXT_CH;
- }
- REG_WRITE(ah, AR_PHY_TURBO, phymode);
-
- ath9k_hw_set11nmac2040(ah, macmode);
-
- REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
- REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
-}
-
-static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
-{
- u32 val;
-
- val = REG_READ(ah, AR_STA_ID1);
- val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
- switch (opmode) {
- case ATH9K_M_HOSTAP:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
- | AR_STA_ID1_KSRCH_MODE);
- REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
- break;
- case ATH9K_M_IBSS:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
- | AR_STA_ID1_KSRCH_MODE);
- REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
- break;
- case ATH9K_M_STA:
- case ATH9K_M_MONITOR:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
- break;
- }
-}
-
-static void
-ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
-{
- u32 rfMode = 0;
-
- if (chan == NULL)
- return;
-
- rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
- ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
-
- if (!AR_SREV_9280_10_OR_LATER(ah))
- rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ :
- AR_PHY_MODE_RF2GHZ;
-
- if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
- rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
-
- REG_WRITE(ah, AR_PHY_MODE, rfMode);
-}
-
-static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
-{
- u32 rst_flags;
- u32 tmpReg;
-
- REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
- AR_RTC_FORCE_WAKE_ON_INT);
-
- if (AR_SREV_9100(ah)) {
- rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
- AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
- } else {
- tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
- if (tmpReg &
- (AR_INTR_SYNC_LOCAL_TIMEOUT |
- AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
- REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
- } else {
- REG_WRITE(ah, AR_RC, AR_RC_AHB);
- }
-
- rst_flags = AR_RTC_RC_MAC_WARM;
- if (type == ATH9K_RESET_COLD)
- rst_flags |= AR_RTC_RC_MAC_COLD;
- }
-
- REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
- udelay(50);
-
- REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
- if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: RTC stuck in MAC reset\n",
- __func__);
- return false;
- }
-
- if (!AR_SREV_9100(ah))
- REG_WRITE(ah, AR_RC, 0);
-
- ath9k_hw_init_pll(ah, NULL);
-
- if (AR_SREV_9100(ah))
- udelay(50);
-
- return true;
-}
-
-static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
-{
- REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
- AR_RTC_FORCE_WAKE_ON_INT);
-
- REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
- REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
-
- if (!ath9k_hw_wait(ah,
- AR_RTC_STATUS,
- AR_RTC_STATUS_M,
- AR_RTC_STATUS_ON)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n",
- __func__);
- return false;
- }
-
- ath9k_hw_read_revisions(ah);
-
- return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
-}
-
-static bool ath9k_hw_set_reset_reg(struct ath_hal *ah,
- u32 type)
-{
- REG_WRITE(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
-
- switch (type) {
- case ATH9K_RESET_POWER_ON:
- return ath9k_hw_set_reset_power_on(ah);
- break;
- case ATH9K_RESET_WARM:
- case ATH9K_RESET_COLD:
- return ath9k_hw_set_reset(ah, type);
- break;
- default:
- return false;
- }
-}
-
-static
-struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u/0x%x; not marked as "
- "2GHz or 5GHz\n", __func__, chan->channel,
- chan->channelFlags);
- return NULL;
- }
-
- if (!IS_CHAN_OFDM(chan) &&
- !IS_CHAN_CCK(chan) &&
- !IS_CHAN_HT20(chan) &&
- !IS_CHAN_HT40(chan)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u/0x%x; not marked as "
- "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
- __func__, chan->channel, chan->channelFlags);
- return NULL;
- }
-
- return ath9k_regd_check_channel(ah, chan);
-}
-
-static inline bool
-ath9k_hw_get_lower_upper_index(u8 target,
- u8 *pList,
- u16 listSize,
- u16 *indexL,
- u16 *indexR)
-{
- u16 i;
-
- if (target <= pList[0]) {
- *indexL = *indexR = 0;
- return true;
- }
- if (target >= pList[listSize - 1]) {
- *indexL = *indexR = (u16) (listSize - 1);
- return true;
- }
-
- for (i = 0; i < listSize - 1; i++) {
- if (pList[i] == target) {
- *indexL = *indexR = i;
- return true;
- }
- if (target < pList[i + 1]) {
- *indexL = i;
- *indexR = (u16) (i + 1);
- return false;
- }
- }
- return false;
-}
-
-static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
-{
- int16_t nfval;
- int16_t sort[ATH9K_NF_CAL_HIST_MAX];
- int i, j;
-
- for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
- sort[i] = nfCalBuffer[i];
-
- for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
- for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
- if (sort[j] > sort[j - 1]) {
- nfval = sort[j];
- sort[j] = sort[j - 1];
- sort[j - 1] = nfval;
- }
- }
- }
- nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
-
- return nfval;
-}
-
-static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
- int16_t *nfarray)
+static int ath9k_hw_init_macaddr(struct ath_hal *ah)
{
+ u32 sum;
int i;
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
-
- if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
- h[i].currIndex = 0;
-
- if (h[i].invalidNFcount > 0) {
- if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE
- || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
- h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
- } else {
- h[i].invalidNFcount--;
- h[i].privNF = nfarray[i];
- }
- } else {
- h[i].privNF =
- ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
- }
- }
- return;
-}
-
-static void ar5416GetNoiseFloor(struct ath_hal *ah,
- int16_t nfarray[NUM_NF_READINGS])
-{
- int16_t nf;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
- else
- nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
- nfarray[0] = nf;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
- AR9280_PHY_CH1_MINCCA_PWR);
- else
- nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
- AR_PHY_CH1_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
- nfarray[1] = nf;
-
- if (!AR_SREV_9280(ah)) {
- nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
- AR_PHY_CH2_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "NF calibrated [ctl] [chain 2] is %d\n", nf);
- nfarray[2] = nf;
- }
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
- AR9280_PHY_EXT_MINCCA_PWR);
- else
- nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
- AR_PHY_EXT_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
- nfarray[3] = nf;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
- AR9280_PHY_CH1_EXT_MINCCA_PWR);
- else
- nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
- AR_PHY_CH1_EXT_MINCCA_PWR);
-
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
- nfarray[4] = nf;
-
- if (!AR_SREV_9280(ah)) {
- nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
- AR_PHY_CH2_EXT_MINCCA_PWR);
- if (nf & 0x100)
- nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "NF calibrated [ext] [chain 2] is %d\n", nf);
- nfarray[5] = nf;
- }
-}
-
-static bool
-getNoiseFloorThresh(struct ath_hal *ah,
- const struct ath9k_channel *chan,
- int16_t *nft)
-{
+ u16 eeval;
struct ath_hal_5416 *ahp = AH5416(ah);
- switch (chan->chanmode) {
- case CHANNEL_A:
- case CHANNEL_A_HT20:
- case CHANNEL_A_HT40PLUS:
- case CHANNEL_A_HT40MINUS:
- *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5);
- break;
- case CHANNEL_B:
- case CHANNEL_G:
- case CHANNEL_G_HT20:
- case CHANNEL_G_HT40PLUS:
- case CHANNEL_G_HT40MINUS:
- *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2);
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel flags 0x%x\n", __func__,
- chan->channelFlags);
- return false;
- }
- return true;
-}
-
-static void ath9k_hw_start_nfcal(struct ath_hal *ah)
-{
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-}
-
-static void
-ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
-{
- struct ath9k_nfcal_hist *h;
- int i, j;
- int32_t val;
- const u32 ar5416_cca_regs[6] = {
- AR_PHY_CCA,
- AR_PHY_CH1_CCA,
- AR_PHY_CH2_CCA,
- AR_PHY_EXT_CCA,
- AR_PHY_CH1_EXT_CCA,
- AR_PHY_CH2_EXT_CCA
- };
- u8 chainmask;
-
- if (AR_SREV_9280(ah))
- chainmask = 0x1B;
- else
- chainmask = 0x3F;
-
-#ifdef ATH_NF_PER_CHAN
- h = chan->nfCalHist;
-#else
- h = ah->nfCalHist;
-#endif
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
-
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_ENABLE_NF);
- REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
- AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
- REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
- for (j = 0; j < 1000; j++) {
- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
- AR_PHY_AGC_CONTROL_NF) == 0)
- break;
- udelay(10);
- }
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- if (chainmask & (1 << i)) {
- val = REG_READ(ah, ar5416_cca_regs[i]);
- val &= 0xFFFFFE00;
- val |= (((u32) (-50) << 1) & 0x1ff);
- REG_WRITE(ah, ar5416_cca_regs[i], val);
- }
- }
-}
-
-static int16_t ath9k_hw_getnf(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- int16_t nf, nfThresh;
- int16_t nfarray[NUM_NF_READINGS] = { 0 };
- struct ath9k_nfcal_hist *h;
- u8 chainmask;
-
- if (AR_SREV_9280(ah))
- chainmask = 0x1B;
- else
- chainmask = 0x3F;
-
- chan->channelFlags &= (~CHANNEL_CW_INT);
- if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: NF did not complete in calibration window\n",
- __func__);
- nf = 0;
- chan->rawNoiseFloor = nf;
- return chan->rawNoiseFloor;
- } else {
- ar5416GetNoiseFloor(ah, nfarray);
- nf = nfarray[0];
- if (getNoiseFloorThresh(ah, chan, &nfThresh)
- && nf > nfThresh) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: noise floor failed detected; "
- "detected %d, threshold %d\n", __func__,
- nf, nfThresh);
- chan->channelFlags |= CHANNEL_CW_INT;
- }
+ sum = 0;
+ for (i = 0; i < 3; i++) {
+ eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i));
+ sum += eeval;
+ ahp->ah_macaddr[2 * i] = eeval >> 8;
+ ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
}
-
-#ifdef ATH_NF_PER_CHAN
- h = chan->nfCalHist;
-#else
- h = ah->nfCalHist;
-#endif
-
- ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
- chan->rawNoiseFloor = h[0].privNF;
-
- return chan->rawNoiseFloor;
-}
-
-static void ath9k_hw_update_mibstats(struct ath_hal *ah,
- struct ath9k_mib_stats *stats)
-{
- stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
- stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
- stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
- stats->rts_good += REG_READ(ah, AR_RTS_OK);
- stats->beacons += REG_READ(ah, AR_BEACON_CNT);
-}
-
-static void ath9k_enable_mib_counters(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n");
-
- ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
- REG_WRITE(ah, AR_FILT_OFDM, 0);
- REG_WRITE(ah, AR_FILT_CCK, 0);
- REG_WRITE(ah, AR_MIBC,
- ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
- & 0x0f);
- 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);
-}
-
-static void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n");
-
- REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
-
- ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
- REG_WRITE(ah, AR_FILT_OFDM, 0);
- REG_WRITE(ah, AR_FILT_CCK, 0);
-}
-
-static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
- if (ahp->ah_ani[i].c.channel == chan->channel)
- return i;
- if (ahp->ah_ani[i].c.channel == 0) {
- ahp->ah_ani[i].c.channel = chan->channel;
- ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
- return i;
- }
+ if (sum == 0 || sum == 0xffff * 3) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "mac address read failed: %pM\n",
+ ahp->ah_macaddr);
+ return -EADDRNOTAVAIL;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "No more channel states left. Using channel 0\n");
return 0;
}
-static void ath9k_hw_ani_attach(struct ath_hal *ah)
+static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah)
{
+ u32 rxgain_type;
struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
- ahp->ah_hasHwPhyCounters = 1;
-
- memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
- for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
- ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
- ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
- ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
- ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
- ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
- ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
- ahp->ah_ani[i].ofdmWeakSigDetectOff =
- !ATH9K_ANI_USE_OFDM_WEAK_SIG;
- ahp->ah_ani[i].cckWeakSigThreshold =
- ATH9K_ANI_CCK_WEAK_SIG_THR;
- ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
- ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
- if (ahp->ah_hasHwPhyCounters) {
- ahp->ah_ani[i].ofdmPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
- ahp->ah_ani[i].cckPhyErrBase =
- AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
- }
- }
- if (ahp->ah_hasHwPhyCounters) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Setting OfdmErrBase = 0x%08x\n",
- ahp->ah_ani[0].ofdmPhyErrBase);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
- ahp->ah_ani[0].cckPhyErrBase);
-
- REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
- ath9k_enable_mib_counters(ah);
- }
- ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
- if (ah->ah_config.enable_ani)
- ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
-}
-
-static void ath9k_hw_ani_setup(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
+ if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
+ rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE);
- const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
- const int coarseHigh[] = { -14, -14, -14, -14, -12 };
- const int coarseLow[] = { -64, -64, -64, -64, -70 };
- const int firpwr[] = { -78, -78, -78, -78, -80 };
-
- for (i = 0; i < 5; i++) {
- ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
- ahp->ah_coarseHigh[i] = coarseHigh[i];
- ahp->ah_coarseLow[i] = coarseLow[i];
- ahp->ah_firpwr[i] = firpwr[i];
- }
-}
-
-static void ath9k_hw_ani_detach(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n");
- if (ahp->ah_hasHwPhyCounters) {
- ath9k_hw_disable_mib_counters(ah);
- REG_WRITE(ah, AR_PHY_ERR_1, 0);
- REG_WRITE(ah, AR_PHY_ERR_2, 0);
- }
-}
-
-
-static bool ath9k_hw_ani_control(struct ath_hal *ah,
- enum ath9k_ani_cmd cmd, int param)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState = ahp->ah_curani;
-
- switch (cmd & ahp->ah_ani_function) {
- case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
- u32 level = param;
-
- if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: level out of range (%u > %u)\n",
- __func__, level,
- (unsigned) ARRAY_SIZE(ahp->
- ah_totalSizeDesired));
- return false;
- }
-
- REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
- AR_PHY_DESIRED_SZ_TOT_DES,
- ahp->ah_totalSizeDesired[level]);
- REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
- AR_PHY_AGC_CTL1_COARSE_LOW,
- ahp->ah_coarseLow[level]);
- REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
- AR_PHY_AGC_CTL1_COARSE_HIGH,
- ahp->ah_coarseHigh[level]);
- REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
- AR_PHY_FIND_SIG_FIRPWR,
- ahp->ah_firpwr[level]);
-
- if (level > aniState->noiseImmunityLevel)
- ahp->ah_stats.ast_ani_niup++;
- else if (level < aniState->noiseImmunityLevel)
- ahp->ah_stats.ast_ani_nidown++;
- aniState->noiseImmunityLevel = level;
- break;
- }
- case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
- const int m1ThreshLow[] = { 127, 50 };
- const int m2ThreshLow[] = { 127, 40 };
- const int m1Thresh[] = { 127, 0x4d };
- const int m2Thresh[] = { 127, 0x40 };
- const int m2CountThr[] = { 31, 16 };
- const int m2CountThrLow[] = { 63, 48 };
- u32 on = param ? 1 : 0;
-
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
- AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
- m1ThreshLow[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
- AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
- m2ThreshLow[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M1_THRESH,
- m1Thresh[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M2_THRESH,
- m2Thresh[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR,
- AR_PHY_SFCORR_M2COUNT_THR,
- m2CountThr[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
- m2CountThrLow[on]);
-
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
- m1ThreshLow[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
- m2ThreshLow[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M1_THRESH,
- m1Thresh[on]);
- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
- AR_PHY_SFCORR_EXT_M2_THRESH,
- m2Thresh[on]);
-
- if (on)
- REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
- AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+ if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+ INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+ ar9280Modes_backoff_13db_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+ else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
+ INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+ ar9280Modes_backoff_23db_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
else
- REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
- AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
- if (!on != aniState->ofdmWeakSigDetectOff) {
- if (on)
- ahp->ah_stats.ast_ani_ofdmon++;
- else
- ahp->ah_stats.ast_ani_ofdmoff++;
- aniState->ofdmWeakSigDetectOff = !on;
- }
- break;
- }
- case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
- 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)
- ahp->ah_stats.ast_ani_cckhigh++;
- else
- ahp->ah_stats.ast_ani_ccklow++;
- aniState->cckWeakSigThreshold = high;
- }
- break;
- }
- case ATH9K_ANI_FIRSTEP_LEVEL:{
- const int firstep[] = { 0, 4, 8 };
- u32 level = param;
-
- if (level >= ARRAY_SIZE(firstep)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: level out of range (%u > %u)\n",
- __func__, level,
- (unsigned) ARRAY_SIZE(firstep));
- return false;
- }
- REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
- AR_PHY_FIND_SIG_FIRSTEP,
- firstep[level]);
- if (level > aniState->firstepLevel)
- ahp->ah_stats.ast_ani_stepup++;
- else if (level < aniState->firstepLevel)
- ahp->ah_stats.ast_ani_stepdown++;
- aniState->firstepLevel = level;
- break;
- }
- case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
- const int cycpwrThr1[] =
- { 2, 4, 6, 8, 10, 12, 14, 16 };
- u32 level = param;
-
- if (level >= ARRAY_SIZE(cycpwrThr1)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: level out of range (%u > %u)\n",
- __func__, level,
- (unsigned)
- ARRAY_SIZE(cycpwrThr1));
- return false;
- }
- REG_RMW_FIELD(ah, AR_PHY_TIMING5,
- AR_PHY_TIMING5_CYCPWR_THR1,
- cycpwrThr1[level]);
- if (level > aniState->spurImmunityLevel)
- ahp->ah_stats.ast_ani_spurup++;
- else if (level < aniState->spurImmunityLevel)
- ahp->ah_stats.ast_ani_spurdown++;
- aniState->spurImmunityLevel = level;
- break;
- }
- case ATH9K_ANI_PRESENT:
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: invalid cmd %u\n", __func__, cmd);
- return false;
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
- "ofdmWeakSigDetectOff=%d\n",
- aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cckWeakSigThreshold=%d, "
- "firstepLevel=%d, listenTime=%d\n",
- aniState->cckWeakSigThreshold, aniState->firstepLevel,
- aniState->listenTime);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
- aniState->cycleCount, aniState->ofdmPhyErrCount,
- aniState->cckPhyErrCount);
- return true;
-}
-
-static void ath9k_ani_restart(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState;
-
- if (!DO_ANI(ah))
- return;
-
- aniState = ahp->ah_curani;
-
- aniState->listenTime = 0;
- if (ahp->ah_hasHwPhyCounters) {
- if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
- aniState->ofdmPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "OFDM Trigger is too high for hw counters\n");
- } else {
- aniState->ofdmPhyErrBase =
- AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
- }
- if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
- aniState->cckPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "CCK Trigger is too high for hw counters\n");
- } else {
- aniState->cckPhyErrBase =
- AR_PHY_COUNTMAX - aniState->cckTrigHigh;
- }
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: Writing ofdmbase=%u cckbase=%u\n",
- __func__, aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
- ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
- }
- aniState->ofdmPhyErrCount = 0;
- aniState->cckPhyErrCount = 0;
-}
-
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *chan = ah->ah_curchan;
- struct ar5416AniState *aniState;
- enum wireless_mode mode;
- int32_t rssi;
-
- if (!DO_ANI(ah))
- return;
-
- aniState = ahp->ah_curani;
-
- 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->ah_opmode == ATH9K_M_HOSTAP) {
- if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
- ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel + 1);
- }
- return;
- }
- rssi = BEACON_RSSI(ahp);
- 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 {
- mode = ath9k_hw_chan2wmode(ah, chan);
- if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
- 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(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *chan = ah->ah_curchan;
- struct ar5416AniState *aniState;
- enum wireless_mode mode;
- int32_t rssi;
-
- if (!DO_ANI(ah))
- return;
-
- aniState = ahp->ah_curani;
- if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
- if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
- aniState->noiseImmunityLevel + 1)) {
- return;
- }
- }
- if (ah->ah_opmode == ATH9K_M_HOSTAP) {
- if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
- ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel + 1);
- }
- return;
- }
- rssi = BEACON_RSSI(ahp);
- if (rssi > aniState->rssiThrLow) {
- if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
- ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel + 1);
- } else {
- mode = ath9k_hw_chan2wmode(ah, chan);
- if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
- if (aniState->firstepLevel > 0)
- ath9k_hw_ani_control(ah,
- ATH9K_ANI_FIRSTEP_LEVEL,
- 0);
- }
- }
-}
-
-static void ath9k_ani_reset(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState;
- struct ath9k_channel *chan = ah->ah_curchan;
- int index;
-
- if (!DO_ANI(ah))
- return;
-
- index = ath9k_hw_get_ani_channel_idx(ah, chan);
- aniState = &ahp->ah_ani[index];
- ahp->ah_curani = aniState;
-
- if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
- && ah->ah_opmode != ATH9K_M_IBSS) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: Reset ANI state opmode %u\n", __func__,
- ah->ah_opmode);
- ahp->ah_stats.ast_ani_reset++;
- 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_hw_setrxfilter(ah,
- ath9k_hw_getrxfilter(ah) |
- ATH9K_RX_FILTER_PHYERR);
- if (ah->ah_opmode == ATH9K_M_HOSTAP) {
- ahp->ah_curani->ofdmTrigHigh =
- ah->ah_config.ofdm_trig_high;
- ahp->ah_curani->ofdmTrigLow =
- ah->ah_config.ofdm_trig_low;
- ahp->ah_curani->cckTrigHigh =
- ah->ah_config.cck_trig_high;
- ahp->ah_curani->cckTrigLow =
- ah->ah_config.cck_trig_low;
- }
- 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);
- if (ahp->ah_hasHwPhyCounters) {
- ath9k_hw_setrxfilter(ah,
- ath9k_hw_getrxfilter(ah) &
- ~ATH9K_RX_FILTER_PHYERR);
- ath9k_ani_restart(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);
-
- } else {
- ath9k_ani_restart(ah);
- ath9k_hw_setrxfilter(ah,
- ath9k_hw_getrxfilter(ah) |
- ATH9K_RX_FILTER_PHYERR);
- }
-}
-
-/*
- * 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_procmibevent(struct ath_hal *ah,
- const struct ath9k_node_stats *stats)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 phyCnt1, phyCnt2;
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
- /* 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, &ahp->ah_mibStats);
- ahp->ah_stats.ast_nodestats = *stats;
-
- if (!DO_ANI(ah))
- 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)) {
- struct ar5416AniState *aniState = ahp->ah_curani;
- u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
- /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
- ahp->ah_stats.ast_ani_ofdmerrs +=
- ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
- aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
- ahp->ah_stats.ast_ani_cckerrs +=
- cckPhyErrCnt - aniState->cckPhyErrCount;
- aniState->cckPhyErrCount = cckPhyErrCnt;
-
- /*
- * NB: figure out which counter triggered. If both
- * trigger we'll only deal with one as the processing
- * clobbers the error counter so the trigger threshold
- * check will never be true.
- */
- if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
- ath9k_hw_ani_ofdm_err_trigger(ah);
- if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
- ath9k_hw_ani_cck_err_trigger(ah);
- /* NB: always restart to insure the h/w counters are reset */
- ath9k_ani_restart(ah);
- }
-}
-
-static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState;
- int32_t rssi;
-
- aniState = ahp->ah_curani;
-
- if (ah->ah_opmode == ATH9K_M_HOSTAP) {
- if (aniState->firstepLevel > 0) {
- if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel - 1)) {
- return;
- }
- }
- } else {
- rssi = BEACON_RSSI(ahp);
- 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) ==
- true) {
- return;
- }
- }
- if (aniState->firstepLevel > 0) {
- if (ath9k_hw_ani_control
- (ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel - 1) ==
- true) {
- return;
- }
- }
- } else {
- if (aniState->firstepLevel > 0) {
- if (ath9k_hw_ani_control
- (ah, ATH9K_ANI_FIRSTEP_LEVEL,
- aniState->firstepLevel - 1) ==
- true) {
- 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;
- }
-}
-
-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState;
- u32 txFrameCount, rxFrameCount, cycleCount;
- int32_t listenTime;
-
- txFrameCount = REG_READ(ah, AR_TFCNT);
- rxFrameCount = REG_READ(ah, AR_RFCNT);
- cycleCount = REG_READ(ah, AR_CCCNT);
-
- aniState = ahp->ah_curani;
- if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-
- listenTime = 0;
- ahp->ah_stats.ast_ani_lzero++;
- } else {
- int32_t ccdelta = cycleCount - aniState->cycleCount;
- int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
- int32_t tfdelta = txFrameCount - aniState->txFrameCount;
- listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
- }
- aniState->cycleCount = cycleCount;
- aniState->txFrameCount = txFrameCount;
- aniState->rxFrameCount = rxFrameCount;
-
- return listenTime;
+ INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+ ar9280Modes_original_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+ } else
+ INIT_INI_ARRAY(&ahp->ah_iniModesRxGain,
+ ar9280Modes_original_rxgain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
}
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
- const struct ath9k_node_stats *stats,
- struct ath9k_channel *chan)
+static void ath9k_hw_init_txgain_ini(struct ath_hal *ah)
{
+ u32 txgain_type;
struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416AniState *aniState;
- int32_t listenTime;
-
- aniState = ahp->ah_curani;
- ahp->ah_stats.ast_nodestats = *stats;
-
- listenTime = ath9k_hw_ani_get_listen_time(ah);
- if (listenTime < 0) {
- ahp->ah_stats.ast_ani_lneg++;
- ath9k_ani_restart(ah);
- return;
- }
-
- aniState->listenTime += listenTime;
-
- if (ahp->ah_hasHwPhyCounters) {
- u32 phyCnt1, phyCnt2;
- u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
- ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
- phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
- phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
- if (phyCnt1 < aniState->ofdmPhyErrBase ||
- phyCnt2 < aniState->cckPhyErrBase) {
- if (phyCnt1 < aniState->ofdmPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- __func__, phyCnt1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_1,
- aniState->ofdmPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_1,
- AR_PHY_ERR_OFDM_TIMING);
- }
- if (phyCnt2 < aniState->cckPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "%s: phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- __func__, phyCnt2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_2,
- aniState->cckPhyErrBase);
- REG_WRITE(ah, AR_PHY_ERR_MASK_2,
- AR_PHY_ERR_CCK_TIMING);
- }
- return;
- }
-
- ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
- ahp->ah_stats.ast_ani_ofdmerrs +=
- ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
- aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
- cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
- ahp->ah_stats.ast_ani_cckerrs +=
- cckPhyErrCnt - aniState->cckPhyErrCount;
- aniState->cckPhyErrCount = cckPhyErrCnt;
- }
-
- if (!DO_ANI(ah))
- return;
-
- if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
- if (aniState->ofdmPhyErrCount <= aniState->listenTime *
- aniState->ofdmTrigLow / 1000 &&
- aniState->cckPhyErrCount <= aniState->listenTime *
- aniState->cckTrigLow / 1000)
- ath9k_hw_ani_lower_immunity(ah);
- ath9k_ani_restart(ah);
- } else if (aniState->listenTime > ahp->ah_aniPeriod) {
- if (aniState->ofdmPhyErrCount > aniState->listenTime *
- aniState->ofdmTrigHigh / 1000) {
- ath9k_hw_ani_ofdm_err_trigger(ah);
- ath9k_ani_restart(ah);
- } else if (aniState->cckPhyErrCount >
- aniState->listenTime * aniState->cckTrigHigh /
- 1000) {
- ath9k_hw_ani_cck_err_trigger(ah);
- ath9k_ani_restart(ah);
- }
- }
-}
-
-#ifndef ATH_NF_PER_CHAN
-static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
-{
- int i, j;
-
- for (i = 0; i < NUM_NF_READINGS; i++) {
- ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
- ah->nfCalHist[i].invalidNFcount =
- AR_PHY_CCA_FILTERWINDOW_LENGTH;
- for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
- }
- }
- return;
-}
-#endif
-
-static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
- u32 gpio, u32 type)
-{
- int addr;
- u32 gpio_shift, tmp;
-
- if (gpio > 11)
- addr = AR_GPIO_OUTPUT_MUX3;
- else if (gpio > 5)
- addr = AR_GPIO_OUTPUT_MUX2;
- else
- addr = AR_GPIO_OUTPUT_MUX1;
-
- gpio_shift = (gpio % 6) * 5;
-
- if (AR_SREV_9280_20_OR_LATER(ah)
- || (addr != AR_GPIO_OUTPUT_MUX1)) {
- REG_RMW(ah, addr, (type << gpio_shift),
- (0x1f << gpio_shift));
- } else {
- tmp = REG_READ(ah, addr);
- tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
- tmp &= ~(0x1f << gpio_shift);
- tmp |= (type << gpio_shift);
- REG_WRITE(ah, addr, tmp);
- }
-}
-
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
- u32 ah_signal_type)
-{
- u32 gpio_shift;
-
- ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
-
- gpio_shift = 2 * gpio;
-
- REG_RMW(ah,
- AR_GPIO_OE_OUT,
- (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
- (AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
-{
- REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
- AR_GPIO_BIT(gpio));
-}
-
-/*
- * Configure GPIO Input lines
- */
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
-{
- u32 gpio_shift;
-
- ASSERT(gpio < ah->ah_caps.num_gpio_pins);
-
- gpio_shift = gpio << 1;
-
- REG_RMW(ah,
- AR_GPIO_OE_OUT,
- (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
- (AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-#ifdef CONFIG_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
- REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
- AR_GPIO_INPUT_MUX2_RFSILENT);
- ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
- REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-#endif
-
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
-{
- if (gpio >= ah->ah_caps.num_gpio_pins)
- return 0xffffffff;
+ if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
+ txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE);
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- return (MS
- (REG_READ(ah, AR_GPIO_IN_OUT),
- AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
- } else {
- return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
- AR_GPIO_BIT(gpio)) != 0;
- }
+ if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+ INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+ ar9280Modes_high_power_tx_gain_9280_2,
+ ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+ else
+ INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+ ar9280Modes_original_tx_gain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+ } else
+ INIT_INI_ARRAY(&ahp->ah_iniModesTxGain,
+ ar9280Modes_original_tx_gain_9280_2,
+ ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
}
static int ath9k_hw_post_attach(struct ath_hal *ah)
@@ -2887,7 +613,7 @@ static int ath9k_hw_post_attach(struct ath_hal *ah)
if (!ath9k_hw_chip_test(ah)) {
DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "%s: hardware self-test failed\n", __func__);
+ "hardware self-test failed\n");
return -ENODEV;
}
@@ -2906,365 +632,17 @@ static int ath9k_hw_post_attach(struct ath_hal *ah)
ath9k_hw_ani_setup(ah);
ath9k_hw_ani_attach(ah);
}
- return 0;
-}
-
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
- struct ar5416_eeprom *pEepData,
- u32 reg, u32 value)
-{
- struct base_eep_header *pBase = &(pEepData->baseEepHeader);
-
- switch (ah->ah_devid) {
- case AR9280_DEVID_PCI:
- if (reg == 0x7894) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "ini VAL: %x EEPROM: %x\n", value,
- (pBase->version & 0xff));
-
- if ((pBase->version & 0xff) > 0x0a) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "PWDCLKIND: %d\n",
- pBase->pwdclkind);
- value &= ~AR_AN_TOP2_PWDCLKIND;
- value |= AR_AN_TOP2_PWDCLKIND & (pBase->
- pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
- } else {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "PWDCLKIND Earlier Rev\n");
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "final ini VAL: %x\n", value);
- }
- break;
- }
- return value;
-}
-
-static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- u16 capField = 0, eeval;
-
- eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0);
-
- ah->ah_currentRD = eeval;
-
- eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1);
- ah->ah_currentRDExt = eeval;
-
- capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP);
-
- if (ah->ah_opmode != ATH9K_M_HOSTAP &&
- ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
- if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
- ah->ah_currentRD += 5;
- else if (ah->ah_currentRD == 0x41)
- ah->ah_currentRD = 0x43;
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: regdomain mapped to 0x%x\n", __func__,
- ah->ah_currentRD);
- }
-
- eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE);
- bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
-
- if (eeval & AR5416_OPFLAGS_11A) {
- set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
- if (ah->ah_config.ht_enable) {
- if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
- set_bit(ATH9K_MODE_11NA_HT20,
- pCap->wireless_modes);
- if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
- set_bit(ATH9K_MODE_11NA_HT40PLUS,
- pCap->wireless_modes);
- set_bit(ATH9K_MODE_11NA_HT40MINUS,
- pCap->wireless_modes);
- }
- }
- }
-
- if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
- set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
- if (ah->ah_config.ht_enable) {
- if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
- set_bit(ATH9K_MODE_11NG_HT20,
- pCap->wireless_modes);
- if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
- set_bit(ATH9K_MODE_11NG_HT40PLUS,
- pCap->wireless_modes);
- set_bit(ATH9K_MODE_11NG_HT40MINUS,
- pCap->wireless_modes);
- }
- }
- }
-
- pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK);
- if ((ah->ah_isPciExpress)
- || (eeval & AR5416_OPFLAGS_11A)) {
- pCap->rx_chainmask =
- ath9k_hw_get_eeprom(ahp, EEP_RX_MASK);
- } else {
- pCap->rx_chainmask =
- (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
- }
-
- if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
- ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
-
- pCap->low_2ghz_chan = 2312;
- pCap->high_2ghz_chan = 2732;
-
- pCap->low_5ghz_chan = 4920;
- pCap->high_5ghz_chan = 6100;
-
- pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
-
- pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
- pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
-
- pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
-
- if (ah->ah_config.ht_enable)
- pCap->hw_caps |= ATH9K_HW_CAP_HT;
- else
- pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
-
- pCap->hw_caps |= ATH9K_HW_CAP_GTT;
- pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
- pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
- pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
-
- if (capField & AR_EEPROM_EEPCAP_MAXQCU)
- pCap->total_queues =
- MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
- else
- pCap->total_queues = ATH9K_NUM_TX_QUEUES;
-
- if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
- pCap->keycache_size =
- 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
- else
- pCap->keycache_size = AR_KEYTABLE_SIZE;
-
- pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
- pCap->num_mr_retries = 4;
- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- pCap->num_gpio_pins = AR928X_NUM_GPIO;
- else
- pCap->num_gpio_pins = AR_NUM_GPIO;
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- pCap->hw_caps |= ATH9K_HW_CAP_WOW;
- pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
- } else {
- pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
- pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
- }
-
- if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
- pCap->hw_caps |= ATH9K_HW_CAP_CST;
- pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
- } else {
- pCap->rts_aggr_limit = (8 * 1024);
- }
-
- pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-
-#ifdef CONFIG_RFKILL
- ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
- if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
- ah->ah_rfkill_gpio =
- MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
- ah->ah_rfkill_polarity =
- MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
-
- pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
- }
-#endif
-
- if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
- (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
- (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
- (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
- (ah->ah_macVersion == AR_SREV_VERSION_9280))
- pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
- else
- pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
-
- if (AR_SREV_9280(ah))
- pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
- else
- pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
-
- if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
- pCap->reg_cap =
- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
- AR_EEPROM_EEREGCAP_EN_KK_U2 |
- AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
- } else {
- pCap->reg_cap =
- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
- }
-
- pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-
- pCap->num_antcfg_5ghz =
- ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ);
- pCap->num_antcfg_2ghz =
- ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ);
-
- return true;
-}
-
-static void ar5416DisablePciePhy(struct ath_hal *ah)
-{
- if (!AR_SREV_9100(ah))
- return;
-
- REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
-
- REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-}
-
-static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
-{
- REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
- if (setChip) {
- REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN);
- if (!AR_SREV_9100(ah))
- REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-
- REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
- AR_RTC_RESET_EN);
- }
-}
-
-static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
-{
- REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
- if (setChip) {
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
- if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
- REG_WRITE(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_ON_INT);
- } else {
- REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
- AR_RTC_FORCE_WAKE_EN);
- }
- }
-}
-
-static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
- int setChip)
-{
- u32 val;
- int i;
-
- 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)
- != true) {
- return false;
- }
- }
- 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);
-
- 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) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- "%s: Failed to wakeup in %uus\n",
- __func__, POWER_UP_TIME / 20);
- return false;
- }
- }
-
- REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
- return true;
-}
-
-bool ath9k_hw_setpower(struct ath_hal *ah,
- enum ath9k_power_mode mode)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- static const char *modes[] = {
- "AWAKE",
- "FULL-SLEEP",
- "NETWORK SLEEP",
- "UNDEFINED"
- };
- int status = true, setChip = true;
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode],
- setChip ? "set chip " : "");
-
- switch (mode) {
- case ATH9K_PM_AWAKE:
- status = ath9k_hw_set_power_awake(ah, setChip);
- break;
- case ATH9K_PM_FULL_SLEEP:
- ath9k_set_power_sleep(ah, setChip);
- ahp->ah_chipFullSleep = true;
- break;
- case ATH9K_PM_NETWORK_SLEEP:
- ath9k_set_power_network_sleep(ah, setChip);
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- "%s: unknown power mode %u\n", __func__, mode);
- return false;
- }
- ahp->ah_powerMode = mode;
- return status;
+ return 0;
}
-static struct ath_hal *ath9k_hw_do_attach(u16 devid,
- struct ath_softc *sc,
- void __iomem *mem,
- int *status)
+static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
+ void __iomem *mem, int *status)
{
struct ath_hal_5416 *ahp;
struct ath_hal *ah;
int ecode;
-#ifndef CONFIG_SLOW_ANT_DIV
- u32 i;
- u32 j;
-#endif
+ u32 i, j;
ahp = ath9k_hw_newstate(devid, sc, mem, status);
if (ahp == NULL)
@@ -3278,15 +656,13 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
ahp->ah_intrMitigation = true;
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n",
- __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n");
ecode = -EIO;
goto bad;
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n",
- __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n");
ecode = -EIO;
goto bad;
}
@@ -3300,18 +676,18 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
SER_REG_MODE_OFF;
}
}
+
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: serialize_regmode is %d\n",
- __func__, ah->ah_config.serialize_regmode);
+ "serialize_regmode is %d\n",
+ ah->ah_config.serialize_regmode);
if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
(ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
(ah->ah_macVersion != AR_SREV_VERSION_9160) &&
- (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
+ (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", __func__,
- ah->ah_macVersion, ah->ah_macRev);
+ "Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", ah->ah_macVersion, ah->ah_macRev);
ecode = -EOPNOTSUPP;
goto bad;
}
@@ -3341,8 +717,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
ahp->ah_adcDcCalInitData.calData =
&adc_init_dc_cal;
}
- ahp->ah_suppCals =
- ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+ ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
if (AR_SREV_9160(ah)) {
@@ -3352,16 +727,46 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
} else {
ahp->ah_ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah)) {
- ahp->ah_ani_function &=
- ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+ ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
}
}
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__,
- ah->ah_macVersion, ah->ah_macRev);
+ "This Mac Chip Rev 0x%02x.%x is \n",
+ ah->ah_macVersion, ah->ah_macRev);
- if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (AR_SREV_9285_12_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2,
+ ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2,
+ ARRAY_SIZE(ar9285Common_9285_1_2), 2);
+
+ if (ah->ah_config.pcie_clock_req) {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9285PciePhy_clkreq_off_L1_9285_1_2,
+ ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
+ } else {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
+ ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
+ 2);
+ }
+ } else if (AR_SREV_9285_10_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285,
+ ARRAY_SIZE(ar9285Modes_9285), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285,
+ ARRAY_SIZE(ar9285Common_9285), 2);
+
+ if (ah->ah_config.pcie_clock_req) {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9285PciePhy_clkreq_off_L1_9285,
+ ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
+ } else {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9285PciePhy_clkreq_always_on_L1_9285,
+ ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
+ }
+ } else if (AR_SREV_9280_20_OR_LATER(ah)) {
INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
ARRAY_SIZE(ar9280Modes_9280_2), 6);
INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
@@ -3369,21 +774,16 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
if (ah->ah_config.pcie_clock_req) {
INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
- ar9280PciePhy_clkreq_off_L1_9280,
- ARRAY_SIZE
- (ar9280PciePhy_clkreq_off_L1_9280),
- 2);
+ ar9280PciePhy_clkreq_off_L1_9280,
+ ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
} else {
INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
- ar9280PciePhy_clkreq_always_on_L1_9280,
- ARRAY_SIZE
- (ar9280PciePhy_clkreq_always_on_L1_9280),
- 2);
+ ar9280PciePhy_clkreq_always_on_L1_9280,
+ ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
}
INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
ar9280Modes_fast_clock_9280_2,
- ARRAY_SIZE(ar9280Modes_fast_clock_9280_2),
- 3);
+ ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
} else if (AR_SREV_9280_10_OR_LATER(ah)) {
INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
ARRAY_SIZE(ar9280Modes_9280), 6);
@@ -3469,13 +869,20 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
if (ah->ah_isPciExpress)
ath9k_hw_configpcipowersave(ah, 0);
else
- ar5416DisablePciePhy(ah);
+ ath9k_hw_disablepcie(ah);
ecode = ath9k_hw_post_attach(ah);
if (ecode != 0)
goto bad;
-#ifndef CONFIG_SLOW_ANT_DIV
+ /* rxgain table */
+ if (AR_SREV_9280_20(ah))
+ ath9k_hw_init_rxgain_ini(ah);
+
+ /* txgain table */
+ if (AR_SREV_9280_20(ah))
+ ath9k_hw_init_txgain_ini(ah);
+
if (ah->ah_devid == AR9280_DEVID_PCI) {
for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
@@ -3484,16 +891,16 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
u32 val = INI_RA(&ahp->ah_iniModes, i, j);
INI_RA(&ahp->ah_iniModes, i, j) =
- ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
+ ath9k_hw_ini_fixup(ah,
+ &ahp->ah_eeprom.def,
reg, val);
}
}
}
-#endif
if (!ath9k_hw_fill_cap_info(ah)) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s:failed ath9k_hw_fill_cap_info\n", __func__);
+ "failed ath9k_hw_fill_cap_info\n");
ecode = -EINVAL;
goto bad;
}
@@ -3501,8 +908,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
ecode = ath9k_hw_init_macaddr(ah);
if (ecode != 0) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: failed initializing mac address\n",
- __func__);
+ "failed initializing mac address\n");
goto bad;
}
@@ -3511,1106 +917,569 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid,
else
ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
-#ifndef ATH_NF_PER_CHAN
-
ath9k_init_nfcal_hist_buffer(ah);
-#endif
return ah;
-
bad:
if (ahp)
ath9k_hw_detach((struct ath_hal *) ahp);
if (status)
*status = ecode;
+
return NULL;
}
-void ath9k_hw_detach(struct ath_hal *ah)
+static void ath9k_hw_init_bb(struct ath_hal *ah,
+ struct ath9k_channel *chan)
{
- if (!AR_SREV_9100(ah))
- ath9k_hw_ani_detach(ah);
- ath9k_hw_rfdetach(ah);
+ u32 synthDelay;
- ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
- kfree(ah);
+ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+ if (IS_CHAN_B(chan))
+ synthDelay = (4 * synthDelay) / 22;
+ else
+ synthDelay /= 10;
+
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+ udelay(synthDelay + BASE_ACTIVATE_DELAY);
}
-bool ath9k_get_channel_edges(struct ath_hal *ah,
- u16 flags, u16 *low,
- u16 *high)
+static void ath9k_hw_init_qos(struct ath_hal *ah)
{
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
+ REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
- if (flags & CHANNEL_5GHZ) {
- *low = pCap->low_5ghz_chan;
- *high = pCap->high_5ghz_chan;
- return true;
- }
- if ((flags & CHANNEL_2GHZ)) {
- *low = pCap->low_2ghz_chan;
- *high = pCap->high_2ghz_chan;
+ REG_WRITE(ah, AR_QOS_NO_ACK,
+ SM(2, AR_QOS_NO_ACK_TWO_BIT) |
+ SM(5, AR_QOS_NO_ACK_BIT_OFF) |
+ SM(0, AR_QOS_NO_ACK_BYTE_OFF));
- return true;
- }
- return false;
+ REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
+ REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
}
-static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin,
- u8 pwrMax,
- u8 *pPwrList,
- u8 *pVpdList,
- u16
- numIntercepts,
- u8 *pRetVpdList)
+static void ath9k_hw_init_pll(struct ath_hal *ah,
+ struct ath9k_channel *chan)
{
- u16 i, k;
- u8 currPwr = pwrMin;
- u16 idxL = 0, idxR = 0;
-
- for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
- ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
- numIntercepts, &(idxL),
- &(idxR));
- if (idxR < 1)
- idxR = 1;
- if (idxL == numIntercepts - 1)
- idxL = (u16) (numIntercepts - 2);
- if (pPwrList[idxL] == pPwrList[idxR])
- k = pVpdList[idxL];
- else
- k = (u16) (((currPwr -
- pPwrList[idxL]) *
- pVpdList[idxR] +
- (pPwrList[idxR] -
- currPwr) * pVpdList[idxL]) /
- (pPwrList[idxR] -
- pPwrList[idxL]));
- pRetVpdList[i] = (u8) k;
- currPwr += 2;
- }
+ u32 pll;
- return true;
-}
+ if (AR_SREV_9100(ah)) {
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll = 0x1450;
+ else
+ pll = 0x1458;
+ } else {
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-static void
-ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq *pRawDataSet,
- u8 *bChans,
- u16 availPiers,
- u16 tPdGainOverlap,
- int16_t *pMinCalPower,
- u16 *pPdGainBoundaries,
- u8 *pPDADCValues,
- u16 numXpdGains)
-{
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- static u8 vpdTableL[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableR[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
- static u8 vpdTableI[AR5416_NUM_PD_GAINS]
- [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR5416_NUM_PD_GAINS];
- u8 maxPwrT4[AR5416_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
- struct chan_centers centers;
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
- ath9k_hw_get_channel_centers(ah, chan, &centers);
+ if (chan && IS_CHAN_5GHZ(chan)) {
+ pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
- for (numPiers = 0; numPiers < availPiers; numPiers++) {
- if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
- break;
- }
- match = ath9k_hw_get_lower_upper_index((u8)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)), bChans,
- numPiers, &idxL, &idxR);
-
- if (match) {
- for (i = 0; i < numXpdGains; i++) {
- minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
- maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].
- pwrPdg[i],
- pRawDataSet[idxL].
- vpdPdg[i],
- AR5416_PD_GAIN_ICEPTS,
- vpdTableI[i]);
- }
- } else {
- for (i = 0; i < numXpdGains; i++) {
- pVpdL = pRawDataSet[idxL].vpdPdg[i];
- pPwrL = pRawDataSet[idxL].pwrPdg[i];
- pVpdR = pRawDataSet[idxR].vpdPdg[i];
- pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
- minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
- maxPwrT4[i] =
- min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
- pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableL[i]);
- ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR5416_PD_GAIN_ICEPTS,
- vpdTableR[i]);
-
- for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8) (ath9k_hw_interpolate
- ((u16)
- FREQ2FBIN(centers.
- synth_center,
- IS_CHAN_2GHZ
- (chan)),
- bChans[idxL],
- bChans[idxR], vpdTableL[i]
- [j], vpdTableR[i]
- [j]));
+ if (AR_SREV_9280_20(ah)) {
+ if (((chan->channel % 20) == 0)
+ || ((chan->channel % 10) == 0))
+ pll = 0x2850;
+ else
+ pll = 0x142c;
+ }
+ } else {
+ pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
}
- }
- }
- *pMinCalPower = (int16_t) (minPwrT4[0] / 2);
-
- k = 0;
- for (i = 0; i < numXpdGains; i++) {
- if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] =
- (u16) (maxPwrT4[i] / 2);
- else
- pPdGainBoundaries[i] =
- (u16) ((maxPwrT4[i] +
- minPwrT4[i + 1]) / 4);
+ } else if (AR_SREV_9160_10_OR_LATER(ah)) {
- pPdGainBoundaries[i] =
- min((u16) AR5416_MAX_RATE_POWER,
- pPdGainBoundaries[i]);
+ pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
- if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else {
- minDelta = 0;
- }
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
- if (i == 0) {
- if (AR_SREV_9280_10_OR_LATER(ah))
- ss = (int16_t) (0 - (minPwrT4[i] / 2));
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
else
- ss = 0;
+ pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
} else {
- ss = (int16_t) ((pPdGainBoundaries[i - 1] -
- (minPwrT4[i] / 2)) -
- tPdGainOverlap + 1 + minDelta);
- }
- vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]);
- vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
- while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep);
- pPDADCValues[k++] =
- (u8) ((tmpVal < 0) ? 0 : tmpVal);
- ss++;
- }
-
- sizeCurrVpdTable =
- (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
- tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap -
- (minPwrT4[i] / 2));
- maxIndex = (tgtIndex <
- sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
+ pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
- while ((ss < maxIndex)
- && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- pPDADCValues[k++] = vpdTableI[i][ss++];
- }
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
- vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] -
- vpdTableI[i][sizeCurrVpdTable - 2]);
- vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
- if (tgtIndex > maxIndex) {
- while ((ss <= tgtIndex)
- && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
- tmpVal = (int16_t) ((vpdTableI[i]
- [sizeCurrVpdTable -
- 1] + (ss - maxIndex +
- 1) * vpdStep));
- pPDADCValues[k++] = (u8) ((tmpVal >
- 255) ? 255 : tmpVal);
- ss++;
- }
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll |= SM(0xa, AR_RTC_PLL_DIV);
+ else
+ pll |= SM(0xb, AR_RTC_PLL_DIV);
}
}
+ REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
- while (i < AR5416_PD_GAINS_IN_MASK) {
- pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
- i++;
- }
+ udelay(RTC_PLL_SETTLE_DELAY);
- while (k < AR5416_NUM_PDADC_VALUES) {
- pPDADCValues[k] = pPDADCValues[k - 1];
- k++;
- }
- return;
+ REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
}
-static bool
-ath9k_hw_set_power_cal_table(struct ath_hal *ah,
- struct ar5416_eeprom *pEepData,
- struct ath9k_channel *chan,
- int16_t *pTxPowerIndexOffset)
+static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
{
- struct cal_data_per_freq *pRawDataset;
- u8 *pCalBChans = NULL;
- u16 pdGainOverlap_t2;
- static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
- u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
- u16 numPiers, i, j;
- int16_t tMinCalPower;
- u16 numXpdGain, xpdMask;
- u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
- u32 reg32, regOffset, regChainOffset;
- int16_t modalIdx;
struct ath_hal_5416 *ahp = AH5416(ah);
+ int rx_chainmask, tx_chainmask;
- modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
- xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
-
- if ((pEepData->baseEepHeader.
- version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- pdGainOverlap_t2 =
- pEepData->modalHeader[modalIdx].pdGainOverlap;
- } else {
- pdGainOverlap_t2 =
- (u16) (MS
- (REG_READ(ah, AR_PHY_TPCRG5),
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
- }
-
- if (IS_CHAN_2GHZ(chan)) {
- pCalBChans = pEepData->calFreqPier2G;
- numPiers = AR5416_NUM_2G_CAL_PIERS;
- } else {
- pCalBChans = pEepData->calFreqPier5G;
- numPiers = AR5416_NUM_5G_CAL_PIERS;
- }
-
- numXpdGain = 0;
+ rx_chainmask = ahp->ah_rxchainmask;
+ tx_chainmask = ahp->ah_txchainmask;
- for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
- if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
- if (numXpdGain >= AR5416_NUM_PD_GAINS)
- break;
- xpdGainValues[numXpdGain] =
- (u16) (AR5416_PD_GAINS_IN_MASK - i);
- numXpdGain++;
+ switch (rx_chainmask) {
+ case 0x5:
+ REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+ AR_PHY_SWAP_ALT_CHAIN);
+ case 0x3:
+ if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
+ break;
}
+ case 0x1:
+ case 0x2:
+ case 0x7:
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+ break;
+ default:
+ break;
}
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
- (numXpdGain - 1) & 0x3);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
- xpdGainValues[0]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
- xpdGainValues[1]);
- REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
- xpdGainValues[2]);
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (AR_SREV_5416_V20_OR_LATER(ah) &&
- (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
- && (i != 0)) {
- regChainOffset = (i == 1) ? 0x2000 : 0x1000;
- } else
- regChainOffset = i * 0x1000;
- if (pEepData->baseEepHeader.txMask & (1 << i)) {
- if (IS_CHAN_2GHZ(chan))
- pRawDataset = pEepData->calPierData2G[i];
- else
- pRawDataset = pEepData->calPierData5G[i];
-
- ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
- pRawDataset,
- pCalBChans,
- numPiers,
- pdGainOverlap_t2,
- &tMinCalPower,
- gainBoundaries,
- pdadcValues,
- numXpdGain);
-
- if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-
- REG_WRITE(ah,
- AR_PHY_TPCRG5 + regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
- | SM(gainBoundaries[0],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
- | SM(gainBoundaries[1],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
- | SM(gainBoundaries[2],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
- | SM(gainBoundaries[3],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
- }
-
- regOffset =
- AR_PHY_BASE + (672 << 2) + regChainOffset;
- for (j = 0; j < 32; j++) {
- reg32 =
- ((pdadcValues[4 * j + 0] & 0xFF) << 0)
- | ((pdadcValues[4 * j + 1] & 0xFF) <<
- 8) | ((pdadcValues[4 * j + 2] &
- 0xFF) << 16) |
- ((pdadcValues[4 * j + 3] & 0xFF) <<
- 24);
- REG_WRITE(ah, regOffset, reg32);
-
- DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
- "PDADC: Chain %d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
-
- regOffset += 4;
- }
- }
+ REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+ if (tx_chainmask == 0x5) {
+ REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+ AR_PHY_SWAP_ALT_CHAIN);
}
- *pTxPowerIndexOffset = 0;
-
- return true;
+ if (AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
+ REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
}
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
+static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
+ enum nl80211_iftype opmode)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- u8 i;
-
- if (ah->ah_isPciExpress != true)
- return;
- if (ah->ah_config.pcie_powersave_enable == 2)
- return;
+ ahp->ah_maskReg = AR_IMR_TXERR |
+ AR_IMR_TXURN |
+ AR_IMR_RXERR |
+ AR_IMR_RXORN |
+ AR_IMR_BCNMISC;
- if (restore)
- return;
+ if (ahp->ah_intrMitigation)
+ ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+ else
+ ahp->ah_maskReg |= AR_IMR_RXOK;
- if (AR_SREV_9280_20_OR_LATER(ah)) {
- for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
- REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
- INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
- }
- udelay(1000);
- } else if (AR_SREV_9280(ah)
- && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
- REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ ahp->ah_maskReg |= AR_IMR_TXOK;
- REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+ if (opmode == NL80211_IFTYPE_AP)
+ ahp->ah_maskReg |= AR_IMR_MIB;
- if (ah->ah_config.pcie_clock_req)
- REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
- else
- REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
+ REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+ REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+ }
+}
- REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
- udelay(1000);
+ if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
+ ahp->ah_acktimeout = (u32) -1;
+ return false;
} else {
- REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
- REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
- REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
- REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+ REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_acktimeout = us;
+ return true;
}
+}
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
- if (ah->ah_config.pcie_waen) {
- REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+ if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
+ ahp->ah_ctstimeout = (u32) -1;
+ return false;
} else {
- if (AR_SREV_9280(ah))
- REG_WRITE(ah, AR_WA, 0x0040073f);
- else
- REG_WRITE(ah, AR_WA, 0x0000073f);
+ REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_ctstimeout = us;
+ return true;
}
}
-static void
-ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
- struct ath9k_channel *chan,
- struct cal_target_power_leg *powInfo,
- u16 numChannels,
- struct cal_target_power_leg *pNewPower,
- u16 numRates,
- bool isExtTarget)
+static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu)
{
- u16 clo, chi;
- int i;
- int matchIndex = -1, lowIndex = -1;
- u16 freq;
- struct chan_centers centers;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
- freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+ struct ath_hal_5416 *ahp = AH5416(ah);
- if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
- IS_CHAN_2GHZ(chan))) {
- matchIndex = 0;
+ if (tu > 0xFFFF) {
+ DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+ "bad global tx timeout %u\n", tu);
+ ahp->ah_globaltxtimeout = (u32) -1;
+ return false;
} else {
- for (i = 0; (i < numChannels)
- && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
- if (freq ==
- ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan))) {
- matchIndex = i;
- break;
- } else if ((freq <
- ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan)))
- && (freq >
- ath9k_hw_fbin2freq(powInfo[i - 1].
- bChannel,
- IS_CHAN_2GHZ
- (chan)))) {
- lowIndex = i - 1;
- break;
- }
- }
- if ((matchIndex == -1) && (lowIndex == -1))
- matchIndex = i - 1;
+ REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
+ ahp->ah_globaltxtimeout = tu;
+ return true;
}
+}
- if (matchIndex != -1) {
- *pNewPower = powInfo[matchIndex];
- } else {
- clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
- IS_CHAN_2GHZ(chan));
- chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
- IS_CHAN_2GHZ(chan));
-
- for (i = 0; i < numRates; i++) {
- pNewPower->tPow2x[i] =
- (u8) ath9k_hw_interpolate(freq, clo, chi,
- powInfo
- [lowIndex].
- tPow2x[i],
- powInfo
- [lowIndex +
- 1].tPow2x[i]);
- }
- }
+static void ath9k_hw_init_user_settings(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n",
+ ahp->ah_miscMode);
+
+ if (ahp->ah_miscMode != 0)
+ REG_WRITE(ah, AR_PCU_MISC,
+ REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
+ if (ahp->ah_slottime != (u32) -1)
+ ath9k_hw_setslottime(ah, ahp->ah_slottime);
+ if (ahp->ah_acktimeout != (u32) -1)
+ ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
+ if (ahp->ah_ctstimeout != (u32) -1)
+ ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
+ if (ahp->ah_globaltxtimeout != (u32) -1)
+ ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
}
-static void
-ath9k_hw_get_target_powers(struct ath_hal *ah,
- struct ath9k_channel *chan,
- struct cal_target_power_ht *powInfo,
- u16 numChannels,
- struct cal_target_power_ht *pNewPower,
- u16 numRates,
- bool isHt40Target)
+const char *ath9k_hw_probe(u16 vendorid, u16 devid)
{
- u16 clo, chi;
- int i;
- int matchIndex = -1, lowIndex = -1;
- u16 freq;
- struct chan_centers centers;
+ return vendorid == ATHEROS_VENDOR_ID ?
+ ath9k_hw_devname(devid) : NULL;
+}
- ath9k_hw_get_channel_centers(ah, chan, &centers);
- freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+void ath9k_hw_detach(struct ath_hal *ah)
+{
+ if (!AR_SREV_9100(ah))
+ ath9k_hw_ani_detach(ah);
- if (freq <=
- ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
- matchIndex = 0;
- } else {
- for (i = 0; (i < numChannels)
- && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
- if (freq ==
- ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan))) {
- matchIndex = i;
- break;
- } else
- if ((freq <
- ath9k_hw_fbin2freq(powInfo[i].bChannel,
- IS_CHAN_2GHZ(chan)))
- && (freq >
- ath9k_hw_fbin2freq(powInfo[i - 1].
- bChannel,
- IS_CHAN_2GHZ
- (chan)))) {
- lowIndex = i - 1;
- break;
- }
- }
- if ((matchIndex == -1) && (lowIndex == -1))
- matchIndex = i - 1;
- }
+ ath9k_hw_rfdetach(ah);
+ ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+ kfree(ah);
+}
- if (matchIndex != -1) {
- *pNewPower = powInfo[matchIndex];
- } else {
- clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
- IS_CHAN_2GHZ(chan));
- chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
- IS_CHAN_2GHZ(chan));
-
- for (i = 0; i < numRates; i++) {
- pNewPower->tPow2x[i] =
- (u8) ath9k_hw_interpolate(freq, clo, chi,
- powInfo
- [lowIndex].
- tPow2x[i],
- powInfo
- [lowIndex +
- 1].tPow2x[i]);
- }
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+ void __iomem *mem, int *error)
+{
+ struct ath_hal *ah = NULL;
+
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ case AR9160_DEVID_PCI:
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ case AR9285_DEVID_PCIE:
+ ah = ath9k_hw_do_attach(devid, sc, mem, error);
+ break;
+ default:
+ *error = -ENXIO;
+ break;
}
+
+ return ah;
}
-static u16
-ath9k_hw_get_max_edge_power(u16 freq,
- struct cal_ctl_edges *pRdEdgesPower,
- bool is2GHz)
+/*******/
+/* INI */
+/*******/
+
+static void ath9k_hw_override_ini(struct ath_hal *ah,
+ struct ath9k_channel *chan)
{
- u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- int i;
+ /*
+ * Set the RX_ABORT and RX_DIS and clear if off only after
+ * RXE is set for MAC. This prevents frames with corrupted
+ * descriptor status.
+ */
+ REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
- for (i = 0; (i < AR5416_NUM_BAND_EDGES)
- && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
- if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
- is2GHz)) {
- twiceMaxEdgePower = pRdEdgesPower[i].tPower;
- break;
- } else if ((i > 0)
- && (freq <
- ath9k_hw_fbin2freq(pRdEdgesPower[i].
- bChannel, is2GHz))) {
- if (ath9k_hw_fbin2freq
- (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq
- && pRdEdgesPower[i - 1].flag) {
- twiceMaxEdgePower =
- pRdEdgesPower[i - 1].tPower;
+
+ if (!AR_SREV_5416_V20_OR_LATER(ah) ||
+ AR_SREV_9280_10_OR_LATER(ah))
+ return;
+
+ REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+}
+
+static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah,
+ struct ar5416_eeprom_def *pEepData,
+ u32 reg, u32 value)
+{
+ struct base_eep_header *pBase = &(pEepData->baseEepHeader);
+
+ switch (ah->ah_devid) {
+ case AR9280_DEVID_PCI:
+ if (reg == 0x7894) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "ini VAL: %x EEPROM: %x\n", value,
+ (pBase->version & 0xff));
+
+ if ((pBase->version & 0xff) > 0x0a) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "PWDCLKIND: %d\n",
+ pBase->pwdclkind);
+ value &= ~AR_AN_TOP2_PWDCLKIND;
+ value |= AR_AN_TOP2_PWDCLKIND &
+ (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "PWDCLKIND Earlier Rev\n");
}
- break;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "final ini VAL: %x\n", value);
}
+ break;
}
- return twiceMaxEdgePower;
+
+ return value;
}
-static bool
-ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
- struct ar5416_eeprom *pEepData,
- struct ath9k_channel *chan,
- int16_t *ratesArray,
- u16 cfgCtl,
- u8 AntennaReduction,
- u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+ struct ar5416_eeprom_def *pEepData,
+ u32 reg, u32 value)
{
- u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
- static const u16 tpScaleReductionTable[5] =
- { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+ struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
- int8_t twiceLargestAntenna;
- struct cal_ctl_data *rep;
- struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
- 0, { 0, 0, 0, 0}
- };
- struct cal_target_power_leg targetPowerOfdmExt = {
- 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
- 0, { 0, 0, 0, 0 }
- };
- struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
- 0, {0, 0, 0, 0}
- };
- u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11a[] =
- { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
- u16 ctlModesFor11g[] =
- { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
- CTL_2GHT40
- };
- u16 numCtlModes, *pCtlMode, ctlMode, freq;
- struct chan_centers centers;
- int tx_chainmask;
- u8 twiceMinEdgePower;
+ if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+ return value;
+ else
+ return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
+}
+
+static int ath9k_hw_process_ini(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ int i, regWrites = 0;
struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 modesIndex, freqIndex;
+ int status;
- tx_chainmask = ahp->ah_txchainmask;
+ switch (chan->chanmode) {
+ case CHANNEL_A:
+ case CHANNEL_A_HT20:
+ modesIndex = 1;
+ freqIndex = 1;
+ break;
+ case CHANNEL_A_HT40PLUS:
+ case CHANNEL_A_HT40MINUS:
+ modesIndex = 2;
+ freqIndex = 1;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_G_HT20:
+ case CHANNEL_B:
+ modesIndex = 4;
+ freqIndex = 2;
+ break;
+ case CHANNEL_G_HT40PLUS:
+ case CHANNEL_G_HT40MINUS:
+ modesIndex = 3;
+ freqIndex = 2;
+ break;
- ath9k_hw_get_channel_centers(ah, chan, &centers);
+ default:
+ return -EINVAL;
+ }
- twiceLargestAntenna = max(
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+ REG_WRITE(ah, AR_PHY(0), 0x00000007);
- twiceLargestAntenna = max((u8) twiceLargestAntenna,
- pEepData->modalHeader
- [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+ REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
- twiceLargestAntenna =
- (int8_t) min(AntennaReduction - twiceLargestAntenna, 0);
+ ath9k_hw_set_addac(ah, chan);
- maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+ if (AR_SREV_5416_V22_OR_LATER(ah)) {
+ REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
+ } else {
+ struct ar5416IniArray temp;
+ u32 addacSize =
+ sizeof(u32) * ahp->ah_iniAddac.ia_rows *
+ ahp->ah_iniAddac.ia_columns;
- if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
- maxRegAllowedPower -=
- (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
- }
+ memcpy(ahp->ah_addac5416_21,
+ ahp->ah_iniAddac.ia_array, addacSize);
- scaledPower = min(powerLimit, maxRegAllowedPower);
+ (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0;
- switch (ar5416_get_ntxchains(tx_chainmask)) {
- case 1:
- break;
- case 2:
- scaledPower -=
- pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
- pwrDecreaseFor2Chain;
- break;
- case 3:
- scaledPower -=
- pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
- pwrDecreaseFor3Chain;
- break;
+ temp.ia_array = ahp->ah_addac5416_21;
+ temp.ia_columns = ahp->ah_iniAddac.ia_columns;
+ temp.ia_rows = ahp->ah_iniAddac.ia_rows;
+ REG_WRITE_ARRAY(&temp, 1, regWrites);
}
- scaledPower = max(0, (int32_t) scaledPower);
-
- if (IS_CHAN_2GHZ(chan)) {
- numCtlModes =
- ARRAY_SIZE(ctlModesFor11g) -
- SUB_NUM_CTL_MODES_AT_2G_40;
- pCtlMode = ctlModesFor11g;
-
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCck, 4,
- false);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdm, 4,
- false);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower2GHT20,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerHt20, 8, false);
+ REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
- if (IS_CHAN_HT40(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11g);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->
- calTargetPower2GHT40,
- AR5416_NUM_2G_40_TARGET_POWERS,
- &targetPowerHt40, 8,
- true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPowerCck,
- AR5416_NUM_2G_CCK_TARGET_POWERS,
- &targetPowerCckExt,
- 4, true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPower2G,
- AR5416_NUM_2G_20_TARGET_POWERS,
- &targetPowerOfdmExt,
- 4, true);
- }
- } else {
+ for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
+ u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
+ u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
- numCtlModes =
- ARRAY_SIZE(ctlModesFor11a) -
- SUB_NUM_CTL_MODES_AT_5G_40;
- pCtlMode = ctlModesFor11a;
-
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPower5G,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerOfdm, 4,
- false);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->calTargetPower5GHT20,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerHt20, 8, false);
+ REG_WRITE(ah, reg, val);
- if (IS_CHAN_HT40(chan)) {
- numCtlModes = ARRAY_SIZE(ctlModesFor11a);
- ath9k_hw_get_target_powers(ah, chan,
- pEepData->
- calTargetPower5GHT40,
- AR5416_NUM_5G_40_TARGET_POWERS,
- &targetPowerHt40, 8,
- true);
- ath9k_hw_get_legacy_target_powers(ah, chan,
- pEepData->
- calTargetPower5G,
- AR5416_NUM_5G_20_TARGET_POWERS,
- &targetPowerOfdmExt,
- 4, true);
+ if (reg >= 0x7800 && reg < 0x78a0
+ && ah->ah_config.analog_shiftreg) {
+ udelay(100);
}
+
+ DO_DELAY(regWrites);
}
- for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode =
- (pCtlMode[ctlMode] == CTL_5GHT40)
- || (pCtlMode[ctlMode] == CTL_2GHT40);
- if (isHt40CtlMode)
- freq = centers.synth_center;
- else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
- freq = centers.ext_center;
- else
- freq = centers.ctl_center;
+ if (AR_SREV_9280(ah))
+ REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
- if (ar5416_get_eep_ver(ahp) == 14
- && ar5416_get_eep_rev(ahp) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ if (AR_SREV_9280(ah))
+ REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
- "EXT_ADDITIVE %d\n",
- ctlMode, numCtlModes, isHt40CtlMode,
- (pCtlMode[ctlMode] & EXT_ADDITIVE));
+ for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
+ u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
+ u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
- for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i];
- i++) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
- "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
- "chan %d\n",
- i, cfgCtl, pCtlMode[ctlMode],
- pEepData->ctlIndex[i], chan->channel);
-
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- pEepData->ctlIndex[i])
- ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((pEepData->
- ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
- rep = &(pEepData->ctlData[i]);
-
- twiceMinEdgePower =
- ath9k_hw_get_max_edge_power(freq,
- rep->
- ctlEdges
- [ar5416_get_ntxchains
- (tx_chainmask)
- - 1],
- IS_CHAN_2GHZ
- (chan));
-
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- " MATCH-EE_IDX %d: ch %d is2 %d "
- "2xMinEdge %d chainmask %d chains %d\n",
- i, freq, IS_CHAN_2GHZ(chan),
- twiceMinEdgePower, tx_chainmask,
- ar5416_get_ntxchains
- (tx_chainmask));
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
- twiceMaxEdgePower =
- min(twiceMaxEdgePower,
- twiceMinEdgePower);
- } else {
- twiceMaxEdgePower =
- twiceMinEdgePower;
- break;
- }
- }
+ REG_WRITE(ah, reg, val);
+
+ if (reg >= 0x7800 && reg < 0x78a0
+ && ah->ah_config.analog_shiftreg) {
+ udelay(100);
}
- minCtlPower = min(twiceMaxEdgePower, scaledPower);
+ DO_DELAY(regWrites);
+ }
+
+ ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- " SEL-Min ctlMode %d pCtlMode %d "
- "2xMaxEdge %d sP %d minCtlPwr %d\n",
- ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
- scaledPower, minCtlPower);
-
- switch (pCtlMode[ctlMode]) {
- case CTL_11B:
- for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
- i++) {
- targetPowerCck.tPow2x[i] =
- min(targetPowerCck.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11A:
- case CTL_11G:
- for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
- i++) {
- targetPowerOfdm.tPow2x[i] =
- min(targetPowerOfdm.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_5GHT20:
- case CTL_2GHT20:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
- i++) {
- targetPowerHt20.tPow2x[i] =
- min(targetPowerHt20.tPow2x[i],
- minCtlPower);
- }
- break;
- case CTL_11B_EXT:
- targetPowerCckExt.tPow2x[0] =
- min(targetPowerCckExt.tPow2x[0], minCtlPower);
- break;
- case CTL_11A_EXT:
- case CTL_11G_EXT:
- targetPowerOfdmExt.tPow2x[0] =
- min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
- break;
- case CTL_5GHT40:
- case CTL_2GHT40:
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
- i++) {
- targetPowerHt40.tPow2x[i] =
- min(targetPowerHt40.tPow2x[i],
- minCtlPower);
- }
- break;
- default:
- break;
- }
+ if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
+ REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
+ regWrites);
}
- ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
- ratesArray[rate18mb] = ratesArray[rate24mb] =
- targetPowerOfdm.tPow2x[0];
- ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
- ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
- ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
- ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
- for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
- ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
- if (IS_CHAN_2GHZ(chan)) {
- ratesArray[rate1l] = targetPowerCck.tPow2x[0];
- ratesArray[rate2s] = ratesArray[rate2l] =
- targetPowerCck.tPow2x[1];
- ratesArray[rate5_5s] = ratesArray[rate5_5l] =
- targetPowerCck.tPow2x[2];
- ;
- ratesArray[rate11s] = ratesArray[rate11l] =
- targetPowerCck.tPow2x[3];
- ;
+ ath9k_hw_override_ini(ah, chan);
+ ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_init_chain_masks(ah);
+
+ status = ath9k_hw_set_txpower(ah, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah,
+ chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit));
+ if (status != 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "error init'ing transmit power\n");
+ return -EIO;
}
- if (IS_CHAN_HT40(chan)) {
- for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
- ratesArray[rateHt40_0 + i] =
- targetPowerHt40.tPow2x[i];
- }
- ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
- ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
- ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
- if (IS_CHAN_2GHZ(chan)) {
- ratesArray[rateExtCck] =
- targetPowerCckExt.tPow2x[0];
- }
+
+ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "ar5416SetRfRegs failed\n");
+ return -EIO;
}
- return true;
+
+ return 0;
}
-static int
-ath9k_hw_set_txpower(struct ath_hal *ah,
- struct ar5416_eeprom *pEepData,
- struct ath9k_channel *chan,
- u16 cfgCtl,
- u8 twiceAntennaReduction,
- u8 twiceMaxRegulatoryPower,
- u8 powerLimit)
+/****************************************/
+/* Reset and Channel Switching Routines */
+/****************************************/
+
+static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
{
- struct modal_eep_header *pModal =
- &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
- int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
- u8 ht40PowerIncForPdadc = 2;
- int i;
+ u32 rfMode = 0;
- memset(ratesArray, 0, sizeof(ratesArray));
+ if (chan == NULL)
+ return;
- if ((pEepData->baseEepHeader.
- version & AR5416_EEP_VER_MINOR_MASK) >=
- AR5416_EEP_MINOR_VER_2) {
- ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
- }
+ rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+ ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
- if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan,
- &ratesArray[0], cfgCtl,
- twiceAntennaReduction,
- twiceMaxRegulatoryPower,
- powerLimit)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set "
- "tx power per rate table\n");
- return -EIO;
- }
+ if (!AR_SREV_9280_10_OR_LATER(ah))
+ rfMode |= (IS_CHAN_5GHZ(chan)) ?
+ AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
- if (!ath9k_hw_set_power_cal_table
- (ah, pEepData, chan, &txPowerIndexOffset)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set power table\n");
- return -EIO;
- }
+ if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
+ rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
- for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
- ratesArray[i] =
- (int16_t) (txPowerIndexOffset + ratesArray[i]);
- if (ratesArray[i] > AR5416_MAX_RATE_POWER)
- ratesArray[i] = AR5416_MAX_RATE_POWER;
- }
+ REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
- }
+static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
- ATH9K_POW_SM(ratesArray[rate18mb], 24)
- | ATH9K_POW_SM(ratesArray[rate12mb], 16)
- | ATH9K_POW_SM(ratesArray[rate9mb], 8)
- | ATH9K_POW_SM(ratesArray[rate6mb], 0)
- );
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
- ATH9K_POW_SM(ratesArray[rate54mb], 24)
- | ATH9K_POW_SM(ratesArray[rate48mb], 16)
- | ATH9K_POW_SM(ratesArray[rate36mb], 8)
- | ATH9K_POW_SM(ratesArray[rate24mb], 0)
- );
-
- if (IS_CHAN_2GHZ(chan)) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
- ATH9K_POW_SM(ratesArray[rate2s], 24)
- | ATH9K_POW_SM(ratesArray[rate2l], 16)
- | ATH9K_POW_SM(ratesArray[rateXr], 8)
- | ATH9K_POW_SM(ratesArray[rate1l], 0)
- );
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
- ATH9K_POW_SM(ratesArray[rate11s], 24)
- | ATH9K_POW_SM(ratesArray[rate11l], 16)
- | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
- | ATH9K_POW_SM(ratesArray[rate5_5l], 0)
- );
- }
+static inline void ath9k_hw_set_dma(struct ath_hal *ah)
+{
+ u32 regval;
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
- ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)
- );
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
- ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
- | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
- | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
- | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)
- );
+ regval = REG_READ(ah, AR_AHB_MODE);
+ REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
- if (IS_CHAN_HT40(chan)) {
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
- ATH9K_POW_SM(ratesArray[rateHt40_3] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_2] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_1] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_0] +
- ht40PowerIncForPdadc, 0)
- );
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
- ATH9K_POW_SM(ratesArray[rateHt40_7] +
- ht40PowerIncForPdadc, 24)
- | ATH9K_POW_SM(ratesArray[rateHt40_6] +
- ht40PowerIncForPdadc, 16)
- | ATH9K_POW_SM(ratesArray[rateHt40_5] +
- ht40PowerIncForPdadc, 8)
- | ATH9K_POW_SM(ratesArray[rateHt40_4] +
- ht40PowerIncForPdadc, 0)
- );
-
- REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
- ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
- | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
- | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
- | ATH9K_POW_SM(ratesArray[rateDupCck], 0)
- );
- }
+ regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
+ REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
- REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
- ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
- | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)
- );
+ REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
- i = rate6mb;
- if (IS_CHAN_HT40(chan))
- i = rateHt40_0;
- else if (IS_CHAN_HT20(chan))
- i = rateHt20_0;
+ regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
+ REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
- if (AR_SREV_9280_10_OR_LATER(ah))
- ah->ah_maxPowerLevel =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
- else
- ah->ah_maxPowerLevel = ratesArray[i];
+ REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
- return 0;
+ if (AR_SREV_9285(ah)) {
+ REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+ AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
+ } else {
+ REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+ AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+ }
+}
+
+static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
+{
+ u32 val;
+
+ val = REG_READ(ah, AR_STA_ID1);
+ val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
+ switch (opmode) {
+ case NL80211_IFTYPE_AP:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
+ | AR_STA_ID1_KSRCH_MODE);
+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
+ | AR_STA_ID1_KSRCH_MODE);
+ REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_MONITOR:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+ break;
+ }
}
static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
@@ -4632,9 +1501,8 @@ static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
*coef_exponent = coef_exp - 16;
}
-static void
-ath9k_hw_set_delta_slope(struct ath_hal *ah,
- struct ath9k_channel *chan)
+static void ath9k_hw_set_delta_slope(struct ath_hal *ah,
+ struct ath9k_channel *chan)
{
u32 coef_scaled, ds_coef_exp, ds_coef_man;
u32 clockMhzScaled = 0x64000000;
@@ -4667,8 +1535,243 @@ ath9k_hw_set_delta_slope(struct ath_hal *ah,
AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
}
-static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah,
- struct ath9k_channel *chan)
+static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
+{
+ u32 rst_flags;
+ u32 tmpReg;
+
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+ AR_RTC_FORCE_WAKE_ON_INT);
+
+ if (AR_SREV_9100(ah)) {
+ rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
+ AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
+ } else {
+ tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+ if (tmpReg &
+ (AR_INTR_SYNC_LOCAL_TIMEOUT |
+ AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+ REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+ } else {
+ REG_WRITE(ah, AR_RC, AR_RC_AHB);
+ }
+
+ rst_flags = AR_RTC_RC_MAC_WARM;
+ if (type == ATH9K_RESET_COLD)
+ rst_flags |= AR_RTC_RC_MAC_COLD;
+ }
+
+ REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+ udelay(50);
+
+ REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
+ if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "RTC stuck in MAC reset\n");
+ return false;
+ }
+
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, 0);
+
+ ath9k_hw_init_pll(ah, NULL);
+
+ if (AR_SREV_9100(ah))
+ udelay(50);
+
+ return true;
+}
+
+static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+ AR_RTC_FORCE_WAKE_ON_INT);
+
+ REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
+ REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+
+ if (!ath9k_hw_wait(ah,
+ AR_RTC_STATUS,
+ AR_RTC_STATUS_M,
+ AR_RTC_STATUS_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
+ return false;
+ }
+
+ ath9k_hw_read_revisions(ah);
+
+ return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+}
+
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type)
+{
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
+ switch (type) {
+ case ATH9K_RESET_POWER_ON:
+ return ath9k_hw_set_reset_power_on(ah);
+ break;
+ case ATH9K_RESET_WARM:
+ case ATH9K_RESET_COLD:
+ return ath9k_hw_set_reset(ah, type);
+ break;
+ default:
+ return false;
+ }
+}
+
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ u32 phymode;
+ u32 enableDacFifo = 0;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (AR_SREV_9285_10_OR_LATER(ah))
+ enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
+ AR_PHY_FC_ENABLE_DAC_FIFO);
+
+ phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+ | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
+
+ if (IS_CHAN_HT40(chan)) {
+ phymode |= AR_PHY_FC_DYN2040_EN;
+
+ if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+ (chan->chanmode == CHANNEL_G_HT40PLUS))
+ phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+ if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
+ phymode |= AR_PHY_FC_DYN2040_EXT_CH;
+ }
+ REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+ ath9k_hw_set11nmac2040(ah, macmode);
+
+ REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+ REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+}
+
+static bool ath9k_hw_chip_reset(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+ return false;
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+ return false;
+
+ ahp->ah_chipFullSleep = false;
+
+ ath9k_hw_init_pll(ah, chan);
+
+ ath9k_hw_set_rfmode(ah, chan);
+
+ return true;
+}
+
+static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "invalid channel %u/0x%x; not marked as "
+ "2GHz or 5GHz\n", chan->channel, chan->channelFlags);
+ return NULL;
+ }
+
+ if (!IS_CHAN_OFDM(chan) &&
+ !IS_CHAN_B(chan) &&
+ !IS_CHAN_HT20(chan) &&
+ !IS_CHAN_HT40(chan)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "invalid channel %u/0x%x; not marked as "
+ "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
+ chan->channel, chan->channelFlags);
+ return NULL;
+ }
+
+ return ath9k_regd_check_channel(ah, chan);
+}
+
+static bool ath9k_hw_channel_change(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ u32 synthDelay, qnum;
+
+ for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
+ if (ath9k_hw_numtxpending(ah, qnum)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "Transmit frames pending on queue %d\n", qnum);
+ return false;
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+ if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+ AR_PHY_RFBUS_GRANT_EN)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "Could not kill baseband RX\n");
+ return false;
+ }
+
+ ath9k_hw_set_regs(ah, chan, macmode);
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "failed to set channel\n");
+ return false;
+ }
+ } else {
+ if (!(ath9k_hw_set_channel(ah, chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "failed to set channel\n");
+ return false;
+ }
+ }
+
+ if (ath9k_hw_set_txpower(ah, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah, chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit)) != 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "error init'ing transmit power\n");
+ return false;
+ }
+
+ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+ if (IS_CHAN_B(chan))
+ synthDelay = (4 * synthDelay) / 22;
+ else
+ synthDelay /= 10;
+
+ udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+ REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+
+ if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+ ath9k_hw_set_delta_slope(ah, chan);
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ath9k_hw_9280_spur_mitigate(ah, chan);
+ else
+ ath9k_hw_spur_mitigate(ah, chan);
+
+ if (!chan->oneTimeCalsDone)
+ chan->oneTimeCalsDone = true;
+
+ return true;
+}
+
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
{
int bb_spur = AR_NO_SPUR;
int freq;
@@ -4918,8 +2021,7 @@ static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah,
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
}
-static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
- struct ath9k_channel *chan)
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
{
int bb_spur = AR_NO_SPUR;
int bin, cur_bin;
@@ -5120,752 +2222,11 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
}
-static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int rx_chainmask, tx_chainmask;
-
- rx_chainmask = ahp->ah_rxchainmask;
- tx_chainmask = ahp->ah_txchainmask;
-
- switch (rx_chainmask) {
- case 0x5:
- REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
- AR_PHY_SWAP_ALT_CHAIN);
- case 0x3:
- if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
- REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
- REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
- break;
- }
- case 0x1:
- case 0x2:
- if (!AR_SREV_9280(ah))
- break;
- case 0x7:
- REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
- REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
- break;
- default:
- break;
- }
-
- REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
- if (tx_chainmask == 0x5) {
- REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
- AR_PHY_SWAP_ALT_CHAIN);
- }
- if (AR_SREV_9100(ah))
- REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
- REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
-}
-
-static void ath9k_hw_set_addac(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- struct modal_eep_header *pModal;
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ar5416_eeprom *eep = &ahp->ah_eeprom;
- u8 biaslevel;
-
- if (ah->ah_macVersion != AR_SREV_VERSION_9160)
- return;
-
- if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
- return;
-
- pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
- if (pModal->xpaBiasLvl != 0xff) {
- biaslevel = pModal->xpaBiasLvl;
- } else {
-
- u16 resetFreqBin, freqBin, freqCount = 0;
- struct chan_centers centers;
-
- ath9k_hw_get_channel_centers(ah, chan, &centers);
-
- resetFreqBin =
- FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
- freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
- biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
-
- freqCount++;
-
- while (freqCount < 3) {
- if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
- break;
-
- freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
- if (resetFreqBin >= freqBin) {
- biaslevel =
- (u8) (pModal->
- xpaBiasLvlFreq[freqCount]
- >> 14);
- } else {
- break;
- }
- freqCount++;
- }
- }
-
- if (IS_CHAN_2GHZ(chan)) {
- INI_RA(&ahp->ah_iniAddac, 7, 1) =
- (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel
- << 3;
- } else {
- INI_RA(&ahp->ah_iniAddac, 6, 1) =
- (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel
- << 6;
- }
-}
-
-static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
-{
- if (ah->ah_curchan != NULL)
- return clks /
- CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
- else
- return clks / CLOCK_RATE[ATH9K_MODE_11B];
-}
-
-static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
-{
- struct ath9k_channel *chan = ah->ah_curchan;
-
- if (chan && IS_CHAN_HT40(chan))
- return ath9k_hw_mac_usec(ah, clks) / 2;
- else
- return ath9k_hw_mac_usec(ah, clks);
-}
-
-static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
-{
- if (ah->ah_curchan != NULL)
- return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
- ah->ah_curchan)];
- else
- return usecs * CLOCK_RATE[ATH9K_MODE_11B];
-}
-
-static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
-{
- struct ath9k_channel *chan = ah->ah_curchan;
-
- if (chan && IS_CHAN_HT40(chan))
- return ath9k_hw_mac_clks(ah, usecs) * 2;
- else
- return ath9k_hw_mac_clks(ah, usecs);
-}
-
-static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n",
- __func__, us);
- ahp->ah_acktimeout = (u32) -1;
- return false;
- } else {
- REG_RMW_FIELD(ah, AR_TIME_OUT,
- AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
- ahp->ah_acktimeout = us;
- return true;
- }
-}
-
-static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n",
- __func__, us);
- ahp->ah_ctstimeout = (u32) -1;
- return false;
- } else {
- REG_RMW_FIELD(ah, AR_TIME_OUT,
- AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
- ahp->ah_ctstimeout = us;
- return true;
- }
-}
-static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah,
- u32 tu)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (tu > 0xFFFF) {
- DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
- "%s: bad global tx timeout %u\n", __func__, tu);
- ahp->ah_globaltxtimeout = (u32) -1;
- return false;
- } else {
- REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
- ahp->ah_globaltxtimeout = tu;
- return true;
- }
-}
-
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n",
- __func__, us);
- ahp->ah_slottime = (u32) -1;
- return false;
- } else {
- REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
- ahp->ah_slottime = us;
- return true;
- }
-}
-
-static void ath9k_hw_init_user_settings(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n",
- __func__, ahp->ah_miscMode);
- if (ahp->ah_miscMode != 0)
- REG_WRITE(ah, AR_PCU_MISC,
- REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
- if (ahp->ah_slottime != (u32) -1)
- ath9k_hw_setslottime(ah, ahp->ah_slottime);
- if (ahp->ah_acktimeout != (u32) -1)
- ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
- if (ahp->ah_ctstimeout != (u32) -1)
- ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
- if (ahp->ah_globaltxtimeout != (u32) -1)
- ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
-}
-
-static int
-ath9k_hw_process_ini(struct ath_hal *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
-{
- int i, regWrites = 0;
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 modesIndex, freqIndex;
- int status;
-
- switch (chan->chanmode) {
- case CHANNEL_A:
- case CHANNEL_A_HT20:
- modesIndex = 1;
- freqIndex = 1;
- break;
- case CHANNEL_A_HT40PLUS:
- case CHANNEL_A_HT40MINUS:
- modesIndex = 2;
- freqIndex = 1;
- break;
- case CHANNEL_G:
- case CHANNEL_G_HT20:
- case CHANNEL_B:
- modesIndex = 4;
- freqIndex = 2;
- break;
- case CHANNEL_G_HT40PLUS:
- case CHANNEL_G_HT40MINUS:
- modesIndex = 3;
- freqIndex = 2;
- break;
-
- default:
- return -EINVAL;
- }
-
- REG_WRITE(ah, AR_PHY(0), 0x00000007);
-
- REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
-
- ath9k_hw_set_addac(ah, chan);
-
- if (AR_SREV_5416_V22_OR_LATER(ah)) {
- REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
- } else {
- struct ar5416IniArray temp;
- u32 addacSize =
- sizeof(u32) * ahp->ah_iniAddac.ia_rows *
- ahp->ah_iniAddac.ia_columns;
-
- memcpy(ahp->ah_addac5416_21,
- ahp->ah_iniAddac.ia_array, addacSize);
-
- (ahp->ah_addac5416_21)[31 *
- ahp->ah_iniAddac.ia_columns + 1] = 0;
-
- temp.ia_array = ahp->ah_addac5416_21;
- temp.ia_columns = ahp->ah_iniAddac.ia_columns;
- temp.ia_rows = ahp->ah_iniAddac.ia_rows;
- REG_WRITE_ARRAY(&temp, 1, regWrites);
- }
- REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
-
- for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
- u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
- u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
-
-#ifdef CONFIG_SLOW_ANT_DIV
- if (ah->ah_devid == AR9280_DEVID_PCI)
- val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg,
- val);
-#endif
-
- REG_WRITE(ah, reg, val);
-
- if (reg >= 0x7800 && reg < 0x78a0
- && ah->ah_config.analog_shiftreg) {
- udelay(100);
- }
-
- DO_DELAY(regWrites);
- }
-
- for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
- u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
- u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
-
- REG_WRITE(ah, reg, val);
-
- if (reg >= 0x7800 && reg < 0x78a0
- && ah->ah_config.analog_shiftreg) {
- udelay(100);
- }
-
- DO_DELAY(regWrites);
- }
-
- ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
-
- if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
- REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
- regWrites);
- }
-
- ath9k_hw_override_ini(ah, chan);
- ath9k_hw_set_regs(ah, chan, macmode);
- ath9k_hw_init_chain_masks(ah);
-
- status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
- ath9k_regd_get_ctl(ah, chan),
- ath9k_regd_get_antenna_allowed(ah,
- chan),
- chan->maxRegTxPower * 2,
- min((u32) MAX_RATE_POWER,
- (u32) ah->ah_powerLimit));
- if (status != 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
- "%s: error init'ing transmit power\n", __func__);
- return -EIO;
- }
-
- if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
- DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
- "%s: ar5416SetRfRegs failed\n", __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static void ath9k_hw_setup_calibration(struct ath_hal *ah,
- struct hal_cal_list *currCal)
-{
- REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
- AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
- currCal->calData->calCountMax);
-
- switch (currCal->calData->calType) {
- case IQ_MISMATCH_CAL:
- REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: starting IQ Mismatch Calibration\n",
- __func__);
- break;
- case ADC_GAIN_CAL:
- REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: starting ADC Gain Calibration\n", __func__);
- break;
- case ADC_DC_CAL:
- REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: starting ADC DC Calibration\n", __func__);
- break;
- case ADC_DC_INIT_CAL:
- REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: starting Init ADC DC Calibration\n",
- __func__);
- break;
- }
-
- REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
- AR_PHY_TIMING_CTRL4_DO_CAL);
-}
-
-static void ath9k_hw_reset_calibration(struct ath_hal *ah,
- struct hal_cal_list *currCal)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
-
- ath9k_hw_setup_calibration(ah, currCal);
-
- currCal->calState = CAL_RUNNING;
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- ahp->ah_Meas0.sign[i] = 0;
- ahp->ah_Meas1.sign[i] = 0;
- ahp->ah_Meas2.sign[i] = 0;
- ahp->ah_Meas3.sign[i] = 0;
- }
-
- ahp->ah_CalSamples = 0;
-}
-
-static void
-ath9k_hw_per_calibration(struct ath_hal *ah,
- struct ath9k_channel *ichan,
- u8 rxchainmask,
- struct hal_cal_list *currCal,
- bool *isCalDone)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- *isCalDone = false;
-
- if (currCal->calState == CAL_RUNNING) {
- if (!(REG_READ(ah,
- AR_PHY_TIMING_CTRL4(0)) &
- AR_PHY_TIMING_CTRL4_DO_CAL)) {
-
- currCal->calData->calCollect(ah);
-
- ahp->ah_CalSamples++;
-
- if (ahp->ah_CalSamples >=
- currCal->calData->calNumSamples) {
- int i, numChains = 0;
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- if (rxchainmask & (1 << i))
- numChains++;
- }
-
- currCal->calData->calPostProc(ah,
- numChains);
-
- ichan->CalValid |=
- currCal->calData->calType;
- currCal->calState = CAL_DONE;
- *isCalDone = true;
- } else {
- ath9k_hw_setup_calibration(ah, currCal);
- }
- }
- } else if (!(ichan->CalValid & currCal->calData->calType)) {
- ath9k_hw_reset_calibration(ah, currCal);
- }
-}
-
-static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah,
- int init_cal_count)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel ichan;
- bool isCalDone;
- struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
- const struct hal_percal_data *calData = currCal->calData;
- int i;
-
- if (currCal == NULL)
- return false;
-
- ichan.CalValid = 0;
-
- for (i = 0; i < init_cal_count; i++) {
- ath9k_hw_reset_calibration(ah, currCal);
-
- if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0),
- AR_PHY_TIMING_CTRL4_DO_CAL, 0)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: Cal %d failed to complete in 100ms.\n",
- __func__, calData->calType);
-
- ahp->ah_cal_list = ahp->ah_cal_list_last =
- ahp->ah_cal_list_curr = NULL;
- return false;
- }
-
- ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask,
- currCal, &isCalDone);
- if (!isCalDone) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: Not able to run Init Cal %d.\n",
- __func__, calData->calType);
- }
- if (currCal->calNext) {
- currCal = currCal->calNext;
- calData = currCal->calData;
- }
- }
-
- ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
- return true;
-}
-
-static bool
-ath9k_hw_channel_change(struct ath_hal *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
-{
- u32 synthDelay, qnum;
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
- if (ath9k_hw_numtxpending(ah, qnum)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: Transmit frames pending on queue %d\n",
- __func__, qnum);
- return false;
- }
- }
-
- REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
- if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
- AR_PHY_RFBUS_GRANT_EN)) {
- DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
- "%s: Could not kill baseband RX\n", __func__);
- return false;
- }
-
- ath9k_hw_set_regs(ah, chan, macmode);
-
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: failed to set channel\n", __func__);
- return false;
- }
- } else {
- if (!(ath9k_hw_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: failed to set channel\n", __func__);
- return false;
- }
- }
-
- if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
- ath9k_regd_get_ctl(ah, chan),
- ath9k_regd_get_antenna_allowed(ah, chan),
- chan->maxRegTxPower * 2,
- min((u32) MAX_RATE_POWER,
- (u32) ah->ah_powerLimit)) != 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: error init'ing transmit power\n", __func__);
- return false;
- }
-
- synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_CCK(chan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
-
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
-
- REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
-
- if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
- ath9k_hw_set_delta_slope(ah, chan);
-
- if (AR_SREV_9280_10_OR_LATER(ah))
- ath9k_hw_9280_spur_mitigate(ah, chan);
- else
- ath9k_hw_spur_mitigate(ah, chan);
-
- if (!chan->oneTimeCalsDone)
- chan->oneTimeCalsDone = true;
-
- return true;
-}
-
-static bool ath9k_hw_chip_reset(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
- return false;
-
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
- return false;
-
- ahp->ah_chipFullSleep = false;
-
- ath9k_hw_init_pll(ah, chan);
-
- ath9k_hw_set_rfmode(ah, chan);
-
- return true;
-}
-
-static inline void ath9k_hw_set_dma(struct ath_hal *ah)
-{
- u32 regval;
-
- regval = REG_READ(ah, AR_AHB_MODE);
- REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
-
- regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
- REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
-
- REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
-
- regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
- REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
-
- REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
-
- if (AR_SREV_9285(ah)) {
- REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
- AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
- } else {
- REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
- AR_PCU_TXBUF_CTRL_USABLE_SIZE);
- }
-}
-
-bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
-{
- REG_WRITE(ah, AR_CR, AR_CR_RXD);
- if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: dma failed to stop in 10ms\n"
- "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
- __func__,
- REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
- return false;
- } else {
- return true;
- }
-}
-
-void ath9k_hw_startpcureceive(struct ath_hal *ah)
-{
- REG_CLR_BIT(ah, AR_DIAG_SW,
- (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
- ath9k_enable_mib_counters(ah);
-
- ath9k_ani_reset(ah);
-}
-
-void ath9k_hw_stoppcurecv(struct ath_hal *ah)
-{
- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
-
- ath9k_hw_disable_mib_counters(ah);
-}
-
-static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
- struct ath9k_channel *chan,
- enum hal_cal_types calType)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- bool retval = false;
-
- switch (calType & ahp->ah_suppCals) {
- case IQ_MISMATCH_CAL:
- if (!IS_CHAN_B(chan))
- retval = true;
- break;
- case ADC_GAIN_CAL:
- case ADC_DC_CAL:
- if (!IS_CHAN_B(chan)
- && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
- retval = true;
- break;
- }
-
- return retval;
-}
-
-static bool ath9k_hw_init_cal(struct ath_hal *ah,
- struct ath9k_channel *chan)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *ichan =
- ath9k_regd_check_channel(ah, chan);
-
- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_CAL);
-
- if (!ath9k_hw_wait
- (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: offset calibration failed to complete in 1ms; "
- "noisy environment?\n", __func__);
- return false;
- }
-
- REG_WRITE(ah, AR_PHY_AGC_CONTROL,
- REG_READ(ah, AR_PHY_AGC_CONTROL) |
- AR_PHY_AGC_CONTROL_NF);
-
- ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr =
- NULL;
-
- if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
- if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
- INIT_CAL(&ahp->ah_adcGainCalData);
- INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: enabling ADC Gain Calibration.\n",
- __func__);
- }
- if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
- INIT_CAL(&ahp->ah_adcDcCalData);
- INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: enabling ADC DC Calibration.\n",
- __func__);
- }
- if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
- INIT_CAL(&ahp->ah_iqCalData);
- INSERT_CAL(ahp, &ahp->ah_iqCalData);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: enabling IQ Calibration.\n",
- __func__);
- }
-
- ahp->ah_cal_list_curr = ahp->ah_cal_list;
-
- if (ahp->ah_cal_list_curr)
- ath9k_hw_reset_calibration(ah,
- ahp->ah_cal_list_curr);
- }
-
- ichan->CalValid = 0;
-
- return true;
-}
-
-
-bool ath9k_hw_reset(struct ath_hal *ah,
- struct ath9k_channel *chan,
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
enum ath9k_ht_macmode macmode,
u8 txchainmask, u8 rxchainmask,
enum ath9k_ht_extprotspacing extprotspacing,
- bool bChannelChange,
- int *status)
+ bool bChannelChange, int *status)
{
u32 saveLedState;
struct ath_hal_5416 *ahp = AH5416(ah);
@@ -5886,8 +2247,8 @@ bool ath9k_hw_reset(struct ath_hal *ah,
if (ath9k_hw_check_chan(ah, chan) == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u/0x%x; no mapping\n",
- __func__, chan->channel, chan->channelFlags);
+ "invalid channel %u/0x%x; no mapping\n",
+ chan->channel, chan->channelFlags);
ecode = -EINVAL;
goto bad;
}
@@ -5907,8 +2268,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
((chan->channelFlags & CHANNEL_ALL) ==
(ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
(!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
- !IS_CHAN_A_5MHZ_SPACED(ah->
- ah_curchan)))) {
+ !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) {
if (ath9k_hw_channel_change(ah, chan, macmode)) {
ath9k_hw_loadnf(ah, ah->ah_curchan);
@@ -5930,8 +2290,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
ath9k_hw_mark_phy_inactive(ah);
if (!ath9k_hw_chip_reset(ah, chan)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
- __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n");
ecode = -EINVAL;
goto bad;
}
@@ -5965,7 +2324,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "%s: error setting board options\n", __func__);
+ "error setting board options\n");
ecode = -EIO;
goto bad;
}
@@ -6016,7 +2375,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
ath9k_hw_init_qos(ah);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
ath9k_enable_rfkill(ah);
#endif
@@ -6055,15 +2414,13 @@ bool ath9k_hw_reset(struct ath_hal *ah,
mask = REG_READ(ah, AR_CFG);
if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s CFG Byte Swap Set 0x%x\n", __func__,
- mask);
+ "CFG Byte Swap Set 0x%x\n", mask);
} else {
mask =
INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
REG_WRITE(ah, AR_CFG, mask);
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s Setting CFG 0x%x\n", __func__,
- REG_READ(ah, AR_CFG));
+ "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
#ifdef __BIG_ENDIAN
@@ -6078,693 +2435,402 @@ bad:
return false;
}
-bool ath9k_hw_phy_disable(struct ath_hal *ah)
-{
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
-}
-
-bool ath9k_hw_disable(struct ath_hal *ah)
-{
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
- return false;
-
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
-}
+/************************/
+/* Key Cache Management */
+/************************/
-bool
-ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
- u8 rxchainmask, bool longcal,
- bool *isCalDone)
+bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
- struct ath9k_channel *ichan =
- ath9k_regd_check_channel(ah, chan);
-
- *isCalDone = true;
+ u32 keyType;
- if (ichan == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u/0x%x; no mapping\n",
- __func__, chan->channel, chan->channelFlags);
+ if (entry >= ah->ah_caps.keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "entry %u out of range\n", entry);
return false;
}
- if (currCal &&
- (currCal->calState == CAL_RUNNING ||
- currCal->calState == CAL_WAITING)) {
- ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
- isCalDone);
- if (*isCalDone) {
- ahp->ah_cal_list_curr = currCal = currCal->calNext;
-
- if (currCal->calState == CAL_WAITING) {
- *isCalDone = false;
- ath9k_hw_reset_calibration(ah, currCal);
- }
- }
- }
+ keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
- if (longcal) {
- ath9k_hw_getnf(ah, ichan);
- ath9k_hw_loadnf(ah, ah->ah_curchan);
- ath9k_hw_start_nfcal(ah);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
- if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+ if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+ u16 micentry = entry + 64;
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
- chan->channelFlags |= CHANNEL_CW_INT;
- ichan->channelFlags &= ~CHANNEL_CW_INT;
- }
}
+ if (ah->ah_curchan == NULL)
+ return true;
+
return true;
}
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
+ u32 macHi, macLo;
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- ahp->ah_totalPowerMeasI[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
- ahp->ah_totalPowerMeasQ[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
- ahp->ah_totalIqCorrMeas[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
- ahp->ah_totalPowerMeasQ[i],
- ahp->ah_totalIqCorrMeas[i]);
+ if (entry >= ah->ah_caps.keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "entry %u out of range\n", entry);
+ return false;
}
-}
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
-
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- ahp->ah_totalAdcIOddPhase[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
- ahp->ah_totalAdcIEvenPhase[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
- ahp->ah_totalAdcQOddPhase[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- ahp->ah_totalAdcQEvenPhase[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ahp->ah_CalSamples, i,
- ahp->ah_totalAdcIOddPhase[i],
- ahp->ah_totalAdcIEvenPhase[i],
- ahp->ah_totalAdcQOddPhase[i],
- ahp->ah_totalAdcQEvenPhase[i]);
+ if (mac != NULL) {
+ macHi = (mac[5] << 8) | mac[4];
+ macLo = (mac[3] << 24) |
+ (mac[2] << 16) |
+ (mac[1] << 8) |
+ mac[0];
+ macLo >>= 1;
+ macLo |= (macHi & 1) << 31;
+ macHi >>= 1;
+ } else {
+ macLo = macHi = 0;
}
-}
-
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- int i;
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
- ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
- ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ahp->ah_CalSamples, i,
- ahp->ah_totalAdcDcOffsetIOddPhase[i],
- ahp->ah_totalAdcDcOffsetIEvenPhase[i],
- ahp->ah_totalAdcDcOffsetQOddPhase[i],
- ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
- }
+ return true;
}
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+ const struct ath9k_keyval *k,
+ const u8 *mac, int xorKey)
{
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u32 key0, key1, key2, key3, key4;
+ u32 keyType;
+ u32 xorMask = xorKey ?
+ (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
+ | ATH9K_KEY_XOR) : 0;
struct ath_hal_5416 *ahp = AH5416(ah);
- u32 powerMeasQ, powerMeasI, iqCorrMeas;
- u32 qCoffDenom, iCoffDenom;
- int32_t qCoff, iCoff;
- int iqCorrNeg, i;
-
- for (i = 0; i < numChains; i++) {
- powerMeasI = ahp->ah_totalPowerMeasI[i];
- powerMeasQ = ahp->ah_totalPowerMeasQ[i];
- iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting IQ Cal and Correction for Chain %d\n",
- i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Orignal: Chn %diq_corr_meas = 0x%08x\n",
- i, ahp->ah_totalIqCorrMeas[i]);
-
- iqCorrNeg = 0;
+ if (entry >= pCap->keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "entry %u out of range\n", entry);
+ return false;
+ }
- if (iqCorrMeas > 0x80000000) {
- iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
- iqCorrNeg = 1;
+ switch (k->kv_type) {
+ case ATH9K_CIPHER_AES_OCB:
+ keyType = AR_KEYTABLE_TYPE_AES;
+ break;
+ case ATH9K_CIPHER_AES_CCM:
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "AES-CCM not supported by mac rev 0x%x\n",
+ ah->ah_macRev);
+ return false;
}
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
- iqCorrNeg);
-
- iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
- qCoffDenom = powerMeasQ / 64;
-
- if (powerMeasQ != 0) {
-
- iCoff = iqCorrMeas / iCoffDenom;
- qCoff = powerMeasI / qCoffDenom - 64;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d iCoff = 0x%08x\n", i, iCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d qCoff = 0x%08x\n", i, qCoff);
-
-
- iCoff = iCoff & 0x3f;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
- if (iqCorrNeg == 0x0)
- iCoff = 0x40 - iCoff;
-
- if (qCoff > 15)
- qCoff = 15;
- else if (qCoff <= -16)
- qCoff = 16;
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
- i, iCoff, qCoff);
-
- REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
- iCoff);
- REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
- AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
- qCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction done for Chain %d\n",
- i);
+ keyType = AR_KEYTABLE_TYPE_CCM;
+ break;
+ case ATH9K_CIPHER_TKIP:
+ keyType = AR_KEYTABLE_TYPE_TKIP;
+ if (ATH9K_IS_MIC_ENABLED(ah)
+ && entry + 64 >= pCap->keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "entry %u inappropriate for TKIP\n", entry);
+ return false;
}
- }
-
- REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
- AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
-}
-
-static void
-ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset,
- qEvenMeasOffset;
- u32 qGainMismatch, iGainMismatch, val, i;
-
- for (i = 0; i < numChains; i++) {
- iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
- iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
- qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
- qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC Gain Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = 0x%08x\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = 0x%08x\n", i,
- qEvenMeasOffset);
-
- if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
- iGainMismatch =
- ((iEvenMeasOffset * 32) /
- iOddMeasOffset) & 0x3f;
- qGainMismatch =
- ((qOddMeasOffset * 32) /
- qEvenMeasOffset) & 0x3f;
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_i = 0x%08x\n", i,
- iGainMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_q = 0x%08x\n", i,
- qGainMismatch);
-
- val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
- val &= 0xfffff000;
- val |= (qGainMismatch) | (iGainMismatch << 6);
- REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC Gain Cal done for Chain %d\n", i);
+ break;
+ case ATH9K_CIPHER_WEP:
+ if (k->kv_len < LEN_WEP40) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "WEP key length %u too small\n", k->kv_len);
+ return false;
}
+ if (k->kv_len <= LEN_WEP40)
+ keyType = AR_KEYTABLE_TYPE_40;
+ else if (k->kv_len <= LEN_WEP104)
+ keyType = AR_KEYTABLE_TYPE_104;
+ else
+ keyType = AR_KEYTABLE_TYPE_128;
+ break;
+ case ATH9K_CIPHER_CLR:
+ keyType = AR_KEYTABLE_TYPE_CLR;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "cipher %u not supported\n", k->kv_type);
+ return false;
}
- REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
- REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
- AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
-}
-
-static void
-ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 iOddMeasOffset, iEvenMeasOffset, val, i;
- int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
- const struct hal_percal_data *calData =
- ahp->ah_cal_list_curr->calData;
- u32 numSamples =
- (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
-
- for (i = 0; i < numChains; i++) {
- iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
- iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
- qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
- qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC DC Offset Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = %d\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = %d\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = %d\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = %d\n", i,
- qEvenMeasOffset);
-
- iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
- numSamples) & 0x1ff;
- qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
- numSamples) & 0x1ff;
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
- iDcMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
- qDcMismatch);
-
- val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
- val &= 0xc0000fff;
- val |= (qDcMismatch << 12) | (iDcMismatch << 21);
- REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC DC Offset Cal done for Chain %d\n", i);
- }
-
- REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
- REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
- AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
-}
-
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *chan = ah->ah_curchan;
+ key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
+ key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
+ key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
+ key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
+ key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
+ if (k->kv_len <= LEN_WEP104)
+ key4 &= 0xff;
- ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
+ if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+ u16 micentry = entry + 64;
- if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
- ath9k_regd_get_ctl(ah, chan),
- ath9k_regd_get_antenna_allowed(ah,
- chan),
- chan->maxRegTxPower * 2,
- min((u32) MAX_RATE_POWER,
- (u32) ah->ah_powerLimit)) != 0)
- return false;
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+ (void) ath9k_hw_keysetmac(ah, entry, mac);
- return true;
-}
+ if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
+ u32 mic0, mic1, mic2, mic3, mic4;
-void
-ath9k_hw_get_channel_centers(struct ath_hal *ah,
- struct ath9k_channel *chan,
- struct chan_centers *centers)
-{
- int8_t extoff;
- struct ath_hal_5416 *ahp = AH5416(ah);
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+ mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
+ mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
+ mic4 = get_unaligned_le32(k->kv_txmic + 4);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
- if (!IS_CHAN_HT40(chan)) {
- centers->ctl_center = centers->ext_center =
- centers->synth_center = chan->channel;
- return;
- }
+ } else {
+ u32 mic0, mic2;
- if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
- (chan->chanmode == CHANNEL_G_HT40PLUS)) {
- centers->synth_center =
- chan->channel + HT40_CHANNEL_CENTER_SHIFT;
- extoff = 1;
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
+ }
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
} else {
- centers->synth_center =
- chan->channel - HT40_CHANNEL_CENTER_SHIFT;
- extoff = -1;
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+ (void) ath9k_hw_keysetmac(ah, entry, mac);
}
- centers->ctl_center = centers->synth_center - (extoff *
- HT40_CHANNEL_CENTER_SHIFT);
- centers->ext_center = centers->synth_center + (extoff *
- ((ahp->
- ah_extprotspacing
- ==
- ATH9K_HT_EXTPROTSPACING_20)
- ?
- HT40_CHANNEL_CENTER_SHIFT
- : 15));
+ if (ah->ah_curchan == NULL)
+ return true;
+ return true;
}
-void
-ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
- bool *isCalDone)
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *ichan =
- ath9k_regd_check_channel(ah, chan);
- struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-
- *isCalDone = true;
-
- if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
- return;
-
- if (currCal == NULL)
- return;
-
- if (ichan == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: invalid channel %u/0x%x; no mapping\n",
- __func__, chan->channel, chan->channelFlags);
- return;
- }
-
-
- if (currCal->calState != CAL_DONE) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: Calibration state incorrect, %d\n",
- __func__, currCal->calState);
- return;
+ if (entry < ah->ah_caps.keycache_size) {
+ u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
+ if (val & AR_KEYTABLE_VALID)
+ return true;
}
-
-
- if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
- return;
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%s: Resetting Cal %d state for channel %u/0x%x\n",
- __func__, currCal->calData->calType, chan->channel,
- chan->channelFlags);
-
- ichan->CalValid &= ~currCal->calData->calType;
- currCal->calState = CAL_WAITING;
-
- *isCalDone = false;
+ return false;
}
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
+/******************************/
+/* Power Management (Chipset) */
+/******************************/
+
+static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip) {
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
- memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
+ REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+ AR_RTC_RESET_EN);
+ }
}
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
+static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip) {
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
- return true;
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_ON_INT);
+ } else {
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ }
+ }
}
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
+static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
+ int setChip)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 val;
+ int i;
- memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
-}
+ 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) != true) {
+ return false;
+ }
+ }
+ if (AR_SREV_9100(ah))
+ REG_SET_BIT(ah, AR_RTC_RESET,
+ AR_RTC_RESET_EN);
-bool
-ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ udelay(50);
- memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
+ 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) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
+ return false;
+ }
+ }
- REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
- REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+ REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
return true;
}
-void
-ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
- u16 assocId)
+bool ath9k_hw_setpower(struct ath_hal *ah,
+ enum ath9k_power_mode mode)
{
struct ath_hal_5416 *ahp = AH5416(ah);
+ static const char *modes[] = {
+ "AWAKE",
+ "FULL-SLEEP",
+ "NETWORK SLEEP",
+ "UNDEFINED"
+ };
+ int status = true, setChip = true;
- memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
- ahp->ah_assocId = assocId;
-
- REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
- REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
- ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
-}
-
-u64 ath9k_hw_gettsf64(struct ath_hal *ah)
-{
- u64 tsf;
-
- tsf = REG_READ(ah, AR_TSF_U32);
- tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
- return tsf;
-}
-
-void ath9k_hw_reset_tsf(struct ath_hal *ah)
-{
- int count;
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
+ modes[ahp->ah_powerMode], modes[mode],
+ setChip ? "set chip " : "");
- count = 0;
- while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
- count++;
- if (count > 10) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n",
- __func__);
- break;
- }
- udelay(10);
+ switch (mode) {
+ case ATH9K_PM_AWAKE:
+ status = ath9k_hw_set_power_awake(ah, setChip);
+ break;
+ case ATH9K_PM_FULL_SLEEP:
+ ath9k_set_power_sleep(ah, setChip);
+ ahp->ah_chipFullSleep = true;
+ break;
+ case ATH9K_PM_NETWORK_SLEEP:
+ ath9k_set_power_network_sleep(ah, setChip);
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "Unknown power mode %u\n", mode);
+ return false;
}
- REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
-}
-
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
-{
- return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
-}
+ ahp->ah_powerMode = mode;
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
-{
- REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
+ return status;
}
-bool
-ath9k_hw_setantennaswitch(struct ath_hal *ah,
- enum ath9k_ant_setting settings,
- struct ath9k_channel *chan,
- u8 *tx_chainmask,
- u8 *rx_chainmask,
- u8 *antenna_cfgd)
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- static u8 tx_chainmask_cfg, rx_chainmask_cfg;
+ u8 i;
- if (AR_SREV_9280(ah)) {
- if (!tx_chainmask_cfg) {
+ if (ah->ah_isPciExpress != true)
+ return;
- tx_chainmask_cfg = *tx_chainmask;
- rx_chainmask_cfg = *rx_chainmask;
- }
+ if (ah->ah_config.pcie_powersave_enable == 2)
+ return;
- switch (settings) {
- case ATH9K_ANT_FIXED_A:
- *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
- *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
- *antenna_cfgd = true;
- break;
- case ATH9K_ANT_FIXED_B:
- if (ah->ah_caps.tx_chainmask >
- ATH9K_ANTENNA1_CHAINMASK) {
- *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
- }
- *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
- *antenna_cfgd = true;
- break;
- case ATH9K_ANT_VARIABLE:
- *tx_chainmask = tx_chainmask_cfg;
- *rx_chainmask = rx_chainmask_cfg;
- *antenna_cfgd = true;
- break;
- default:
- break;
+ if (restore)
+ return;
+
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
+ REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
+ INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
}
- } else {
- ahp->ah_diversityControl = settings;
- }
+ udelay(1000);
+ } else if (AR_SREV_9280(ah) &&
+ (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
- return true;
-}
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-void ath9k_hw_setopmode(struct ath_hal *ah)
-{
- ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
-}
+ if (ah->ah_config.pcie_clock_req)
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+ else
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-bool
-ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
- u32 capability, u32 *result)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
- switch (type) {
- case ATH9K_CAP_CIPHER:
- switch (capability) {
- case ATH9K_CIPHER_AES_CCM:
- case ATH9K_CIPHER_AES_OCB:
- case ATH9K_CIPHER_TKIP:
- case ATH9K_CIPHER_WEP:
- case ATH9K_CIPHER_MIC:
- case ATH9K_CIPHER_CLR:
- return true;
- default:
- return false;
- }
- case ATH9K_CAP_TKIP_MIC:
- switch (capability) {
- case 0:
- return true;
- case 1:
- return (ahp->ah_staId1Defaults &
- AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
- false;
- }
- case ATH9K_CAP_TKIP_SPLIT:
- return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
- false : true;
- case ATH9K_CAP_WME_TKIPMIC:
- return 0;
- case ATH9K_CAP_PHYCOUNTERS:
- return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
- case ATH9K_CAP_DIVERSITY:
- return (REG_READ(ah, AR_PHY_CCK_DETECT) &
- AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
- true : false;
- case ATH9K_CAP_PHYDIAG:
- return true;
- case ATH9K_CAP_MCAST_KEYSRCH:
- switch (capability) {
- case 0:
- return true;
- case 1:
- if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
- return false;
- } else {
- return (ahp->ah_staId1Defaults &
- AR_STA_ID1_MCAST_KSRCH) ? true :
- false;
- }
- }
- return false;
- case ATH9K_CAP_TSF_ADJUST:
- return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
- true : false;
- case ATH9K_CAP_RFSILENT:
- if (capability == 3)
- return false;
- case ATH9K_CAP_ANT_CFG_2GHZ:
- *result = pCap->num_antcfg_2ghz;
- return true;
- case ATH9K_CAP_ANT_CFG_5GHZ:
- *result = pCap->num_antcfg_5ghz;
- return true;
- case ATH9K_CAP_TXPOW:
- switch (capability) {
- case 0:
- return 0;
- case 1:
- *result = ah->ah_powerLimit;
- return 0;
- case 2:
- *result = ah->ah_maxPowerLevel;
- return 0;
- case 3:
- *result = ah->ah_tpScale;
- return 0;
- }
- return false;
- default:
- return false;
- }
-}
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-int
-ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_channel *chan = ah->ah_curchan;
- const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- u16 ant_config;
- u32 halNumAntConfig;
+ udelay(1000);
+ } else {
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+ }
- halNumAntConfig =
- IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap->
- num_antcfg_5ghz;
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- if (cfg < halNumAntConfig) {
- if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan,
- cfg, &ant_config)) {
- REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
- return 0;
- }
+ if (ah->ah_config.pcie_waen) {
+ REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+ } else {
+ if (AR_SREV_9285(ah))
+ REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
+ else if (AR_SREV_9280(ah))
+ REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
+ else
+ REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
}
- return -EINVAL;
}
+/**********************/
+/* Interrupt Handling */
+/**********************/
+
bool ath9k_hw_intrpend(struct ath_hal *ah)
{
u32 host_isr;
@@ -6791,6 +2857,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
u32 sync_cause = 0;
bool fatal_int = false;
+ struct ath_hal_5416 *ahp = AH5416(ah);
if (!AR_SREV_9100(ah)) {
if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
@@ -6800,9 +2867,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
}
}
- sync_cause =
- REG_READ(ah,
- AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
+ sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
+ AR_INTR_SYNC_DEFAULT;
*masked = 0;
@@ -6814,8 +2880,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
}
if (isr) {
- struct ath_hal_5416 *ahp = AH5416(ah);
-
if (isr & AR_ISR_BCNMISC) {
u32 isr2;
isr2 = REG_READ(ah, AR_ISR_S2);
@@ -6842,7 +2906,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
*masked = isr & ATH9K_INT_COMMON;
if (ahp->ah_intrMitigation) {
-
if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
*masked |= ATH9K_INT_RX;
}
@@ -6867,8 +2930,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
if (isr & AR_ISR_RXORN) {
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "%s: receive FIFO overrun interrupt\n",
- __func__);
+ "receive FIFO overrun interrupt\n");
}
if (!AR_SREV_9100(ah)) {
@@ -6881,8 +2943,10 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
*masked |= mask2;
}
+
if (AR_SREV_9100(ah))
return true;
+
if (sync_cause) {
fatal_int =
(sync_cause &
@@ -6892,32 +2956,29 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
if (fatal_int) {
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "%s: received PCI FATAL interrupt\n",
- __func__);
+ "received PCI FATAL interrupt\n");
}
if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "%s: received PCI PERR interrupt\n",
- __func__);
+ "received PCI PERR interrupt\n");
}
}
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n",
- __func__);
+ "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
REG_WRITE(ah, AR_RC, 0);
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n",
- __func__);
+ "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
}
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
}
+
return true;
}
@@ -6933,12 +2994,10 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__,
- omask, ints);
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
if (omask & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n",
- __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
if (!AR_SREV_9100(ah)) {
@@ -6993,8 +3052,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
mask2 |= AR_IMR_S2_CST;
}
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__,
- mask);
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
REG_WRITE(ah, AR_IMR, mask);
mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
AR_IMR_S2_DTIM |
@@ -7014,8 +3072,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
}
if (ints & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n",
- __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
@@ -7035,9 +3092,11 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
return omask;
}
-void
-ath9k_hw_beaconinit(struct ath_hal *ah,
- u32 next_beacon, u32 beacon_period)
+/*******************/
+/* Beacon Handling */
+/*******************/
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period)
{
struct ath_hal_5416 *ahp = AH5416(ah);
int flags = 0;
@@ -7045,14 +3104,14 @@ ath9k_hw_beaconinit(struct ath_hal *ah,
ahp->ah_beaconInterval = beacon_period;
switch (ah->ah_opmode) {
- case ATH9K_M_STA:
- case ATH9K_M_MONITOR:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_MONITOR:
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
flags |= AR_TBTT_TIMER_EN;
break;
- case ATH9K_M_IBSS:
+ case NL80211_IFTYPE_ADHOC:
REG_SET_BIT(ah, AR_TXCFG,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
REG_WRITE(ah, AR_NEXT_NDP_TIMER,
@@ -7060,7 +3119,7 @@ ath9k_hw_beaconinit(struct ath_hal *ah,
(ahp->ah_atimWindow ? ahp->
ah_atimWindow : 1)));
flags |= AR_NDP_TIMER_EN;
- case ATH9K_M_HOSTAP:
+ case NL80211_IFTYPE_AP:
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
TU_TO_USEC(next_beacon -
@@ -7073,6 +3132,12 @@ ath9k_hw_beaconinit(struct ath_hal *ah,
flags |=
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
+ "%s: unsupported opmode: %d\n",
+ __func__, ah->ah_opmode);
+ return;
+ break;
}
REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
@@ -7089,9 +3154,8 @@ ath9k_hw_beaconinit(struct ath_hal *ah,
REG_SET_BIT(ah, AR_TIMER_MODE, flags);
}
-void
-ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
- const struct ath9k_beacon_state *bs)
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+ const struct ath9k_beacon_state *bs)
{
u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
@@ -7120,14 +3184,10 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
else
nextTbtt = bs->bs_nexttbtt;
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__,
- bs->bs_nextdtim);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__,
- nextTbtt);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__,
- beaconintval);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__,
- dtimperiod);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
REG_WRITE(ah, AR_NEXT_DTIM,
TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
@@ -7154,1424 +3214,682 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
}
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
-{
- if (entry < ah->ah_caps.keycache_size) {
- u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
- if (val & AR_KEYTABLE_VALID)
- return true;
- }
- return false;
-}
+/*******************/
+/* HW Capabilities */
+/*******************/
-bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
{
- u32 keyType;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u16 capField = 0, eeval;
- if (entry >= ah->ah_caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: entry %u out of range\n", __func__, entry);
- return false;
- }
- keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
+ eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0);
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
- REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+ ah->ah_currentRD = eeval;
- if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
- u16 micentry = entry + 64;
+ eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1);
+ ah->ah_currentRDExt = eeval;
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+ capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP);
+ if (ah->ah_opmode != NL80211_IFTYPE_AP &&
+ ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+ if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
+ ah->ah_currentRD += 5;
+ else if (ah->ah_currentRD == 0x41)
+ ah->ah_currentRD = 0x43;
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "regdomain mapped to 0x%x\n", ah->ah_currentRD);
}
- if (ah->ah_curchan == NULL)
- return true;
-
- return true;
-}
-
-bool
-ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
- const u8 *mac)
-{
- u32 macHi, macLo;
-
- if (entry >= ah->ah_caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: entry %u out of range\n", __func__, entry);
- return false;
- }
+ eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE);
+ bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
- if (mac != NULL) {
- macHi = (mac[5] << 8) | mac[4];
- macLo = (mac[3] << 24) | (mac[2] << 16)
- | (mac[1] << 8) | mac[0];
- macLo >>= 1;
- macLo |= (macHi & 1) << 31;
- macHi >>= 1;
- } else {
- macLo = macHi = 0;
+ if (eeval & AR5416_OPFLAGS_11A) {
+ set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
+ if (ah->ah_config.ht_enable) {
+ if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
+ set_bit(ATH9K_MODE_11NA_HT20,
+ pCap->wireless_modes);
+ if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
+ set_bit(ATH9K_MODE_11NA_HT40PLUS,
+ pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11NA_HT40MINUS,
+ pCap->wireless_modes);
+ }
+ }
}
- REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
- return true;
-}
-
-bool
-ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
- const struct ath9k_keyval *k,
- const u8 *mac, int xorKey)
-{
- const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- u32 key0, key1, key2, key3, key4;
- u32 keyType;
- u32 xorMask = xorKey ?
- (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
- | ATH9K_KEY_XOR) : 0;
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (entry >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: entry %u out of range\n", __func__, entry);
- return false;
- }
- switch (k->kv_type) {
- case ATH9K_CIPHER_AES_OCB:
- keyType = AR_KEYTABLE_TYPE_AES;
- break;
- case ATH9K_CIPHER_AES_CCM:
- if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: AES-CCM not supported by "
- "mac rev 0x%x\n", __func__,
- ah->ah_macRev);
- return false;
- }
- keyType = AR_KEYTABLE_TYPE_CCM;
- break;
- case ATH9K_CIPHER_TKIP:
- keyType = AR_KEYTABLE_TYPE_TKIP;
- if (ATH9K_IS_MIC_ENABLED(ah)
- && entry + 64 >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: entry %u inappropriate for TKIP\n",
- __func__, entry);
- return false;
- }
- break;
- case ATH9K_CIPHER_WEP:
- if (k->kv_len < LEN_WEP40) {
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: WEP key length %u too small\n",
- __func__, k->kv_len);
- return false;
+ if (eeval & AR5416_OPFLAGS_11G) {
+ set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
+ if (ah->ah_config.ht_enable) {
+ if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
+ set_bit(ATH9K_MODE_11NG_HT20,
+ pCap->wireless_modes);
+ if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
+ set_bit(ATH9K_MODE_11NG_HT40PLUS,
+ pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11NG_HT40MINUS,
+ pCap->wireless_modes);
+ }
}
- if (k->kv_len <= LEN_WEP40)
- keyType = AR_KEYTABLE_TYPE_40;
- else if (k->kv_len <= LEN_WEP104)
- keyType = AR_KEYTABLE_TYPE_104;
- else
- keyType = AR_KEYTABLE_TYPE_128;
- break;
- case ATH9K_CIPHER_CLR:
- keyType = AR_KEYTABLE_TYPE_CLR;
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
- "%s: cipher %u not supported\n", __func__,
- k->kv_type);
- return false;
}
- key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
- key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
- key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
- key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
- key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
- if (k->kv_len <= LEN_WEP104)
- key4 &= 0xff;
-
- if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
- u16 micentry = entry + 64;
-
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
- (void) ath9k_hw_keysetmac(ah, entry, mac);
-
- if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
- u32 mic0, mic1, mic2, mic3, mic4;
-
- mic0 = get_unaligned_le32(k->kv_mic + 0);
- mic2 = get_unaligned_le32(k->kv_mic + 4);
- mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
- mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
- mic4 = get_unaligned_le32(k->kv_txmic + 4);
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
- AR_KEYTABLE_TYPE_CLR);
-
- } else {
- u32 mic0, mic2;
-
- mic0 = get_unaligned_le32(k->kv_mic + 0);
- mic2 = get_unaligned_le32(k->kv_mic + 4);
- REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
- AR_KEYTABLE_TYPE_CLR);
- }
- REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK);
+ if ((ah->ah_isPciExpress)
+ || (eeval & AR5416_OPFLAGS_11A)) {
+ pCap->rx_chainmask =
+ ath9k_hw_get_eeprom(ah, EEP_RX_MASK);
} else {
- REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
- REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
- REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
- REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
- REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
- REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-
- (void) ath9k_hw_keysetmac(ah, entry, mac);
+ pCap->rx_chainmask =
+ (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
}
- if (ah->ah_curchan == NULL)
- return true;
-
- return true;
-}
-
-bool
-ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- u32 txcfg, curLevel, newLevel;
- enum ath9k_int omask;
-
- if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
- return false;
-
- omask = ath9k_hw_set_interrupts(ah,
- ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
-
- txcfg = REG_READ(ah, AR_TXCFG);
- curLevel = MS(txcfg, AR_FTRIG);
- newLevel = curLevel;
- if (bIncTrigLevel) {
- if (curLevel < MAX_TX_FIFO_THRESHOLD)
- newLevel++;
- } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
- newLevel--;
- if (newLevel != curLevel)
- REG_WRITE(ah, AR_TXCFG,
- (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+ if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
+ ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
- ath9k_hw_set_interrupts(ah, omask);
+ pCap->low_2ghz_chan = 2312;
+ pCap->high_2ghz_chan = 2732;
- ah->ah_txTrigLevel = newLevel;
+ pCap->low_5ghz_chan = 4920;
+ pCap->high_5ghz_chan = 6100;
- return newLevel != curLevel;
-}
+ pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
-bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
- const struct ath9k_tx_queue_info *qinfo)
-{
- u32 cw;
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- struct ath9k_tx_queue_info *qi;
+ pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
- if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
- __func__, q);
- return false;
- }
+ pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
- qi = &ahp->ah_txq[q];
- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
- __func__);
- return false;
- }
+ if (ah->ah_config.ht_enable)
+ pCap->hw_caps |= ATH9K_HW_CAP_HT;
+ else
+ pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
+ pCap->hw_caps |= ATH9K_HW_CAP_GTT;
+ pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
+ pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
+ pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
- qi->tqi_ver = qinfo->tqi_ver;
- qi->tqi_subtype = qinfo->tqi_subtype;
- qi->tqi_qflags = qinfo->tqi_qflags;
- qi->tqi_priority = qinfo->tqi_priority;
- if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
- qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+ if (capField & AR_EEPROM_EEPCAP_MAXQCU)
+ pCap->total_queues =
+ MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
else
- qi->tqi_aifs = INIT_AIFS;
- if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
- cw = min(qinfo->tqi_cwmin, 1024U);
- qi->tqi_cwmin = 1;
- while (qi->tqi_cwmin < cw)
- qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
- } else
- qi->tqi_cwmin = qinfo->tqi_cwmin;
- if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
- cw = min(qinfo->tqi_cwmax, 1024U);
- qi->tqi_cwmax = 1;
- while (qi->tqi_cwmax < cw)
- qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
- } else
- qi->tqi_cwmax = INIT_CWMAX;
+ pCap->total_queues = ATH9K_NUM_TX_QUEUES;
- if (qinfo->tqi_shretry != 0)
- qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
- else
- qi->tqi_shretry = INIT_SH_RETRY;
- if (qinfo->tqi_lgretry != 0)
- qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+ if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
+ pCap->keycache_size =
+ 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
else
- qi->tqi_lgretry = INIT_LG_RETRY;
- qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
- qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
- qi->tqi_burstTime = qinfo->tqi_burstTime;
- qi->tqi_readyTime = qinfo->tqi_readyTime;
-
- switch (qinfo->tqi_subtype) {
- case ATH9K_WME_UPSD:
- if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
- qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
- break;
- default:
- break;
- }
- return true;
-}
+ pCap->keycache_size = AR_KEYTABLE_SIZE;
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
- struct ath9k_tx_queue_info *qinfo)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- struct ath9k_tx_queue_info *qi;
+ pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
+ pCap->num_mr_retries = 4;
+ pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
- if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
- __func__, q);
- return false;
- }
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ pCap->num_gpio_pins = AR928X_NUM_GPIO;
+ else
+ pCap->num_gpio_pins = AR_NUM_GPIO;
- qi = &ahp->ah_txq[q];
- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
- __func__);
- return false;
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ pCap->hw_caps |= ATH9K_HW_CAP_WOW;
+ pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+ } else {
+ pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
+ pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
}
- qinfo->tqi_qflags = qi->tqi_qflags;
- qinfo->tqi_ver = qi->tqi_ver;
- qinfo->tqi_subtype = qi->tqi_subtype;
- qinfo->tqi_qflags = qi->tqi_qflags;
- qinfo->tqi_priority = qi->tqi_priority;
- qinfo->tqi_aifs = qi->tqi_aifs;
- qinfo->tqi_cwmin = qi->tqi_cwmin;
- qinfo->tqi_cwmax = qi->tqi_cwmax;
- qinfo->tqi_shretry = qi->tqi_shretry;
- qinfo->tqi_lgretry = qi->tqi_lgretry;
- qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
- qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
- qinfo->tqi_burstTime = qi->tqi_burstTime;
- qinfo->tqi_readyTime = qi->tqi_readyTime;
+ if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
+ pCap->hw_caps |= ATH9K_HW_CAP_CST;
+ pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
+ } else {
+ pCap->rts_aggr_limit = (8 * 1024);
+ }
- return true;
-}
+ pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-int
-ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
- const struct ath9k_tx_queue_info *qinfo)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_tx_queue_info *qi;
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- int q;
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+ ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
+ if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
+ ah->ah_rfkill_gpio =
+ MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
+ ah->ah_rfkill_polarity =
+ MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
- switch (type) {
- case ATH9K_TX_QUEUE_BEACON:
- q = pCap->total_queues - 1;
- break;
- case ATH9K_TX_QUEUE_CAB:
- q = pCap->total_queues - 2;
- break;
- case ATH9K_TX_QUEUE_PSPOLL:
- q = 1;
- break;
- case ATH9K_TX_QUEUE_UAPSD:
- q = pCap->total_queues - 3;
- break;
- case ATH9K_TX_QUEUE_DATA:
- for (q = 0; q < pCap->total_queues; q++)
- if (ahp->ah_txq[q].tqi_type ==
- ATH9K_TX_QUEUE_INACTIVE)
- break;
- if (q == pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: no available tx queue\n", __func__);
- return -1;
- }
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
- __func__, type);
- return -1;
+ pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
}
+#endif
+
+ if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9280))
+ pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+ if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
+ pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
- qi = &ahp->ah_txq[q];
- if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: tx queue %u already active\n", __func__, q);
- return -1;
- }
- memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
- qi->tqi_type = type;
- if (qinfo == NULL) {
- qi->tqi_qflags =
- TXQ_FLAG_TXOKINT_ENABLE
- | TXQ_FLAG_TXERRINT_ENABLE
- | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
- qi->tqi_aifs = INIT_AIFS;
- qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
- qi->tqi_cwmax = INIT_CWMAX;
- qi->tqi_shretry = INIT_SH_RETRY;
- qi->tqi_lgretry = INIT_LG_RETRY;
- qi->tqi_physCompBuf = 0;
+ if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
+ pCap->reg_cap =
+ AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+ AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
+ AR_EEPROM_EEREGCAP_EN_KK_U2 |
+ AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
} else {
- qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
- (void) ath9k_hw_set_txq_props(ah, q, qinfo);
+ pCap->reg_cap =
+ AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+ AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
}
- return q;
-}
+ pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-static void
-ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
- struct ath9k_tx_queue_info *qi)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
+ pCap->num_antcfg_5ghz =
+ ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
+ pCap->num_antcfg_2ghz =
+ ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
- __func__, ahp->ah_txOkInterruptMask,
- ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
- ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
-
- REG_WRITE(ah, AR_IMR_S0,
- SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
- | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
- REG_WRITE(ah, AR_IMR_S1,
- SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
- | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
- REG_RMW_FIELD(ah, AR_IMR_S2,
- AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+ return true;
}
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+ u32 capability, u32 *result)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- struct ath9k_tx_queue_info *qi;
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
- __func__, q);
+ switch (type) {
+ case ATH9K_CAP_CIPHER:
+ switch (capability) {
+ case ATH9K_CIPHER_AES_CCM:
+ case ATH9K_CIPHER_AES_OCB:
+ case ATH9K_CIPHER_TKIP:
+ case ATH9K_CIPHER_WEP:
+ case ATH9K_CIPHER_MIC:
+ case ATH9K_CIPHER_CLR:
+ return true;
+ default:
+ return false;
+ }
+ case ATH9K_CAP_TKIP_MIC:
+ switch (capability) {
+ case 0:
+ return true;
+ case 1:
+ return (ahp->ah_staId1Defaults &
+ AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
+ false;
+ }
+ case ATH9K_CAP_TKIP_SPLIT:
+ return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
+ false : true;
+ case ATH9K_CAP_WME_TKIPMIC:
+ return 0;
+ case ATH9K_CAP_PHYCOUNTERS:
+ return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
+ case ATH9K_CAP_DIVERSITY:
+ return (REG_READ(ah, AR_PHY_CCK_DETECT) &
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
+ true : false;
+ case ATH9K_CAP_PHYDIAG:
+ return true;
+ case ATH9K_CAP_MCAST_KEYSRCH:
+ switch (capability) {
+ case 0:
+ return true;
+ case 1:
+ if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
+ return false;
+ } else {
+ return (ahp->ah_staId1Defaults &
+ AR_STA_ID1_MCAST_KSRCH) ? true :
+ false;
+ }
+ }
return false;
- }
- qi = &ahp->ah_txq[q];
- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
- __func__, q);
+ case ATH9K_CAP_TSF_ADJUST:
+ return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
+ true : false;
+ case ATH9K_CAP_RFSILENT:
+ if (capability == 3)
+ return false;
+ case ATH9K_CAP_ANT_CFG_2GHZ:
+ *result = pCap->num_antcfg_2ghz;
+ return true;
+ case ATH9K_CAP_ANT_CFG_5GHZ:
+ *result = pCap->num_antcfg_5ghz;
+ return true;
+ case ATH9K_CAP_TXPOW:
+ switch (capability) {
+ case 0:
+ return 0;
+ case 1:
+ *result = ah->ah_powerLimit;
+ return 0;
+ case 2:
+ *result = ah->ah_maxPowerLevel;
+ return 0;
+ case 3:
+ *result = ah->ah_tpScale;
+ return 0;
+ }
+ return false;
+ default:
return false;
}
-
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
- __func__, q);
-
- qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
- ahp->ah_txOkInterruptMask &= ~(1 << q);
- ahp->ah_txErrInterruptMask &= ~(1 << q);
- ahp->ah_txDescInterruptMask &= ~(1 << q);
- ahp->ah_txEolInterruptMask &= ~(1 << q);
- ahp->ah_txUrnInterruptMask &= ~(1 << q);
- ath9k_hw_set_txq_interrupts(ah, qi);
-
- return true;
}
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+ u32 capability, u32 setting, int *status)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
- struct ath9k_channel *chan = ah->ah_curchan;
- struct ath9k_tx_queue_info *qi;
- u32 cwMin, chanCwMin, value;
+ u32 v;
- if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
- __func__, q);
- return false;
- }
- qi = &ahp->ah_txq[q];
- if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
- __func__, q);
+ switch (type) {
+ case ATH9K_CAP_TKIP_MIC:
+ if (setting)
+ ahp->ah_staId1Defaults |=
+ AR_STA_ID1_CRPT_MIC_ENABLE;
+ else
+ ahp->ah_staId1Defaults &=
+ ~AR_STA_ID1_CRPT_MIC_ENABLE;
return true;
- }
-
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
-
- if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
- if (chan && IS_CHAN_B(chan))
- chanCwMin = INIT_CWMIN_11B;
+ case ATH9K_CAP_DIVERSITY:
+ v = REG_READ(ah, AR_PHY_CCK_DETECT);
+ if (setting)
+ v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
else
- chanCwMin = INIT_CWMIN;
-
- for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
- } else
- cwMin = qi->tqi_cwmin;
-
- REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN)
- | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
- | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
-
- REG_WRITE(ah, AR_DRETRY_LIMIT(q),
- SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
- | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
- | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
-
- REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
- REG_WRITE(ah, AR_DMISC(q),
- AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
-
- if (qi->tqi_cbrPeriod) {
- REG_WRITE(ah, AR_QCBRCFG(q),
- SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL)
- | SM(qi->tqi_cbrOverflowLimit,
- AR_Q_CBRCFG_OVF_THRESH));
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah,
- AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi->
- tqi_cbrOverflowLimit
- ?
- AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN
- :
- 0));
- }
- if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
- REG_WRITE(ah, AR_QRDYTIMECFG(q),
- SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
- AR_Q_RDYTIMECFG_EN);
- }
-
- REG_WRITE(ah, AR_DCHNTIME(q),
- SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
- (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
-
- if (qi->tqi_burstTime
- && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah,
- AR_QMISC(q)) |
- AR_Q_MISC_RDYTIME_EXP_POLICY);
-
- }
-
- if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- AR_D_MISC_POST_FR_BKOFF_DIS);
- }
- if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- AR_D_MISC_FRAG_BKOFF_EN);
- }
- switch (qi->tqi_type) {
- case ATH9K_TX_QUEUE_BEACON:
- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
- | AR_Q_MISC_FSP_DBA_GATED
- | AR_Q_MISC_BEACON_USE
- | AR_Q_MISC_CBR_INCR_DIS1);
-
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
- AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
- | AR_D_MISC_BEACON_USE
- | AR_D_MISC_POST_FR_BKOFF_DIS);
- break;
- case ATH9K_TX_QUEUE_CAB:
- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
- | AR_Q_MISC_FSP_DBA_GATED
- | AR_Q_MISC_CBR_INCR_DIS1
- | AR_Q_MISC_CBR_INCR_DIS0);
- value = (qi->tqi_readyTime
- - (ah->ah_config.sw_beacon_response_time -
- ah->ah_config.dma_beacon_response_time)
- -
- ah->ah_config.additional_swba_backoff) *
- 1024;
- REG_WRITE(ah, AR_QRDYTIMECFG(q),
- value | AR_Q_RDYTIMECFG_EN);
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
- AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
- break;
- case ATH9K_TX_QUEUE_PSPOLL:
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah,
- AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
- break;
- case ATH9K_TX_QUEUE_UAPSD:
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
- | AR_D_MISC_POST_FR_BKOFF_DIS);
- break;
+ v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+ return true;
+ case ATH9K_CAP_MCAST_KEYSRCH:
+ if (setting)
+ ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
+ else
+ ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
+ return true;
+ case ATH9K_CAP_TSF_ADJUST:
+ if (setting)
+ ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+ else
+ ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+ return true;
default:
- break;
- }
-
- if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
- AR_D_MISC_ARB_LOCKOUT_CNTRL) |
- AR_D_MISC_POST_FR_BKOFF_DIS);
+ return false;
}
-
- if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
- ahp->ah_txOkInterruptMask |= 1 << q;
- else
- ahp->ah_txOkInterruptMask &= ~(1 << q);
- if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
- ahp->ah_txErrInterruptMask |= 1 << q;
- else
- ahp->ah_txErrInterruptMask &= ~(1 << q);
- if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
- ahp->ah_txDescInterruptMask |= 1 << q;
- else
- ahp->ah_txDescInterruptMask &= ~(1 << q);
- if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
- ahp->ah_txEolInterruptMask |= 1 << q;
- else
- ahp->ah_txEolInterruptMask &= ~(1 << q);
- if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
- ahp->ah_txUrnInterruptMask |= 1 << q;
- else
- ahp->ah_txUrnInterruptMask &= ~(1 << q);
- ath9k_hw_set_txq_interrupts(ah, qi);
-
- return true;
}
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
- *txqs &= ahp->ah_intrTxqs;
- ahp->ah_intrTxqs &= ~(*txqs);
-}
+/****************************/
+/* GPIO / RFKILL / Antennae */
+/****************************/
-bool
-ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 segLen, bool firstSeg,
- bool lastSeg, const struct ath_desc *ds0)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- if (firstSeg) {
- ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
- } else if (lastSeg) {
- ads->ds_ctl0 = 0;
- ads->ds_ctl1 = segLen;
- ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
- ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
- } else {
- ads->ds_ctl0 = 0;
- ads->ds_ctl1 = segLen | AR_TxMore;
- ads->ds_ctl2 = 0;
- ads->ds_ctl3 = 0;
- }
- ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
- ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
- ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
- ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
- ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
- return true;
-}
-
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
+ u32 gpio, u32 type)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
+ int addr;
+ u32 gpio_shift, tmp;
- ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
- ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
- ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
- ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
- ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-}
+ if (gpio > 11)
+ addr = AR_GPIO_OUTPUT_MUX3;
+ else if (gpio > 5)
+ addr = AR_GPIO_OUTPUT_MUX2;
+ else
+ addr = AR_GPIO_OUTPUT_MUX1;
-int
-ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- if ((ads->ds_txstatus9 & AR_TxDone) == 0)
- return -EINPROGRESS;
-
- ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
- ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
- ds->ds_txstat.ts_status = 0;
- ds->ds_txstat.ts_flags = 0;
-
- if (ads->ds_txstatus1 & AR_ExcessiveRetries)
- ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
- if (ads->ds_txstatus1 & AR_Filtered)
- ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
- if (ads->ds_txstatus1 & AR_FIFOUnderrun)
- ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
- if (ads->ds_txstatus9 & AR_TxOpExceeded)
- ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
- if (ads->ds_txstatus1 & AR_TxTimerExpired)
- ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
- if (ads->ds_txstatus1 & AR_DescCfgErr)
- ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
- if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
- ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
- ath9k_hw_updatetxtriglevel(ah, true);
- }
- if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
- ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
- ath9k_hw_updatetxtriglevel(ah, true);
- }
- if (ads->ds_txstatus0 & AR_TxBaStatus) {
- ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
- ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
- ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
- }
+ gpio_shift = (gpio % 6) * 5;
- ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
- switch (ds->ds_txstat.ts_rateindex) {
- case 0:
- ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
- break;
- case 1:
- ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
- break;
- case 2:
- ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
- break;
- case 3:
- ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
- break;
+ if (AR_SREV_9280_20_OR_LATER(ah)
+ || (addr != AR_GPIO_OUTPUT_MUX1)) {
+ REG_RMW(ah, addr, (type << gpio_shift),
+ (0x1f << gpio_shift));
+ } else {
+ tmp = REG_READ(ah, addr);
+ tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+ tmp &= ~(0x1f << gpio_shift);
+ tmp |= (type << gpio_shift);
+ REG_WRITE(ah, addr, tmp);
}
-
- ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
- ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
- ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
- ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
- ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
- ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
- ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
- ds->ds_txstat.evm0 = ads->AR_TxEVM0;
- ds->ds_txstat.evm1 = ads->AR_TxEVM1;
- ds->ds_txstat.evm2 = ads->AR_TxEVM2;
- ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
- ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
- ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
- ds->ds_txstat.ts_antenna = 1;
-
- return 0;
}
-void
-ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
- u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- txPower += ahp->ah_txPowerIndexOffset;
- if (txPower > 63)
- txPower = 63;
-
- ads->ds_ctl0 = (pktLen & AR_FrameLen)
- | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
- | SM(txPower, AR_XmitPower)
- | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
- | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
- | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
- ads->ds_ctl1 =
- (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
- | SM(type, AR_FrameType)
- | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
- | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
- | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+ u32 gpio_shift;
- ads->ds_ctl6 = SM(keyType, AR_EncrType);
+ ASSERT(gpio < ah->ah_caps.num_gpio_pins);
- if (AR_SREV_9285(ah)) {
+ gpio_shift = gpio << 1;
- ads->ds_ctl8 = 0;
- ads->ds_ctl9 = 0;
- ads->ds_ctl10 = 0;
- ads->ds_ctl11 = 0;
- }
+ REG_RMW(ah,
+ AR_GPIO_OE_OUT,
+ (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+ (AR_GPIO_OE_OUT_DRV << gpio_shift));
}
-void
-ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
- struct ath_desc *lastds,
- u32 durUpdateEn, u32 rtsctsRate,
- u32 rtsctsDuration,
- struct ath9k_11n_rate_series series[],
- u32 nseries, u32 flags)
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
- struct ar5416_desc *last_ads = AR5416DESC(lastds);
- u32 ds_ctl0;
-
- (void) nseries;
- (void) rtsctsDuration;
-
- if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
- ds_ctl0 = ads->ds_ctl0;
-
- if (flags & ATH9K_TXDESC_RTSENA) {
- ds_ctl0 &= ~AR_CTSEnable;
- ds_ctl0 |= AR_RTSEnable;
- } else {
- ds_ctl0 &= ~AR_RTSEnable;
- ds_ctl0 |= AR_CTSEnable;
- }
+ if (gpio >= ah->ah_caps.num_gpio_pins)
+ return 0xffffffff;
- ads->ds_ctl0 = ds_ctl0;
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ return (MS
+ (REG_READ(ah, AR_GPIO_IN_OUT),
+ AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
} else {
- ads->ds_ctl0 =
- (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+ return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
+ AR_GPIO_BIT(gpio)) != 0;
}
-
- ads->ds_ctl2 = set11nTries(series, 0)
- | set11nTries(series, 1)
- | set11nTries(series, 2)
- | set11nTries(series, 3)
- | (durUpdateEn ? AR_DurUpdateEna : 0)
- | SM(0, AR_BurstDur);
-
- ads->ds_ctl3 = set11nRate(series, 0)
- | set11nRate(series, 1)
- | set11nRate(series, 2)
- | set11nRate(series, 3);
-
- ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
- | set11nPktDurRTSCTS(series, 1);
-
- ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
- | set11nPktDurRTSCTS(series, 3);
-
- ads->ds_ctl7 = set11nRateFlags(series, 0)
- | set11nRateFlags(series, 1)
- | set11nRateFlags(series, 2)
- | set11nRateFlags(series, 3)
- | SM(rtsctsRate, AR_RTSCTSRate);
- last_ads->ds_ctl2 = ads->ds_ctl2;
- last_ads->ds_ctl3 = ads->ds_ctl3;
}
-void
-ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
- u32 aggrLen)
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+ u32 ah_signal_type)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
- ads->ds_ctl6 &= ~AR_AggrLen;
- ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
-}
+ u32 gpio_shift;
-void
-ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
- u32 numDelims)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
- unsigned int ctl6;
+ ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
- ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+ gpio_shift = 2 * gpio;
- ctl6 = ads->ds_ctl6;
- ctl6 &= ~AR_PadDelim;
- ctl6 |= SM(numDelims, AR_PadDelim);
- ads->ds_ctl6 = ctl6;
+ REG_RMW(ah,
+ AR_GPIO_OE_OUT,
+ (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
+ (AR_GPIO_OE_OUT_DRV << gpio_shift));
}
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl1 |= AR_IsAggr;
- ads->ds_ctl1 &= ~AR_MoreAggr;
- ads->ds_ctl6 &= ~AR_PadDelim;
+ REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
+ AR_GPIO_BIT(gpio));
}
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+void ath9k_enable_rfkill(struct ath_hal *ah)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
- ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+ AR_GPIO_INPUT_MUX2_RFSILENT);
+
+ ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+ REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
}
+#endif
-void
-ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
- u32 burstDuration)
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u16 ant_config;
+ u32 halNumAntConfig;
- ads->ds_ctl2 &= ~AR_BurstDur;
- ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
-}
+ halNumAntConfig = IS_CHAN_2GHZ(chan) ?
+ pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz;
-void
-ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
- u32 vmf)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
+ if (cfg < halNumAntConfig) {
+ if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan,
+ cfg, &ant_config)) {
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+ return 0;
+ }
+ }
- if (vmf)
- ads->ds_ctl0 |= AR_VirtMoreFrag;
- else
- ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+ return -EINVAL;
}
-void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
{
- REG_WRITE(ah, AR_RXDP, rxdp);
+ return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
}
-void ath9k_hw_rxena(struct ath_hal *ah)
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
{
- REG_WRITE(ah, AR_CR, AR_CR_RXE);
+ REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
}
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
+ enum ath9k_ant_setting settings,
+ struct ath9k_channel *chan,
+ u8 *tx_chainmask,
+ u8 *rx_chainmask,
+ u8 *antenna_cfgd)
{
- if (set) {
-
- REG_SET_BIT(ah, AR_DIAG_SW,
- (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
- if (!ath9k_hw_wait
- (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
- u32 reg;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ static u8 tx_chainmask_cfg, rx_chainmask_cfg;
- REG_CLR_BIT(ah, AR_DIAG_SW,
- (AR_DIAG_RX_DIS |
- AR_DIAG_RX_ABORT));
+ if (AR_SREV_9280(ah)) {
+ if (!tx_chainmask_cfg) {
- reg = REG_READ(ah, AR_OBS_BUS_1);
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
- __func__, reg);
+ tx_chainmask_cfg = *tx_chainmask;
+ rx_chainmask_cfg = *rx_chainmask;
+ }
- return false;
+ switch (settings) {
+ case ATH9K_ANT_FIXED_A:
+ *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+ *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+ *antenna_cfgd = true;
+ break;
+ case ATH9K_ANT_FIXED_B:
+ if (ah->ah_caps.tx_chainmask >
+ ATH9K_ANTENNA1_CHAINMASK) {
+ *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+ }
+ *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+ *antenna_cfgd = true;
+ break;
+ case ATH9K_ANT_VARIABLE:
+ *tx_chainmask = tx_chainmask_cfg;
+ *rx_chainmask = rx_chainmask_cfg;
+ *antenna_cfgd = true;
+ break;
+ default:
+ break;
}
} else {
- REG_CLR_BIT(ah, AR_DIAG_SW,
- (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+ ahp->ah_diversityControl = settings;
}
return true;
}
-void
-ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
- u32 filter1)
-{
- REG_WRITE(ah, AR_MCAST_FIL0, filter0);
- REG_WRITE(ah, AR_MCAST_FIL1, filter1);
-}
+/*********************/
+/* General Operation */
+/*********************/
-bool
-ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 size, u32 flags)
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
{
- struct ar5416_desc *ads = AR5416DESC(ds);
- struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u32 bits = REG_READ(ah, AR_RX_FILTER);
+ u32 phybits = REG_READ(ah, AR_PHY_ERR);
- ads->ds_ctl1 = size & AR_BufLen;
- if (flags & ATH9K_RXDESC_INTREQ)
- ads->ds_ctl1 |= AR_RxIntrReq;
+ if (phybits & AR_PHY_ERR_RADAR)
+ bits |= ATH9K_RX_FILTER_PHYRADAR;
+ if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
+ bits |= ATH9K_RX_FILTER_PHYERR;
- ads->ds_rxstatus8 &= ~AR_RxDone;
- if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
- memset(&(ads->u), 0, sizeof(ads->u));
- return true;
+ return bits;
}
-int
-ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
- u32 pa, struct ath_desc *nds, u64 tsf)
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
{
- struct ar5416_desc ads;
- struct ar5416_desc *adsp = AR5416DESC(ds);
-
- if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
- return -EINPROGRESS;
-
- ads.u.rx = adsp->u.rx;
-
- ds->ds_rxstat.rs_status = 0;
- ds->ds_rxstat.rs_flags = 0;
+ u32 phybits;
- ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
- ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+ REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
+ phybits = 0;
+ if (bits & ATH9K_RX_FILTER_PHYRADAR)
+ phybits |= AR_PHY_ERR_RADAR;
+ if (bits & ATH9K_RX_FILTER_PHYERR)
+ phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+ REG_WRITE(ah, AR_PHY_ERR, phybits);
- ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
- ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
- ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
- ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
- ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
- ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
- ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
- if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
- ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+ if (phybits)
+ REG_WRITE(ah, AR_RXCFG,
+ REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
else
- ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
-
- ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
- ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
-
- ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
- ds->ds_rxstat.rs_moreaggr =
- (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
- ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
- ds->ds_rxstat.rs_flags =
- (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
- ds->ds_rxstat.rs_flags |=
- (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
-
- if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
- ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
- if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
- ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
- if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
- ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
-
- if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
-
- if (ads.ds_rxstatus8 & AR_CRCErr)
- ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
- else if (ads.ds_rxstatus8 & AR_PHYErr) {
- u32 phyerr;
-
- ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
- phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
- ds->ds_rxstat.rs_phyerr = phyerr;
- } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
- ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
- else if (ads.ds_rxstatus8 & AR_MichaelErr)
- ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
- }
-
- return 0;
+ REG_WRITE(ah, AR_RXCFG,
+ REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
}
-static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
- struct ath9k_rate_table *rt)
+bool ath9k_hw_phy_disable(struct ath_hal *ah)
{
- int i;
-
- if (rt->rateCodeToIndex[0] != 0)
- return;
- for (i = 0; i < 256; i++)
- rt->rateCodeToIndex[i] = (u8) -1;
- for (i = 0; i < rt->rateCount; i++) {
- u8 code = rt->info[i].rateCode;
- u8 cix = rt->info[i].controlRate;
-
- rt->rateCodeToIndex[code] = i;
- rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
-
- rt->info[i].lpAckDuration =
- ath9k_hw_computetxtime(ah, rt,
- WLAN_CTRL_FRAME_SIZE,
- cix,
- false);
- rt->info[i].spAckDuration =
- ath9k_hw_computetxtime(ah, rt,
- WLAN_CTRL_FRAME_SIZE,
- cix,
- true);
- }
+ return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
}
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
- u32 mode)
+bool ath9k_hw_disable(struct ath_hal *ah)
{
- struct ath9k_rate_table *rt;
- switch (mode) {
- case ATH9K_MODE_11A:
- rt = &ar5416_11a_table;
- break;
- case ATH9K_MODE_11B:
- rt = &ar5416_11b_table;
- break;
- case ATH9K_MODE_11G:
- rt = &ar5416_11g_table;
- break;
- case ATH9K_MODE_11NG_HT20:
- case ATH9K_MODE_11NG_HT40PLUS:
- case ATH9K_MODE_11NG_HT40MINUS:
- rt = &ar5416_11ng_table;
- break;
- case ATH9K_MODE_11NA_HT20:
- case ATH9K_MODE_11NA_HT40PLUS:
- case ATH9K_MODE_11NA_HT40MINUS:
- rt = &ar5416_11na_table;
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
- __func__, mode);
- return NULL;
- }
- ath9k_hw_setup_rate_table(ah, rt);
- return rt;
-}
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+ return false;
-static const char *ath9k_hw_devname(u16 devid)
-{
- switch (devid) {
- case AR5416_DEVID_PCI:
- case AR5416_DEVID_PCIE:
- return "Atheros 5416";
- case AR9160_DEVID_PCI:
- return "Atheros 9160";
- case AR9280_DEVID_PCI:
- case AR9280_DEVID_PCIE:
- return "Atheros 9280";
- }
- return NULL;
+ return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
}
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
{
- return vendorid == ATHEROS_VENDOR_ID ?
- ath9k_hw_devname(devid) : NULL;
-}
+ struct ath9k_channel *chan = ah->ah_curchan;
-struct ath_hal *ath9k_hw_attach(u16 devid,
- struct ath_softc *sc,
- void __iomem *mem,
- int *error)
-{
- struct ath_hal *ah = NULL;
+ ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
- switch (devid) {
- case AR5416_DEVID_PCI:
- case AR5416_DEVID_PCIE:
- case AR9160_DEVID_PCI:
- case AR9280_DEVID_PCI:
- case AR9280_DEVID_PCIE:
- ah = ath9k_hw_do_attach(devid, sc, mem, error);
- break;
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "devid=0x%x not supported.\n", devid);
- ah = NULL;
- *error = -ENXIO;
- break;
- }
+ if (ath9k_hw_set_txpower(ah, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah, chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit)) != 0)
+ return false;
- return ah;
+ return true;
}
-u16
-ath9k_hw_computetxtime(struct ath_hal *ah,
- const struct ath9k_rate_table *rates,
- u32 frameLen, u16 rateix,
- bool shortPreamble)
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
{
- u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
- u32 kbps;
-
- kbps = rates->info[rateix].rateKbps;
-
- if (kbps == 0)
- return 0;
- switch (rates->info[rateix].phy) {
-
- case PHY_CCK:
- phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
- if (shortPreamble && rates->info[rateix].shortPreamble)
- phyTime >>= 1;
- numBits = frameLen << 3;
- txTime = CCK_SIFS_TIME + phyTime
- + ((numBits * 1000) / kbps);
- break;
- case PHY_OFDM:
- if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
- bitsPerSymbol =
- (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
-
- numBits = OFDM_PLCP_BITS + (frameLen << 3);
- numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
- txTime = OFDM_SIFS_TIME_QUARTER
- + OFDM_PREAMBLE_TIME_QUARTER
- + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
- } else if (ah->ah_curchan &&
- IS_CHAN_HALF_RATE(ah->ah_curchan)) {
- bitsPerSymbol =
- (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
-
- numBits = OFDM_PLCP_BITS + (frameLen << 3);
- numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
- txTime = OFDM_SIFS_TIME_HALF +
- OFDM_PREAMBLE_TIME_HALF
- + (numSymbols * OFDM_SYMBOL_TIME_HALF);
- } else {
- bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
-
- numBits = OFDM_PLCP_BITS + (frameLen << 3);
- numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
- txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
- + (numSymbols * OFDM_SYMBOL_TIME);
- }
- break;
+ struct ath_hal_5416 *ahp = AH5416(ah);
- default:
- DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
- "%s: unknown phy %u (rate ix %u)\n", __func__,
- rates->info[rateix].phy, rateix);
- txTime = 0;
- break;
- }
- return txTime;
+ memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
}
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
{
- if (flags & CHANNEL_2GHZ) {
- if (freq == 2484)
- return 14;
- if (freq < 2484)
- return (freq - 2407) / 5;
- else
- return 15 + ((freq - 2512) / 20);
- } else if (flags & CHANNEL_5GHZ) {
- if (ath9k_regd_is_public_safety_sku(ah) &&
- IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
- return ((freq * 10) +
- (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
- } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
- return (freq - 4000) / 5;
- } else {
- return (freq - 5000) / 5;
- }
- } else {
- if (freq == 2484)
- return 14;
- if (freq < 2484)
- return (freq - 2407) / 5;
- if (freq < 5000) {
- if (ath9k_regd_is_public_safety_sku(ah)
- && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
- return ((freq * 10) +
- (((freq % 5) ==
- 2) ? 5 : 0) - 49400) / 5;
- } else if (freq > 4900) {
- return (freq - 4000) / 5;
- } else {
- return 15 + ((freq - 2512) / 20);
- }
- }
- return (freq - 5000) / 5;
- }
-}
+ struct ath_hal_5416 *ahp = AH5416(ah);
-/* We can tune this as we go by monitoring really low values */
-#define ATH9K_NF_TOO_LOW -60
+ memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * is incorrect and we should use the static NF value. Later we can try to
- * find out why they are reporting these values */
-static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
-{
- if (nf > ATH9K_NF_TOO_LOW) {
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "%s: noise floor value detected (%d) is "
- "lower than what we think is a "
- "reasonable value (%d)\n",
- __func__, nf, ATH9K_NF_TOO_LOW);
- return false;
- }
return true;
}
-s16
-ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+void ath9k_hw_setopmode(struct ath_hal *ah)
{
- struct ath9k_channel *ichan;
- s16 nf;
-
- ichan = ath9k_regd_check_channel(ah, chan);
- if (ichan == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
- "%s: invalid channel %u/0x%x; no mapping\n",
- __func__, chan->channel, chan->channelFlags);
- return ATH_DEFAULT_NOISE_FLOOR;
- }
- if (ichan->rawNoiseFloor == 0) {
- enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
- nf = NOISE_FLOOR[mode];
- } else
- nf = ichan->rawNoiseFloor;
-
- if (!ath9k_hw_nf_in_range(ah, nf))
- nf = ATH_DEFAULT_NOISE_FLOOR;
-
- return nf;
+ ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
}
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1)
{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- if (setting)
- ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
- else
- ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
- return true;
+ REG_WRITE(ah, AR_MCAST_FIL0, filter0);
+ REG_WRITE(ah, AR_MCAST_FIL1, filter1);
}
-bool ath9k_hw_phycounters(struct ath_hal *ah)
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
{
struct ath_hal_5416 *ahp = AH5416(ah);
- return ahp->ah_hasHwPhyCounters ? true : false;
+ memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
}
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
{
- return REG_READ(ah, AR_QTXDP(q));
-}
+ struct ath_hal_5416 *ahp = AH5416(ah);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
- u32 txdp)
-{
- REG_WRITE(ah, AR_QTXDP(q), txdp);
+ memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
+
+ REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
+ REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
return true;
}
-bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId)
{
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+ struct ath_hal_5416 *ahp = AH5416(ah);
- REG_WRITE(ah, AR_Q_TXE, 1 << q);
+ memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
+ ahp->ah_assocId = assocId;
- return true;
+ REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
+ REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
+ ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
}
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+u64 ath9k_hw_gettsf64(struct ath_hal *ah)
{
- u32 npend;
+ u64 tsf;
- npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
- if (npend == 0) {
+ tsf = REG_READ(ah, AR_TSF_U32);
+ tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
- if (REG_READ(ah, AR_Q_TXE) & (1 << q))
- npend = 1;
- }
- return npend;
+ return tsf;
}
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+void ath9k_hw_reset_tsf(struct ath_hal *ah)
{
- u32 wait;
-
- REG_WRITE(ah, AR_Q_TXD, 1 << q);
+ int count;
- for (wait = 1000; wait != 0; wait--) {
- if (ath9k_hw_numtxpending(ah, q) == 0)
+ count = 0;
+ while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+ count++;
+ if (count > 10) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
break;
- udelay(100);
+ }
+ udelay(10);
}
+ REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+}
- if (ath9k_hw_numtxpending(ah, q)) {
- u32 tsfLow, j;
-
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: Num of pending TX Frames %d on Q %d\n",
- __func__, ath9k_hw_numtxpending(ah, q), q);
-
- for (j = 0; j < 2; j++) {
- tsfLow = REG_READ(ah, AR_TSF_L32);
- REG_WRITE(ah, AR_QUIET2,
- SM(10, AR_QUIET2_QUIET_DUR));
- REG_WRITE(ah, AR_QUIET_PERIOD, 100);
- REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
- REG_SET_BIT(ah, AR_TIMER_MODE,
- AR_QUIET_TIMER_EN);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
- if ((REG_READ(ah, AR_TSF_L32) >> 10) ==
- (tsfLow >> 10)) {
- break;
- }
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: TSF have moved while trying to set "
- "quiet time TSF: 0x%08x\n",
- __func__, tsfLow);
- }
+ if (setting)
+ ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+ else
+ ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+ return true;
+}
- udelay(200);
- REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
- wait = 1000;
+ if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
+ ahp->ah_slottime = (u32) -1;
+ return false;
+ } else {
+ REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_slottime = us;
+ return true;
+ }
+}
- while (ath9k_hw_numtxpending(ah, q)) {
- if ((--wait) == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
- "%s: Failed to stop Tx DMA in 100 "
- "msec after killing last frame\n",
- __func__);
- break;
- }
- udelay(100);
- }
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
+{
+ u32 macmode;
- REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
- }
+ if (mode == ATH9K_HT_MACMODE_2040 &&
+ !ah->ah_config.cwm_ignore_extcca)
+ macmode = AR_2040_JOINED_RX_CLEAR;
+ else
+ macmode = 0;
- REG_WRITE(ah, AR_Q_TXD, 0);
- return wait != 0;
+ REG_WRITE(ah, AR_2040_MODE, macmode);
}
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 2113818ee93..91d8f594af8 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -415,6 +415,9 @@ struct ar5416Stats {
#define AR5416_EEP_MINOR_VER_3 0x3
#define AR5416_EEP_MINOR_VER_7 0x7
#define AR5416_EEP_MINOR_VER_9 0x9
+#define AR5416_EEP_MINOR_VER_16 0x10
+#define AR5416_EEP_MINOR_VER_17 0x11
+#define AR5416_EEP_MINOR_VER_19 0x13
#define AR5416_NUM_5G_CAL_PIERS 8
#define AR5416_NUM_2G_CAL_PIERS 4
@@ -436,6 +439,27 @@ struct ar5416Stats {
#define AR5416_MAX_CHAINS 3
#define AR5416_PWR_TABLE_OFFSET -5
+/* Rx gain type values */
+#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0
+#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1
+#define AR5416_EEP_RXGAIN_ORIG 2
+
+/* Tx gain type values */
+#define AR5416_EEP_TXGAIN_ORIGINAL 0
+#define AR5416_EEP_TXGAIN_HIGH_POWER 1
+
+#define AR5416_EEP4K_START_LOC 64
+#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3
+#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_CTLS 12
+#define AR5416_EEP4K_NUM_BAND_EDGES 4
+#define AR5416_EEP4K_NUM_PD_GAINS 2
+#define AR5416_EEP4K_PD_GAINS_IN_MASK 4
+#define AR5416_EEP4K_PD_GAIN_ICEPTS 5
+#define AR5416_EEP4K_MAX_CHAINS 1
+
enum eeprom_param {
EEP_NFTHRESH_5,
EEP_NFTHRESH_2,
@@ -454,6 +478,8 @@ enum eeprom_param {
EEP_MINOR_REV,
EEP_TX_MASK,
EEP_RX_MASK,
+ EEP_RXGAIN_TYPE,
+ EEP_TXGAIN_TYPE,
};
enum ar5416_rates {
@@ -469,6 +495,11 @@ enum ar5416_rates {
Ar5416RateSize
};
+enum ath9k_hal_freq_band {
+ ATH9K_HAL_FREQ_BAND_5GHZ = 0,
+ ATH9K_HAL_FREQ_BAND_2GHZ = 1
+};
+
struct base_eep_header {
u16 length;
u16 checksum;
@@ -485,9 +516,32 @@ struct base_eep_header {
u32 binBuildNumber;
u8 deviceType;
u8 pwdclkind;
- u8 futureBase[32];
+ u8 futureBase_1[2];
+ u8 rxGainType;
+ u8 futureBase_2[3];
+ u8 txGainType;
+ u8 futureBase_3[25];
+} __packed;
+
+struct base_eep_header_4k {
+ u16 length;
+ u16 checksum;
+ u16 version;
+ u8 opCapFlags;
+ u8 eepMisc;
+ u16 regDmn[2];
+ u8 macAddr[6];
+ u8 rxMask;
+ u8 txMask;
+ u16 rfSilent;
+ u16 blueToothOptions;
+ u16 deviceCap;
+ u32 binBuildNumber;
+ u8 deviceType;
+ u8 futureBase[1];
} __packed;
+
struct spur_chan {
u16 spurChan;
u8 spurRangeLow;
@@ -540,11 +594,58 @@ struct modal_eep_header {
struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
} __packed;
+struct modal_eep_4k_header {
+ u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+ u32 antCtrlCommon;
+ u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 adcDesiredSize;
+ u8 pgaDesiredSize;
+ u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
+ u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
+ u8 pdGainOverlap;
+ u8 ob_01;
+ u8 db1_01;
+ u8 xpaBiasLvl;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
+ u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
+ u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
+ u8 db2_01;
+ u8 version;
+ u16 ob_234;
+ u16 db1_234;
+ u16 db2_234;
+ u8 futureModal[4];
+
+ struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+} __packed;
+
+
struct cal_data_per_freq {
u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
} __packed;
+struct cal_data_per_freq_4k {
+ u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS];
+} __packed;
+
struct cal_target_power_leg {
u8 bChannel;
u8 tPow2x[4];
@@ -555,6 +656,7 @@ struct cal_target_power_ht {
u8 tPow2x[8];
} __packed;
+
#ifdef __BIG_ENDIAN_BITFIELD
struct cal_ctl_edges {
u8 bChannel;
@@ -569,10 +671,15 @@ struct cal_ctl_edges {
struct cal_ctl_data {
struct cal_ctl_edges
- ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+ ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
} __packed;
-struct ar5416_eeprom {
+struct cal_ctl_data_4k {
+ struct cal_ctl_edges
+ ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
+} __packed;
+
+struct ar5416_eeprom_def {
struct base_eep_header baseEepHeader;
u8 custData[64];
struct modal_eep_header modalHeader[2];
@@ -601,6 +708,26 @@ struct ar5416_eeprom {
u8 padding;
} __packed;
+struct ar5416_eeprom_4k {
+ struct base_eep_header_4k baseEepHeader;
+ u8 custData[20];
+ struct modal_eep_4k_header modalHeader;
+ u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
+ struct cal_data_per_freq_4k
+ calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
+ struct cal_target_power_leg
+ calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
+ struct cal_target_power_leg
+ calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
+ u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
+ struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
+ u8 padding;
+} __packed;
+
struct ar5416IniArray {
u32 *ia_array;
u32 ia_rows;
@@ -668,9 +795,22 @@ struct hal_cal_list {
struct hal_cal_list *calNext;
};
+/*
+ * Enum to indentify the eeprom mappings
+ */
+enum hal_eep_map {
+ EEP_MAP_DEFAULT = 0x0,
+ EEP_MAP_4KBITS,
+ EEP_MAP_MAX
+};
+
+
struct ath_hal_5416 {
struct ath_hal ah;
- struct ar5416_eeprom ah_eeprom;
+ union {
+ struct ar5416_eeprom_def def;
+ struct ar5416_eeprom_4k map4k;
+ } ah_eeprom;
struct ar5416Stats ah_stats;
struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
void __iomem *ah_cal_mem;
@@ -792,6 +932,10 @@ struct ath_hal_5416 {
struct ar5416IniArray ah_iniAddac;
struct ar5416IniArray ah_iniPcieSerdes;
struct ar5416IniArray ah_iniModesAdditional;
+ struct ar5416IniArray ah_iniModesRxGain;
+ struct ar5416IniArray ah_iniModesTxGain;
+ /* To indicate EEPROM mapping used */
+ enum hal_eep_map ah_eep_map;
};
#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
@@ -833,13 +977,20 @@ struct ath_hal_5416 {
(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
#define AR5416_EEPROM_MAX 0xae0
#define ar5416_get_eep_ver(_ahp) \
- (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF)
+ (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF)
#define ar5416_get_eep_rev(_ahp) \
- (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF)
+ (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF)
#define ar5416_get_ntxchains(_txchainmask) \
(((_txchainmask >> 2) & 1) + \
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
+/* EEPROM 4K bit map definations */
+#define ar5416_get_eep4k_ver(_ahp) \
+ (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF)
+#define ar5416_get_eep4k_rev(_ahp) \
+ (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF)
+
+
#ifdef __BIG_ENDIAN
#define AR5416_EEPROM_MAGIC 0x5aa5
#else
@@ -923,7 +1074,7 @@ struct ath_hal_5416 {
#define OFDM_PLCP_BITS_QUARTER 22
#define OFDM_SYMBOL_TIME_QUARTER 16
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
enum eeprom_param param);
#endif
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h
index 3dd3815940a..f3cfa16525e 100644
--- a/drivers/net/wireless/ath9k/initvals.h
+++ b/drivers/net/wireless/ath9k/initvals.h
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* AR5416 to Fowl ar5146.ini */
static const u32 ar5416Modes_9100[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de },
+ { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
{ 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
- { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
@@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
+ { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 },
@@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = {
{ 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
+ { 0x00008338, 0x00070000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 },
@@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = {
{0x000098c4, 0x00000000 },
};
+/* ar5416 - howl ar5416_howl.ini */
static const u32 ar5416Modes[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = {
{ 0x0000994c, 0x00020028 },
{ 0x0000c95c, 0x004b6a8e },
{ 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb514 },
+ { 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = {
{0x000098cc, 0x00000000 },
};
-
+/* AR5416 9160 Sowl ar5416_sowl.ini */
static const u32 ar5416Modes_9160[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+ { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
{ 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
{ 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+ { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
{ 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
{ 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
@@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00008134, 0x00000000 },
{ 0x00008138, 0x00000000 },
{ 0x0000813c, 0x00000000 },
- { 0x00008144, 0x00000000 },
+ { 0x00008144, 0xffffffff },
{ 0x00008168, 0x00000000 },
{ 0x0000816c, 0x00000000 },
{ 0x00008170, 0x32143320 },
@@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000832c, 0x00000007 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
- { 0x00008338, 0x00000000 },
+ { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
{ 0x00009808, 0x00000000 },
@@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x00009958, 0x2108ecff },
{ 0x00009940, 0x00750604 },
{ 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
@@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a244, 0x00007bb6 },
{ 0x0000a248, 0x0fff3ffc },
{ 0x0000a24c, 0x00000001 },
- { 0x0000a250, 0x0000a000 },
+ { 0x0000a250, 0x0000e000 },
{ 0x0000a254, 0x00000000 },
{ 0x0000a258, 0x0cc75380 },
{ 0x0000a25c, 0x0f0f0f01 },
@@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = {
{ 0x0000a34c, 0x3fffffff },
{ 0x0000a350, 0x3fffffff },
{ 0x0000a354, 0x0003ffff },
- { 0x0000a358, 0x79a8aa33 },
+ { 0x0000a358, 0x79bfaa03 },
{ 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 },
@@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = {
};
static const u32 ar5416Bank6_9160[][3] = {
-
{ 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 },
{ 0x0000989c, 0x00000000, 0x00000000 },
@@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = {
{ 0x000098cc, 0x0000000e },
};
-
static u32 ar5416Addac_9160[][2] = {
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
@@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = {
{0x000098cc, 0x00000000 },
};
-
static u32 ar5416Addac_91601_1[][2] = {
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
@@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = {
{0x000098cc, 0x00000000 },
};
-
-
+/* XXX 9280 1 */
static const u32 ar9280Modes_9280[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = {
{ 0x00007898, 0x2a850160 },
};
-
-
-
+/* XXX 9280 2 */
static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
- { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e },
+ { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
- { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
- { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
- { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
- { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
- { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
{ 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
- { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
{ 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
- { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
- { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+ { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
{ 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
- { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c },
- { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
{ 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
@@ -2587,6 +2581,516 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
+};
+
+static const u32 ar9280Common_9280_2[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008120, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x00581043 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafa68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x01002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x2108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x00009968, 0x000003ce },
+ { 0x00009970, 0x190fb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x00009980, 0x00000000 },
+ { 0x00009984, 0x00000000 },
+ { 0x00009988, 0x00000000 },
+ { 0x0000998c, 0x00000000 },
+ { 0x00009990, 0x00000000 },
+ { 0x00009994, 0x00000000 },
+ { 0x00009998, 0x00000000 },
+ { 0x0000999c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x006f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a208, 0x803e4788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f7180 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c88000 },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x00007800, 0x00040000 },
+ { 0x00007804, 0xdb005012 },
+ { 0x00007808, 0x04924914 },
+ { 0x0000780c, 0x21084210 },
+ { 0x00007810, 0x6d801300 },
+ { 0x00007818, 0x07e41000 },
+ { 0x0000781c, 0x00392000 },
+ { 0x00007820, 0x92592480 },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb005012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x6d801300 },
+ { 0x0000783c, 0x07e40000 },
+ { 0x00007840, 0x00392000 },
+ { 0x00007844, 0x92592480 },
+ { 0x00007848, 0x00100000 },
+ { 0x0000784c, 0x773f0567 },
+ { 0x00007850, 0x54214514 },
+ { 0x00007854, 0x12035828 },
+ { 0x00007858, 0x9259269a },
+ { 0x00007860, 0x52802000 },
+ { 0x00007864, 0x0a8e370e },
+ { 0x00007868, 0xc0102850 },
+ { 0x0000786c, 0x812d4000 },
+ { 0x00007870, 0x807ec400 },
+ { 0x00007874, 0x001b6db0 },
+ { 0x00007878, 0x00376b63 },
+ { 0x0000787c, 0x06db6db6 },
+ { 0x00007880, 0x006d8000 },
+ { 0x00007884, 0xffeffffe },
+ { 0x00007888, 0xffeffffe },
+ { 0x0000788c, 0x00010000 },
+ { 0x00007890, 0x02060aeb },
+ { 0x00007898, 0x2a850160 },
+};
+
+static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
+ { 0x00001030, 0x00000268, 0x000004d0 },
+ { 0x00001070, 0x0000018c, 0x00000318 },
+ { 0x000010b0, 0x00000fd0, 0x00001fa0 },
+ { 0x00008014, 0x044c044c, 0x08980898 },
+ { 0x0000801c, 0x148ec02b, 0x148ec057 },
+ { 0x00008318, 0x000044c0, 0x00008980 },
+ { 0x00009820, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000f0f, 0x00000f0f },
+ { 0x00009828, 0x0b020001, 0x0b020001 },
+ { 0x00009834, 0x00000f0f, 0x00000f0f },
+ { 0x00009844, 0x03721821, 0x03721821 },
+ { 0x00009914, 0x00000898, 0x00001130 },
+ { 0x00009918, 0x0000000b, 0x00000016 },
+ { 0x00009944, 0xdfbc1210, 0xdfbc1210 },
+};
+
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
+ { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 },
+};
+
+static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
{ 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
{ 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
{ 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
@@ -2715,14 +3219,172 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
{ 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
{ 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
- { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
- { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
- { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
- { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
- { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a },
- { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
- { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 },
- { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+};
+
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
+ { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b },
+ { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a },
+};
+
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
+ { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
+ { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 },
+ { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 },
+ { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 },
+ { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a },
+ { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 },
+ { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+ { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 },
+ { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 },
+ { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 },
+ { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 },
+ { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 },
+ { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 },
+ { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c },
+ { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a },
+ { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 },
+ { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 },
+ { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 },
+ { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 },
+ { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 },
+ { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+ { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff },
+ { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
+};
+
+static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
{ 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
@@ -2745,14 +3407,363 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
{ 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
{ 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+ { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+ { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff },
+ { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
+};
+
+static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+/* AR9285 */
+static const u_int32_t ar9285Modes_9285[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e },
+ { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+ { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c },
+ { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 },
+ { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 },
+ { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
{ 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
- { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
};
-static const u32 ar9280Common_9280_2[][2] = {
+static const u_int32_t ar9285Common_9285[][2] = {
{ 0x0000000c, 0x00000000 },
- { 0x00000030, 0x00020015 },
+ { 0x00000030, 0x00020045 },
{ 0x00000034, 0x00000005 },
{ 0x00000040, 0x00000000 },
{ 0x00000044, 0x00000008 },
@@ -2837,7 +3848,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00004024, 0x0000001f },
{ 0x00004060, 0x00000000 },
{ 0x00004064, 0x00000000 },
- { 0x00007010, 0x00000033 },
+ { 0x00007010, 0x00000031 },
{ 0x00007034, 0x00000002 },
{ 0x00007038, 0x000004c2 },
{ 0x00008004, 0x00000000 },
@@ -2847,7 +3858,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008020, 0x00000000 },
{ 0x00008038, 0x00000000 },
{ 0x0000803c, 0x00000000 },
- { 0x00008048, 0x40000000 },
+ { 0x00008048, 0x00000000 },
{ 0x00008054, 0x00000000 },
{ 0x00008058, 0x00000000 },
{ 0x0000805c, 0x000fc78f },
@@ -2923,6 +3934,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -2936,15 +3948,15 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008300, 0x00000040 },
{ 0x00008314, 0x00000000 },
{ 0x00008328, 0x00000000 },
- { 0x0000832c, 0x00000007 },
+ { 0x0000832c, 0x00000001 },
{ 0x00008330, 0x00000302 },
{ 0x00008334, 0x00000e00 },
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
- { 0x00008340, 0x000107ff },
+ { 0x00008340, 0x00010380 },
{ 0x00008344, 0x00581043 },
{ 0x00009808, 0x00000000 },
- { 0x0000980c, 0xafa68e30 },
+ { 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
{ 0x00009814, 0x9c0a9f6b },
{ 0x0000981c, 0x00000000 },
@@ -2952,7 +3964,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009830, 0x00000000 },
{ 0x0000983c, 0x00200400 },
{ 0x0000984c, 0x0040233c },
- { 0x0000a84c, 0x0040233c },
{ 0x00009854, 0x00000044 },
{ 0x00009900, 0x00000000 },
{ 0x00009904, 0x00000000 },
@@ -2961,20 +3972,18 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009910, 0x01002310 },
{ 0x0000991c, 0x10000fff },
{ 0x00009920, 0x04900000 },
- { 0x0000a920, 0x04900000 },
{ 0x00009928, 0x00000001 },
{ 0x0000992c, 0x00000004 },
{ 0x00009934, 0x1e1f2022 },
{ 0x00009938, 0x0a0b0c0d },
{ 0x0000993c, 0x00000000 },
+ { 0x00009940, 0x14750604 },
{ 0x00009948, 0x9280c00a },
{ 0x0000994c, 0x00020028 },
{ 0x00009954, 0x5f3ca3de },
{ 0x00009958, 0x2108ecff },
- { 0x00009940, 0x14750604 },
- { 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
- { 0x00009970, 0x190fb515 },
+ { 0x00009968, 0x000003ce },
+ { 0x00009970, 0x1927b515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@@ -2989,7 +3998,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x000099a0, 0x00000000 },
{ 0x000099a4, 0x00000001 },
{ 0x000099a8, 0x201fff00 },
- { 0x000099ac, 0x006f0000 },
+ { 0x000099ac, 0x2def0a00 },
{ 0x000099b0, 0x03051000 },
{ 0x000099b4, 0x00000820 },
{ 0x000099dc, 0x00000000 },
@@ -2998,31 +4007,28 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x000099e8, 0x3c466478 },
{ 0x000099ec, 0x0cc80caa },
{ 0x000099f0, 0x00000000 },
- { 0x000099fc, 0x00001042 },
+ { 0x0000a208, 0x803e6788 },
{ 0x0000a210, 0x4080a333 },
- { 0x0000a214, 0x40206c10 },
+ { 0x0000a214, 0x00206c10 },
{ 0x0000a218, 0x009c4060 },
{ 0x0000a220, 0x01834061 },
{ 0x0000a224, 0x00000400 },
{ 0x0000a228, 0x000003b5 },
- { 0x0000a22c, 0x233f71c0 },
+ { 0x0000a22c, 0x00000000 },
{ 0x0000a234, 0x20202020 },
{ 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c88000 },
- { 0x0000a240, 0x38490a20 },
- { 0x0000a244, 0x00007bb6 },
- { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
{ 0x0000a24c, 0x00000000 },
{ 0x0000a254, 0x00000000 },
- { 0x0000a258, 0x0cdbd380 },
- { 0x0000a25c, 0x0f0f0f01 },
- { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a258, 0x0ccb5380 },
+ { 0x0000a25c, 0x15151501 },
+ { 0x0000a260, 0xdfa90f01 },
{ 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000d270, 0x00820820 },
- { 0x0000a278, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce },
+ { 0x0000a26c, 0x0ebae9e6 },
+ { 0x0000d270, 0x0d820820 },
+ { 0x0000a278, 0x39ce739c },
+ { 0x0000a27c, 0x050e039c },
{ 0x0000d35c, 0x07ffffef },
{ 0x0000d360, 0x0fffffe7 },
{ 0x0000d364, 0x17ffffe5 },
@@ -3037,8 +4043,8 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a388, 0x0c000000 },
{ 0x0000a38c, 0x20202020 },
{ 0x0000a390, 0x20202020 },
- { 0x0000a394, 0x1ce739ce },
- { 0x0000a398, 0x000001ce },
+ { 0x0000a394, 0x39ce739c },
+ { 0x0000a398, 0x0000039c },
{ 0x0000a39c, 0x00000001 },
{ 0x0000a3a0, 0x00000000 },
{ 0x0000a3a4, 0x00000000 },
@@ -3050,96 +4056,746 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a3bc, 0x00000000 },
{ 0x0000a3c0, 0x00000000 },
{ 0x0000a3c4, 0x00000000 },
- { 0x0000a3c8, 0x00000246 },
{ 0x0000a3cc, 0x20202020 },
{ 0x0000a3d0, 0x20202020 },
{ 0x0000a3d4, 0x20202020 },
- { 0x0000a3dc, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3dc, 0x39ce739c },
+ { 0x0000a3e0, 0x0000039c },
{ 0x0000a3e4, 0x00000000 },
{ 0x0000a3e8, 0x18c43433 },
{ 0x0000a3ec, 0x00f70081 },
- { 0x00007800, 0x00040000 },
- { 0x00007804, 0xdb005012 },
- { 0x00007808, 0x04924914 },
- { 0x0000780c, 0x21084210 },
- { 0x00007810, 0x6d801300 },
- { 0x00007814, 0x0019beff },
- { 0x00007818, 0x07e41000 },
- { 0x0000781c, 0x00392000 },
- { 0x00007820, 0x92592480 },
- { 0x00007824, 0x00040000 },
- { 0x00007828, 0xdb005012 },
- { 0x0000782c, 0x04924914 },
- { 0x00007830, 0x21084210 },
- { 0x00007834, 0x6d801300 },
- { 0x00007838, 0x0019beff },
- { 0x0000783c, 0x07e40000 },
- { 0x00007840, 0x00392000 },
- { 0x00007844, 0x92592480 },
- { 0x00007848, 0x00100000 },
- { 0x0000784c, 0x773f0567 },
- { 0x00007850, 0x54214514 },
- { 0x00007854, 0x12035828 },
- { 0x00007858, 0x9259269a },
- { 0x00007860, 0x52802000 },
- { 0x00007864, 0x0a8e370e },
- { 0x00007868, 0xc0102850 },
- { 0x0000786c, 0x812d4000 },
- { 0x00007870, 0x807ec400 },
- { 0x00007874, 0x001b6db0 },
- { 0x00007878, 0x00376b63 },
- { 0x0000787c, 0x06db6db6 },
- { 0x00007880, 0x006d8000 },
- { 0x00007884, 0xffeffffe },
- { 0x00007888, 0xffeffffe },
- { 0x0000788c, 0x00010000 },
- { 0x00007890, 0x02060aeb },
- { 0x00007898, 0x2a850160 },
+ { 0x00007800, 0x00140000 },
+ { 0x00007804, 0x0e4548d8 },
+ { 0x00007808, 0x54214514 },
+ { 0x0000780c, 0x02025820 },
+ { 0x00007810, 0x71c0d388 },
+ { 0x00007814, 0x924934a8 },
+ { 0x0000781c, 0x00000000 },
+ { 0x00007820, 0x00000c04 },
+ { 0x00007824, 0x00d86fff },
+ { 0x00007828, 0x26d2491b },
+ { 0x0000782c, 0x6e36d97b },
+ { 0x00007830, 0xedb6d96c },
+ { 0x00007834, 0x71400086 },
+ { 0x00007838, 0xfac68800 },
+ { 0x0000783c, 0x0001fffe },
+ { 0x00007840, 0xffeb1a20 },
+ { 0x00007844, 0x000c0db6 },
+ { 0x00007848, 0x6db61b6f },
+ { 0x0000784c, 0x6d9b66db },
+ { 0x00007850, 0x6d8c6dba },
+ { 0x00007854, 0x00040000 },
+ { 0x00007858, 0xdb003012 },
+ { 0x0000785c, 0x04924914 },
+ { 0x00007860, 0x21084210 },
+ { 0x00007864, 0xf7d7ffde },
+ { 0x00007868, 0xc2034080 },
+ { 0x0000786c, 0x48609eb4 },
+ { 0x00007870, 0x10142c00 },
};
-static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
- { 0x00001030, 0x00000268, 0x000004d0 },
- { 0x00001070, 0x0000018c, 0x00000318 },
- { 0x000010b0, 0x00000fd0, 0x00001fa0 },
- { 0x00008014, 0x044c044c, 0x08980898 },
- { 0x0000801c, 0x148ec02b, 0x148ec057 },
- { 0x00008318, 0x000044c0, 0x00008980 },
- { 0x00009820, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000f0f, 0x00000f0f },
- { 0x00009828, 0x0b020001, 0x0b020001 },
- { 0x00009834, 0x00000f0f, 0x00000f0f },
- { 0x00009844, 0x03721821, 0x03721821 },
- { 0x00009914, 0x00000898, 0x00000898 },
- { 0x00009918, 0x0000000b, 0x00000016 },
- { 0x00009944, 0xdfbc1210, 0xdfbc1210 },
+static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
};
-
-
-static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
+static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004040, 0x9248fd00 },
{0x00004040, 0x24924924 },
{0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 },
- {0x00004040, 0x401dcffc },
- {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
};
+static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e },
+ { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 },
+ { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+ { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
+ { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 },
+ { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 },
+ { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 },
+ { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 },
+ { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+};
+static const u_int32_t ar9285Common_9285_1_2[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020045 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00007010, 0x00000031 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x00000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008120, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000001 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x00010380 },
+ { 0x00008344, 0x00581043 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x01002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009940, 0x14750604 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x2108ecff },
+ { 0x00009968, 0x000003ce },
+ { 0x00009970, 0x192bb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x00009980, 0x00000000 },
+ { 0x00009984, 0x00000000 },
+ { 0x00009988, 0x00000000 },
+ { 0x0000998c, 0x00000000 },
+ { 0x00009990, 0x00000000 },
+ { 0x00009994, 0x00000000 },
+ { 0x00009998, 0x00000000 },
+ { 0x0000999c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x2def1000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x0000a208, 0x803e6788 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x00206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x00000000 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0ccb5380 },
+ { 0x0000a25c, 0x15151501 },
+ { 0x0000a260, 0xdfa90f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9e6 },
+ { 0x0000d270, 0x0d820820 },
+ { 0x0000a278, 0x318c6318 },
+ { 0x0000a27c, 0x050c0318 },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x318c6318 },
+ { 0x0000a398, 0x00000318 },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x318c6318 },
+ { 0x0000a3e0, 0x00000318 },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x00007800, 0x00140000 },
+ { 0x00007804, 0x0e4548d8 },
+ { 0x00007808, 0x54214514 },
+ { 0x0000780c, 0x02025820 },
+ { 0x00007810, 0x71c0d388 },
+ { 0x00007814, 0x924934a8 },
+ { 0x0000781c, 0x00000000 },
+ { 0x00007820, 0x00000c04 },
+ { 0x00007824, 0x00d86fff },
+ { 0x00007828, 0x26d2491b },
+ { 0x0000782c, 0x6e36d97b },
+ { 0x00007830, 0xedb6d96e },
+ { 0x00007834, 0x71400087 },
+ { 0x00007838, 0xfac68801 },
+ { 0x0000783c, 0x0001fffe },
+ { 0x00007840, 0xffeb1a20 },
+ { 0x00007844, 0x000c0db6 },
+ { 0x00007848, 0x6db61b6f },
+ { 0x0000784c, 0x6d9b66db },
+ { 0x00007850, 0x6d8c6dba },
+ { 0x00007854, 0x00040000 },
+ { 0x00007858, 0xdb003012 },
+ { 0x0000785c, 0x04924914 },
+ { 0x00007860, 0x21084210 },
+ { 0x00007864, 0xf7d7ffde },
+ { 0x00007868, 0xc2034080 },
+ { 0x0000786c, 0x48609eb4 },
+ { 0x00007870, 0x10142c00 },
+};
-static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
+static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0xc01dcffd },
+ {0x00004040, 0x1aaabe41 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
{0x00004040, 0x9248fd00 },
{0x00004040, 0x24924924 },
{0x00004040, 0xa8000019 },
{0x00004040, 0x13160820 },
{0x00004040, 0xe5980560 },
- {0x00004040, 0x401dcffd },
- {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xc01dcffc },
+ {0x00004040, 0x1aaabe41 },
{0x00004040, 0xbe105554 },
{0x00004040, 0x00043007 },
{0x00004044, 0x00000000 },
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c
new file mode 100644
index 00000000000..af32d091dc3
--- /dev/null
+++ b/drivers/net/wireless/ath9k/mac.c
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+ struct ath9k_tx_queue_info *qi)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+ "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+ ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
+ ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
+ ahp->ah_txUrnInterruptMask);
+
+ REG_WRITE(ah, AR_IMR_S0,
+ SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+ | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+ REG_WRITE(ah, AR_IMR_S1,
+ SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+ | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+ REG_RMW_FIELD(ah, AR_IMR_S2,
+ AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+{
+ return REG_READ(ah, AR_QTXDP(q));
+}
+
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
+{
+ REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+ return true;
+}
+
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+{
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+
+ REG_WRITE(ah, AR_Q_TXE, 1 << q);
+
+ return true;
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+{
+ u32 npend;
+
+ npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+ if (npend == 0) {
+
+ if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+ npend = 1;
+ }
+
+ return npend;
+}
+
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 txcfg, curLevel, newLevel;
+ enum ath9k_int omask;
+
+ if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+ return false;
+
+ omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+
+ txcfg = REG_READ(ah, AR_TXCFG);
+ curLevel = MS(txcfg, AR_FTRIG);
+ newLevel = curLevel;
+ if (bIncTrigLevel) {
+ if (curLevel < MAX_TX_FIFO_THRESHOLD)
+ newLevel++;
+ } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+ newLevel--;
+ if (newLevel != curLevel)
+ REG_WRITE(ah, AR_TXCFG,
+ (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+ ath9k_hw_set_interrupts(ah, omask);
+
+ ah->ah_txTrigLevel = newLevel;
+
+ return newLevel != curLevel;
+}
+
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+{
+ u32 tsfLow, j, wait;
+
+ REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+ for (wait = 1000; wait != 0; wait--) {
+ if (ath9k_hw_numtxpending(ah, q) == 0)
+ break;
+ udelay(100);
+ }
+
+ if (ath9k_hw_numtxpending(ah, q)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: Num of pending TX Frames %d on Q %d\n",
+ __func__, ath9k_hw_numtxpending(ah, q), q);
+
+ for (j = 0; j < 2; j++) {
+ tsfLow = REG_READ(ah, AR_TSF_L32);
+ REG_WRITE(ah, AR_QUIET2,
+ SM(10, AR_QUIET2_QUIET_DUR));
+ REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+ REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+ REG_SET_BIT(ah, AR_TIMER_MODE,
+ AR_QUIET_TIMER_EN);
+
+ if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+ break;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "TSF have moved while trying to set "
+ "quiet time TSF: 0x%08x\n", tsfLow);
+ }
+
+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+
+ udelay(200);
+ REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+
+ wait = 1000;
+
+ while (ath9k_hw_numtxpending(ah, q)) {
+ if ((--wait) == 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+ "Failed to stop Tx DMA in 100 "
+ "msec after killing last frame\n");
+ break;
+ }
+ udelay(100);
+ }
+
+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+ }
+
+ REG_WRITE(ah, AR_Q_TXD, 0);
+
+ return wait != 0;
+}
+
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 segLen, bool firstSeg,
+ bool lastSeg, const struct ath_desc *ds0)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (firstSeg) {
+ ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
+ } else if (lastSeg) {
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = segLen;
+ ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+ ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+ } else {
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = segLen | AR_TxMore;
+ ads->ds_ctl2 = 0;
+ ads->ds_ctl3 = 0;
+ }
+ ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+ ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+ ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+ ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+ ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+
+ return true;
+}
+
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+ ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+ ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+ ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+ ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+ return -EINPROGRESS;
+
+ ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+ ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
+ ds->ds_txstat.ts_status = 0;
+ ds->ds_txstat.ts_flags = 0;
+
+ if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+ if (ads->ds_txstatus1 & AR_Filtered)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+ if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
+ if (ads->ds_txstatus9 & AR_TxOpExceeded)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+ if (ads->ds_txstatus1 & AR_TxTimerExpired)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+ if (ads->ds_txstatus1 & AR_DescCfgErr)
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+ if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
+ if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
+ if (ads->ds_txstatus0 & AR_TxBaStatus) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
+ ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
+ ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
+ }
+
+ ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+ switch (ds->ds_txstat.ts_rateindex) {
+ case 0:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+ break;
+ case 1:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+ break;
+ case 2:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+ break;
+ case 3:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+ break;
+ }
+
+ ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+ ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+ ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+ ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+ ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+ ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+ ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+ ds->ds_txstat.evm0 = ads->AR_TxEVM0;
+ ds->ds_txstat.evm1 = ads->AR_TxEVM1;
+ ds->ds_txstat.evm2 = ads->AR_TxEVM2;
+ ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+ ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+ ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+ ds->ds_txstat.ts_antenna = 1;
+
+ return 0;
+}
+
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+ u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ txPower += ahp->ah_txPowerIndexOffset;
+ if (txPower > 63)
+ txPower = 63;
+
+ ads->ds_ctl0 = (pktLen & AR_FrameLen)
+ | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(txPower, AR_XmitPower)
+ | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+ | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+ | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+ ads->ds_ctl1 =
+ (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+ | SM(type, AR_FrameType)
+ | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+ | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+ | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+ ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+ if (AR_SREV_9285(ah)) {
+ ads->ds_ctl8 = 0;
+ ads->ds_ctl9 = 0;
+ ads->ds_ctl10 = 0;
+ ads->ds_ctl11 = 0;
+ }
+}
+
+void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+ struct ath_desc *lastds,
+ u32 durUpdateEn, u32 rtsctsRate,
+ u32 rtsctsDuration,
+ struct ath9k_11n_rate_series series[],
+ u32 nseries, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ar5416_desc *last_ads = AR5416DESC(lastds);
+ u32 ds_ctl0;
+
+ (void) nseries;
+ (void) rtsctsDuration;
+
+ if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+ ds_ctl0 = ads->ds_ctl0;
+
+ if (flags & ATH9K_TXDESC_RTSENA) {
+ ds_ctl0 &= ~AR_CTSEnable;
+ ds_ctl0 |= AR_RTSEnable;
+ } else {
+ ds_ctl0 &= ~AR_RTSEnable;
+ ds_ctl0 |= AR_CTSEnable;
+ }
+
+ ads->ds_ctl0 = ds_ctl0;
+ } else {
+ ads->ds_ctl0 =
+ (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+ }
+
+ ads->ds_ctl2 = set11nTries(series, 0)
+ | set11nTries(series, 1)
+ | set11nTries(series, 2)
+ | set11nTries(series, 3)
+ | (durUpdateEn ? AR_DurUpdateEna : 0)
+ | SM(0, AR_BurstDur);
+
+ ads->ds_ctl3 = set11nRate(series, 0)
+ | set11nRate(series, 1)
+ | set11nRate(series, 2)
+ | set11nRate(series, 3);
+
+ ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+ | set11nPktDurRTSCTS(series, 1);
+
+ ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+ | set11nPktDurRTSCTS(series, 3);
+
+ ads->ds_ctl7 = set11nRateFlags(series, 0)
+ | set11nRateFlags(series, 1)
+ | set11nRateFlags(series, 2)
+ | set11nRateFlags(series, 3)
+ | SM(rtsctsRate, AR_RTSCTSRate);
+ last_ads->ds_ctl2 = ads->ds_ctl2;
+ last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+ u32 aggrLen)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+ ads->ds_ctl6 &= ~AR_AggrLen;
+ ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+ u32 numDelims)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ unsigned int ctl6;
+
+ ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+ ctl6 = ads->ds_ctl6;
+ ctl6 &= ~AR_PadDelim;
+ ctl6 |= SM(numDelims, AR_PadDelim);
+ ads->ds_ctl6 = ctl6;
+}
+
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 |= AR_IsAggr;
+ ads->ds_ctl1 &= ~AR_MoreAggr;
+ ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+ u32 burstDuration)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl2 &= ~AR_BurstDur;
+ ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+ u32 vmf)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (vmf)
+ ads->ds_ctl0 |= AR_VirtMoreFrag;
+ else
+ ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ *txqs &= ahp->ah_intrTxqs;
+ ahp->ah_intrTxqs &= ~(*txqs);
+}
+
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+ const struct ath9k_tx_queue_info *qinfo)
+{
+ u32 cw;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ return false;
+ }
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
+
+ qi->tqi_ver = qinfo->tqi_ver;
+ qi->tqi_subtype = qinfo->tqi_subtype;
+ qi->tqi_qflags = qinfo->tqi_qflags;
+ qi->tqi_priority = qinfo->tqi_priority;
+ if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+ qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+ else
+ qi->tqi_aifs = INIT_AIFS;
+ if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+ cw = min(qinfo->tqi_cwmin, 1024U);
+ qi->tqi_cwmin = 1;
+ while (qi->tqi_cwmin < cw)
+ qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+ } else
+ qi->tqi_cwmin = qinfo->tqi_cwmin;
+ if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+ cw = min(qinfo->tqi_cwmax, 1024U);
+ qi->tqi_cwmax = 1;
+ while (qi->tqi_cwmax < cw)
+ qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+ } else
+ qi->tqi_cwmax = INIT_CWMAX;
+
+ if (qinfo->tqi_shretry != 0)
+ qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+ else
+ qi->tqi_shretry = INIT_SH_RETRY;
+ if (qinfo->tqi_lgretry != 0)
+ qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+ else
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+ qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+ qi->tqi_burstTime = qinfo->tqi_burstTime;
+ qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+ switch (qinfo->tqi_subtype) {
+ case ATH9K_WME_UPSD:
+ if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
+ qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+ struct ath9k_tx_queue_info *qinfo)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ return false;
+ }
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
+ return false;
+ }
+
+ qinfo->tqi_qflags = qi->tqi_qflags;
+ qinfo->tqi_ver = qi->tqi_ver;
+ qinfo->tqi_subtype = qi->tqi_subtype;
+ qinfo->tqi_qflags = qi->tqi_qflags;
+ qinfo->tqi_priority = qi->tqi_priority;
+ qinfo->tqi_aifs = qi->tqi_aifs;
+ qinfo->tqi_cwmin = qi->tqi_cwmin;
+ qinfo->tqi_cwmax = qi->tqi_cwmax;
+ qinfo->tqi_shretry = qi->tqi_shretry;
+ qinfo->tqi_lgretry = qi->tqi_lgretry;
+ qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
+ qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
+ qinfo->tqi_burstTime = qi->tqi_burstTime;
+ qinfo->tqi_readyTime = qi->tqi_readyTime;
+
+ return true;
+}
+
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+ const struct ath9k_tx_queue_info *qinfo)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_tx_queue_info *qi;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ int q;
+
+ switch (type) {
+ case ATH9K_TX_QUEUE_BEACON:
+ q = pCap->total_queues - 1;
+ break;
+ case ATH9K_TX_QUEUE_CAB:
+ q = pCap->total_queues - 2;
+ break;
+ case ATH9K_TX_QUEUE_PSPOLL:
+ q = 1;
+ break;
+ case ATH9K_TX_QUEUE_UAPSD:
+ q = pCap->total_queues - 3;
+ break;
+ case ATH9K_TX_QUEUE_DATA:
+ for (q = 0; q < pCap->total_queues; q++)
+ if (ahp->ah_txq[q].tqi_type ==
+ ATH9K_TX_QUEUE_INACTIVE)
+ break;
+ if (q == pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "no available tx queue\n");
+ return -1;
+ }
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
+ return -1;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "tx queue %u already active\n", q);
+ return -1;
+ }
+ memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+ qi->tqi_type = type;
+ if (qinfo == NULL) {
+ qi->tqi_qflags =
+ TXQ_FLAG_TXOKINT_ENABLE
+ | TXQ_FLAG_TXERRINT_ENABLE
+ | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+ qi->tqi_aifs = INIT_AIFS;
+ qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+ qi->tqi_cwmax = INIT_CWMAX;
+ qi->tqi_shretry = INIT_SH_RETRY;
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ qi->tqi_physCompBuf = 0;
+ } else {
+ qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+ (void) ath9k_hw_set_txq_props(ah, q, qinfo);
+ }
+
+ return q;
+}
+
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ return false;
+ }
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
+
+ qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+ ath9k_hw_set_txq_interrupts(ah, qi);
+
+ return true;
+}
+
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ath9k_tx_queue_info *qi;
+ u32 cwMin, chanCwMin, value;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
+ return false;
+ }
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
+ return true;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
+
+ if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+ if (chan && IS_CHAN_B(chan))
+ chanCwMin = INIT_CWMIN_11B;
+ else
+ chanCwMin = INIT_CWMIN;
+
+ for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+ } else
+ cwMin = qi->tqi_cwmin;
+
+ REG_WRITE(ah, AR_DLCL_IFS(q),
+ SM(cwMin, AR_D_LCL_IFS_CWMIN) |
+ SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
+ SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+ REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+ SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
+ SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
+ SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
+
+ REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+ if (qi->tqi_cbrPeriod) {
+ REG_WRITE(ah, AR_QCBRCFG(q),
+ SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
+ SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
+ (qi->tqi_cbrOverflowLimit ?
+ AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+ }
+ if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
+ REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+ AR_Q_RDYTIMECFG_EN);
+ }
+
+ REG_WRITE(ah, AR_DCHNTIME(q),
+ SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+ (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+ if (qi->tqi_burstTime
+ && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah, AR_QMISC(q)) |
+ AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+ }
+
+ if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ }
+ if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ AR_D_MISC_FRAG_BKOFF_EN);
+ }
+ switch (qi->tqi_type) {
+ case ATH9K_TX_QUEUE_BEACON:
+ REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+ | AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_BEACON_USE
+ | AR_Q_MISC_CBR_INCR_DIS1);
+
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+ | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
+ | AR_D_MISC_BEACON_USE
+ | AR_D_MISC_POST_FR_BKOFF_DIS);
+ break;
+ case ATH9K_TX_QUEUE_CAB:
+ REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+ | AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_CBR_INCR_DIS1
+ | AR_Q_MISC_CBR_INCR_DIS0);
+ value = (qi->tqi_readyTime -
+ (ah->ah_config.sw_beacon_response_time -
+ ah->ah_config.dma_beacon_response_time) -
+ ah->ah_config.additional_swba_backoff) * 1024;
+ REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ value | AR_Q_RDYTIMECFG_EN);
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+ | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+ break;
+ case ATH9K_TX_QUEUE_PSPOLL:
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+ break;
+ case ATH9K_TX_QUEUE_UAPSD:
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ break;
+ default:
+ break;
+ }
+
+ if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+ AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ }
+
+ if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+ ahp->ah_txOkInterruptMask |= 1 << q;
+ else
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+ ahp->ah_txErrInterruptMask |= 1 << q;
+ else
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+ ahp->ah_txDescInterruptMask |= 1 << q;
+ else
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+ ahp->ah_txEolInterruptMask |= 1 << q;
+ else
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+ ahp->ah_txUrnInterruptMask |= 1 << q;
+ else
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+ ath9k_hw_set_txq_interrupts(ah, qi);
+
+ return true;
+}
+
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pa, struct ath_desc *nds, u64 tsf)
+{
+ struct ar5416_desc ads;
+ struct ar5416_desc *adsp = AR5416DESC(ds);
+ u32 phyerr;
+
+ if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+ return -EINPROGRESS;
+
+ ads.u.rx = adsp->u.rx;
+
+ ds->ds_rxstat.rs_status = 0;
+ ds->ds_rxstat.rs_flags = 0;
+
+ ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+ ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
+ ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+ ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+ else
+ ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+ ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
+ ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+ ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+ ds->ds_rxstat.rs_moreaggr =
+ (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+ ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+ ds->ds_rxstat.rs_flags =
+ (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+ ds->ds_rxstat.rs_flags |=
+ (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+ if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+ if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+ if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+ if (ads.ds_rxstatus8 & AR_CRCErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+ else if (ads.ds_rxstatus8 & AR_PHYErr) {
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+ phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+ ds->ds_rxstat.rs_phyerr = phyerr;
+ } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+ else if (ads.ds_rxstatus8 & AR_MichaelErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+ }
+
+ return 0;
+}
+
+bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 size, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ ads->ds_ctl1 = size & AR_BufLen;
+ if (flags & ATH9K_RXDESC_INTREQ)
+ ads->ds_ctl1 |= AR_RxIntrReq;
+
+ ads->ds_rxstatus8 &= ~AR_RxDone;
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ memset(&(ads->u), 0, sizeof(ads->u));
+
+ return true;
+}
+
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+{
+ u32 reg;
+
+ if (set) {
+ REG_SET_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+ if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+ REG_CLR_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS |
+ AR_DIAG_RX_ABORT));
+
+ reg = REG_READ(ah, AR_OBS_BUS_1);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
+
+ return false;
+ }
+ } else {
+ REG_CLR_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+ }
+
+ return true;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+{
+ REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_rxena(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+void ath9k_hw_startpcureceive(struct ath_hal *ah)
+{
+ ath9k_enable_mib_counters(ah);
+
+ ath9k_ani_reset(ah);
+
+ REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+}
+
+void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+{
+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+
+ ath9k_hw_disable_mib_counters(ah);
+}
+
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+ if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "dma failed to stop in 10ms\n"
+ "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+ REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+ return false;
+ } else {
+ return true;
+ }
+}
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index f05f584ab7b..191eec50dc7 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -14,15 +14,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* mac80211 and PCI callbacks */
-
#include <linux/nl80211.h>
#include "core.h"
+#include "reg.h"
+#include "hw.h"
#define ATH_PCI_VERSION "0.1"
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
-
static char *dev_info = "ath9k";
MODULE_AUTHOR("Atheros Communications");
@@ -36,9 +34,581 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
{ PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
{ PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
{ 0 }
};
+static void ath_detach(struct ath_softc *sc);
+
+/* return bus cachesize in 4B word units */
+
+static void bus_read_cachesize(struct ath_softc *sc, int *csz)
+{
+ u8 u8tmp;
+
+ pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
+ *csz = (int)u8tmp;
+
+ /*
+ * This check was put in to avoid "unplesant" consequences if
+ * the bootrom has not fully initialized all PCI devices.
+ * Sometimes the cache line size register is not set
+ */
+
+ if (*csz == 0)
+ *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
+}
+
+static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
+{
+ sc->cur_rate_table = sc->hw_rate_table[mode];
+ /*
+ * All protection frames are transmited at 2Mb/s for
+ * 11g, otherwise at 1Mb/s.
+ * XXX select protection rate index from rate table.
+ */
+ sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
+}
+
+static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
+{
+ if (chan->chanmode == CHANNEL_A)
+ return ATH9K_MODE_11A;
+ else if (chan->chanmode == CHANNEL_G)
+ return ATH9K_MODE_11G;
+ else if (chan->chanmode == CHANNEL_B)
+ return ATH9K_MODE_11B;
+ else if (chan->chanmode == CHANNEL_A_HT20)
+ return ATH9K_MODE_11NA_HT20;
+ else if (chan->chanmode == CHANNEL_G_HT20)
+ return ATH9K_MODE_11NG_HT20;
+ else if (chan->chanmode == CHANNEL_A_HT40PLUS)
+ return ATH9K_MODE_11NA_HT40PLUS;
+ else if (chan->chanmode == CHANNEL_A_HT40MINUS)
+ return ATH9K_MODE_11NA_HT40MINUS;
+ else if (chan->chanmode == CHANNEL_G_HT40PLUS)
+ return ATH9K_MODE_11NG_HT40PLUS;
+ else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+ return ATH9K_MODE_11NG_HT40MINUS;
+
+ WARN_ON(1); /* should not get here */
+
+ return ATH9K_MODE_11B;
+}
+
+static void ath_update_txpow(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 txpow;
+
+ if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
+ ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
+ /* read back in case value is clamped */
+ ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
+ sc->sc_curtxpow = txpow;
+ }
+}
+
+static u8 parse_mpdudensity(u8 mpdudensity)
+{
+ /*
+ * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+ * 0 for no restriction
+ * 1 for 1/4 us
+ * 2 for 1/2 us
+ * 3 for 1 us
+ * 4 for 2 us
+ * 5 for 4 us
+ * 6 for 8 us
+ * 7 for 16 us
+ */
+ switch (mpdudensity) {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ /* Our lower layer calculations limit our precision to
+ 1 microsecond */
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ return 4;
+ case 6:
+ return 8;
+ case 7:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
+{
+ struct ath_rate_table *rate_table = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *rate;
+ int i, maxrates;
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11G];
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rate_table = sc->hw_rate_table[ATH9K_MODE_11A];
+ break;
+ default:
+ break;
+ }
+
+ if (rate_table == NULL)
+ return;
+
+ sband = &sc->sbands[band];
+ rate = sc->rates[band];
+
+ if (rate_table->rate_cnt > ATH_RATE_MAX)
+ maxrates = ATH_RATE_MAX;
+ else
+ maxrates = rate_table->rate_cnt;
+
+ for (i = 0; i < maxrates; i++) {
+ rate[i].bitrate = rate_table->info[i].ratekbps / 100;
+ rate[i].hw_value = rate_table->info[i].ratecode;
+ sband->n_bitrates++;
+ DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n",
+ rate[i].bitrate / 10, rate[i].hw_value);
+ }
+}
+
+static int ath_setup_channels(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int nchan, i, a = 0, b = 0;
+ u8 regclassids[ATH_REGCLASSIDS_MAX];
+ u32 nregclass = 0;
+ struct ieee80211_supported_band *band_2ghz;
+ struct ieee80211_supported_band *band_5ghz;
+ struct ieee80211_channel *chan_2ghz;
+ struct ieee80211_channel *chan_5ghz;
+ struct ath9k_channel *c;
+
+ /* Fill in ah->ah_channels */
+ if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
+ regclassids, ATH_REGCLASSIDS_MAX,
+ &nregclass, CTRY_DEFAULT, false, 1)) {
+ u32 rd = ah->ah_currentRD;
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to collect channel list; "
+ "regdomain likely %u country code %u\n",
+ rd, CTRY_DEFAULT);
+ return -EINVAL;
+ }
+
+ band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
+ band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
+ chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
+ chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
+
+ for (i = 0; i < nchan; i++) {
+ c = &ah->ah_channels[i];
+ if (IS_CHAN_2GHZ(c)) {
+ chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
+ chan_2ghz[a].center_freq = c->channel;
+ chan_2ghz[a].max_power = c->maxTxPower;
+
+ if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+ chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
+ if (c->channelFlags & CHANNEL_PASSIVE)
+ chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+ band_2ghz->n_channels = ++a;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ c->channel, c->channelFlags);
+ } else if (IS_CHAN_5GHZ(c)) {
+ chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
+ chan_5ghz[b].center_freq = c->channel;
+ chan_5ghz[b].max_power = c->maxTxPower;
+
+ if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+ chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
+ if (c->channelFlags & CHANNEL_PASSIVE)
+ chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+ band_5ghz->n_channels = ++b;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ c->channel, c->channelFlags);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Set/change channels. If the channel is really being changed, it's done
+ * by reseting the chip. To accomplish this we must first cleanup any pending
+ * DMA, then restart stuff.
+*/
+static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ bool fastcc = true, stopped;
+
+ if (sc->sc_flags & SC_OP_INVALID)
+ return -EIO;
+
+ if (hchan->channel != sc->sc_ah->ah_curchan->channel ||
+ hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags ||
+ (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) ||
+ (sc->sc_flags & SC_OP_FULL_RESET)) {
+ int status;
+ /*
+ * This is only performed if the channel settings have
+ * actually changed.
+ *
+ * To switch channels clear any pending DMA operations;
+ * wait long enough for the RX fifo to drain, reset the
+ * hardware at the new frequency, and then re-enable
+ * the relevant bits of the h/w.
+ */
+ ath9k_hw_set_interrupts(ah, 0);
+ ath_draintxq(sc, false);
+ stopped = ath_stoprecv(sc);
+
+ /* XXX: do not flush receive queue here. We don't want
+ * to flush data frames already in queue because of
+ * changing channel. */
+
+ if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
+ fastcc = false;
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n",
+ sc->sc_ah->ah_curchan->channel,
+ hchan->channel, hchan->channelFlags, sc->tx_chan_width);
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, fastcc, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n",
+ ath9k_hw_mhz2ieee(ah, hchan->channel,
+ hchan->channelFlags),
+ hchan->channel, hchan->channelFlags, status);
+ spin_unlock_bh(&sc->sc_resetlock);
+ return -EIO;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE;
+ sc->sc_flags &= ~SC_OP_FULL_RESET;
+
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to restart recv logic\n");
+ return -EIO;
+ }
+
+ ath_setcurmode(sc, ath_chan2mode(hchan));
+ ath_update_txpow(sc);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ return 0;
+}
+
+/*
+ * 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.
+ */
+static void ath_ani_calibrate(unsigned long data)
+{
+ struct ath_softc *sc;
+ struct ath_hal *ah;
+ bool longcal = false;
+ bool shortcal = false;
+ bool aniflag = false;
+ unsigned int timestamp = jiffies_to_msecs(jiffies);
+ u32 cal_interval;
+
+ sc = (struct ath_softc *)data;
+ ah = sc->sc_ah;
+
+ /*
+ * don't calibrate when we're scanning.
+ * we are most likely not on our home channel.
+ */
+ if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)
+ return;
+
+ /* Long calibration runs independently of short calibration. */
+ if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) {
+ longcal = true;
+ DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+ sc->sc_ani.sc_longcal_timer = timestamp;
+ }
+
+ /* Short calibration applies only while sc_caldone is false */
+ if (!sc->sc_ani.sc_caldone) {
+ if ((timestamp - sc->sc_ani.sc_shortcal_timer) >=
+ ATH_SHORT_CALINTERVAL) {
+ shortcal = true;
+ DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
+ sc->sc_ani.sc_shortcal_timer = timestamp;
+ sc->sc_ani.sc_resetcal_timer = timestamp;
+ }
+ } else {
+ if ((timestamp - sc->sc_ani.sc_resetcal_timer) >=
+ ATH_RESTART_CALINTERVAL) {
+ ath9k_hw_reset_calvalid(ah, ah->ah_curchan,
+ &sc->sc_ani.sc_caldone);
+ if (sc->sc_ani.sc_caldone)
+ sc->sc_ani.sc_resetcal_timer = timestamp;
+ }
+ }
+
+ /* Verify whether we must check ANI */
+ if ((timestamp - sc->sc_ani.sc_checkani_timer) >=
+ ATH_ANI_POLLINTERVAL) {
+ aniflag = true;
+ sc->sc_ani.sc_checkani_timer = timestamp;
+ }
+
+ /* Skip all processing if there's nothing to do. */
+ if (longcal || shortcal || aniflag) {
+ /* Call ANI routine if necessary */
+ if (aniflag)
+ ath9k_hw_ani_monitor(ah, &sc->sc_halstats,
+ ah->ah_curchan);
+
+ /* Perform calibration if necessary */
+ if (longcal || shortcal) {
+ bool iscaldone = false;
+
+ if (ath9k_hw_calibrate(ah, ah->ah_curchan,
+ sc->sc_rx_chainmask, longcal,
+ &iscaldone)) {
+ if (longcal)
+ sc->sc_ani.sc_noise_floor =
+ ath9k_hw_getchan_noise(ah,
+ ah->ah_curchan);
+
+ DPRINTF(sc, ATH_DBG_ANI,
+ "calibrate chan %u/%x nf: %d\n",
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags,
+ sc->sc_ani.sc_noise_floor);
+ } else {
+ DPRINTF(sc, ATH_DBG_ANY,
+ "calibrate chan %u/%x failed\n",
+ ah->ah_curchan->channel,
+ ah->ah_curchan->channelFlags);
+ }
+ sc->sc_ani.sc_caldone = iscaldone;
+ }
+ }
+
+ /*
+ * 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->ah_config.enable_ani)
+ cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+ if (!sc->sc_ani.sc_caldone)
+ cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
+
+ mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
+}
+
+/*
+ * Update tx/rx chainmask. For legacy association,
+ * hard code chainmask to 1x1, for 11n association, use
+ * the chainmask configuration.
+ */
+static void ath_update_chainmask(struct ath_softc *sc, int is_ht)
+{
+ sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
+ if (is_ht) {
+ sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
+ sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
+ } else {
+ sc->sc_tx_chainmask = 1;
+ sc->sc_rx_chainmask = 1;
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask);
+}
+
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+ struct ath_node *an;
+
+ an = (struct ath_node *)sta->drv_priv;
+
+ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_tx_node_init(sc, an);
+
+ an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ sta->ht_cap.ampdu_factor);
+ an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+}
+
+static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
+{
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
+
+ if (sc->sc_flags & SC_OP_TXAGGR)
+ ath_tx_node_cleanup(sc, an);
+}
+
+static void ath9k_tasklet(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ u32 status = sc->sc_intrstatus;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ ath_reset(sc, false);
+ return;
+ } else {
+
+ if (status &
+ (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+ spin_lock_bh(&sc->rx.rxflushlock);
+ ath_rx_tasklet(sc, 0);
+ spin_unlock_bh(&sc->rx.rxflushlock);
+ }
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_TX)
+ ath_tx_tasklet(sc);
+ }
+
+ /* re-enable hardware interrupt */
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+}
+
+static irqreturn_t ath_isr(int irq, void *dev)
+{
+ struct ath_softc *sc = dev;
+ struct ath_hal *ah = sc->sc_ah;
+ enum ath9k_int status;
+ bool sched = false;
+
+ do {
+ if (sc->sc_flags & SC_OP_INVALID) {
+ /*
+ * The hardware is not ready/present, don't
+ * touch anything. Note this can happen early
+ * on if the IRQ is shared.
+ */
+ return IRQ_NONE;
+ }
+ if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
+ return IRQ_NONE;
+ }
+
+ /*
+ * Figure out the reason(s) for the interrupt. Note
+ * that the hal returns a pseudo-ISR that may include
+ * bits we haven't explicitly enabled so we mask the
+ * value to insure we only process bits we requested.
+ */
+ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
+
+ status &= sc->sc_imask; /* discard unasked-for bits */
+
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
+ */
+ if (!status)
+ return IRQ_NONE;
+
+ sc->sc_intrstatus = status;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ sched = true;
+ } else if (status & ATH9K_INT_RXORN) {
+ /* need a chip reset */
+ sched = true;
+ } else {
+ if (status & ATH9K_INT_SWBA) {
+ /* schedule a tasklet for beacon handling */
+ tasklet_schedule(&sc->bcon_tasklet);
+ }
+ if (status & ATH9K_INT_RXEOL) {
+ /*
+ * NB: the hardware should re-read the link when
+ * RXE bit is written, but it doesn't work
+ * at least on older hardware revs.
+ */
+ sched = true;
+ }
+
+ if (status & ATH9K_INT_TXURN)
+ /* bump tx trigger level */
+ ath9k_hw_updatetxtriglevel(ah, true);
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_RX)
+ sched = true;
+ if (status & ATH9K_INT_TX)
+ sched = true;
+ if (status & ATH9K_INT_BMISS)
+ sched = true;
+ /* carrier sense timeout */
+ if (status & ATH9K_INT_CST)
+ sched = true;
+ if (status & ATH9K_INT_MIB) {
+ /*
+ * Disable interrupts until we service the MIB
+ * interrupt; otherwise it will continue to
+ * fire.
+ */
+ ath9k_hw_set_interrupts(ah, 0);
+ /*
+ * Let the hal handle the event. We assume
+ * it will clear whatever condition caused
+ * the interrupt.
+ */
+ ath9k_hw_procmibevent(ah, &sc->sc_halstats);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ if (status & ATH9K_INT_TIM_TIMER) {
+ if (!(ah->ah_caps.hw_caps &
+ ATH9K_HW_CAP_AUTOSLEEP)) {
+ /* Clear RxAbort bit so that we can
+ * receive frames */
+ ath9k_hw_setrxabort(ah, 0);
+ sched = true;
+ }
+ }
+ }
+ } while (0);
+
+ ath_debug_stat_interrupt(sc, status);
+
+ if (sched) {
+ /* turn off every interrupt except SWBA */
+ ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
+ tasklet_schedule(&sc->intr_tq);
+ }
+
+ return IRQ_HANDLED;
+}
+
static int ath_get_channel(struct ath_softc *sc,
struct ieee80211_channel *chan)
{
@@ -53,34 +623,39 @@ static int ath_get_channel(struct ath_softc *sc,
}
static u32 ath_get_extchanmode(struct ath_softc *sc,
- struct ieee80211_channel *chan)
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
u32 chanmode = 0;
- u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset;
- enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width;
switch (chan->band) {
case IEEE80211_BAND_2GHZ:
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
- (tx_chan_width == ATH9K_HT_MACMODE_20))
+ switch(channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
chanmode = CHANNEL_G_HT20;
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
- (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ break;
+ case NL80211_CHAN_HT40PLUS:
chanmode = CHANNEL_G_HT40PLUS;
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
- (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ break;
+ case NL80211_CHAN_HT40MINUS:
chanmode = CHANNEL_G_HT40MINUS;
+ break;
+ }
break;
case IEEE80211_BAND_5GHZ:
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
- (tx_chan_width == ATH9K_HT_MACMODE_20))
+ switch(channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
chanmode = CHANNEL_A_HT20;
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
- (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ break;
+ case NL80211_CHAN_HT40PLUS:
chanmode = CHANNEL_A_HT40PLUS;
- if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
- (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ break;
+ case NL80211_CHAN_HT40MINUS:
chanmode = CHANNEL_A_HT40MINUS;
+ break;
+ }
break;
default:
break;
@@ -89,22 +664,31 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
+static int ath_keyset(struct ath_softc *sc, u16 keyix,
+ struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
+{
+ bool status;
+
+ status = ath9k_hw_set_keycache_entry(sc->sc_ah,
+ keyix, hk, mac, false);
+
+ return status != false;
+}
-static int ath_setkey_tkip(struct ath_softc *sc,
- struct ieee80211_key_conf *key,
+static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
struct ath9k_keyval *hk,
const u8 *addr)
{
- u8 *key_rxmic = NULL;
- u8 *key_txmic = NULL;
+ const u8 *key_rxmic;
+ const u8 *key_txmic;
- key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
- key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+ key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+ key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
if (addr == NULL) {
/* Group key installation */
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- return ath_keyset(sc, key->keyidx, hk, addr);
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ return ath_keyset(sc, keyix, hk, addr);
}
if (!sc->sc_splitmic) {
/*
@@ -113,34 +697,113 @@ static int ath_setkey_tkip(struct ath_softc *sc,
*/
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
- return ath_keyset(sc, key->keyidx, hk, addr);
+ return ath_keyset(sc, keyix, hk, addr);
}
/*
* TX key goes at first index, RX key at +32.
* The hal handles the MIC keys at index+64.
*/
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- if (!ath_keyset(sc, key->keyidx, hk, NULL)) {
+ if (!ath_keyset(sc, keyix, hk, NULL)) {
/* Txmic entry failed. No need to proceed further */
DPRINTF(sc, ATH_DBG_KEYCACHE,
- "%s Setting TX MIC Key Failed\n", __func__);
+ "Setting TX MIC Key Failed\n");
return 0;
}
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
/* XXX delete tx key on failure? */
- return ath_keyset(sc, key->keyidx+32, hk, addr);
+ return ath_keyset(sc, keyix + 32, hk, addr);
+}
+
+static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
+{
+ int i;
+
+ for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+ if (test_bit(i, sc->sc_keymap) ||
+ test_bit(i + 64, sc->sc_keymap))
+ continue; /* At least one part of TKIP key allocated */
+ if (sc->sc_splitmic &&
+ (test_bit(i + 32, sc->sc_keymap) ||
+ test_bit(i + 64 + 32, sc->sc_keymap)))
+ continue; /* At least one part of TKIP key allocated */
+
+ /* Found a free slot for a TKIP key */
+ return i;
+ }
+ return -1;
+}
+
+static int ath_reserve_key_cache_slot(struct ath_softc *sc)
+{
+ int i;
+
+ /* First, try to find slots that would not be available for TKIP. */
+ if (sc->sc_splitmic) {
+ for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
+ if (!test_bit(i, sc->sc_keymap) &&
+ (test_bit(i + 32, sc->sc_keymap) ||
+ test_bit(i + 64, sc->sc_keymap) ||
+ test_bit(i + 64 + 32, sc->sc_keymap)))
+ return i;
+ if (!test_bit(i + 32, sc->sc_keymap) &&
+ (test_bit(i, sc->sc_keymap) ||
+ test_bit(i + 64, sc->sc_keymap) ||
+ test_bit(i + 64 + 32, sc->sc_keymap)))
+ return i + 32;
+ if (!test_bit(i + 64, sc->sc_keymap) &&
+ (test_bit(i , sc->sc_keymap) ||
+ test_bit(i + 32, sc->sc_keymap) ||
+ test_bit(i + 64 + 32, sc->sc_keymap)))
+ return i + 64;
+ if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
+ (test_bit(i, sc->sc_keymap) ||
+ test_bit(i + 32, sc->sc_keymap) ||
+ test_bit(i + 64, sc->sc_keymap)))
+ return i + 64 + 32;
+ }
+ } else {
+ for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
+ if (!test_bit(i, sc->sc_keymap) &&
+ test_bit(i + 64, sc->sc_keymap))
+ return i;
+ if (test_bit(i, sc->sc_keymap) &&
+ !test_bit(i + 64, sc->sc_keymap))
+ return i + 64;
+ }
+ }
+
+ /* No partially used TKIP slots, pick any available slot */
+ for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
+ /* Do not allow slots that could be needed for TKIP group keys
+ * to be used. This limitation could be removed if we know that
+ * TKIP will not be used. */
+ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
+ continue;
+ if (sc->sc_splitmic) {
+ if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
+ continue;
+ if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
+ continue;
+ }
+
+ if (!test_bit(i, sc->sc_keymap))
+ return i; /* Found a free slot for a key */
+ }
+
+ /* No free slot found */
+ return -1;
}
static int ath_key_config(struct ath_softc *sc,
const u8 *addr,
struct ieee80211_key_conf *key)
{
- struct ieee80211_vif *vif;
struct ath9k_keyval hk;
const u8 *mac = NULL;
int ret = 0;
- enum nl80211_iftype opmode;
+ int idx;
memset(&hk, 0, sizeof(hk));
@@ -158,226 +821,103 @@ static int ath_key_config(struct ath_softc *sc,
return -EINVAL;
}
- hk.kv_len = key->keylen;
+ hk.kv_len = key->keylen;
memcpy(hk.kv_val, key->key, key->keylen);
- if (!sc->sc_vaps[0])
- return -EIO;
+ if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ /* For now, use the default keys for broadcast keys. This may
+ * need to change with virtual interfaces. */
+ idx = key->keyidx;
+ } else if (key->keyidx) {
+ struct ieee80211_vif *vif;
- vif = sc->sc_vaps[0]->av_if_data;
- opmode = vif->type;
-
- /*
- * Strategy:
- * For _M_STA mc tx, we will not setup a key at all since we never
- * tx mc.
- * _M_STA mc rx, we will use the keyID.
- * for _M_IBSS mc tx, we will use the keyID, and no macaddr.
- * for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the
- * peer node. BUT we will plumb a cleartext key so that we can do
- * perSta default key table lookup in software.
- */
- if (is_broadcast_ether_addr(addr)) {
- switch (opmode) {
- case NL80211_IFTYPE_STATION:
- /* default key: could be group WPA key
- * or could be static WEP key */
- mac = NULL;
- break;
- case NL80211_IFTYPE_ADHOC:
- break;
- case NL80211_IFTYPE_AP:
- break;
- default:
- ASSERT(0);
- break;
- }
+ mac = addr;
+ vif = sc->sc_vaps[0];
+ if (vif->type != NL80211_IFTYPE_AP) {
+ /* Only keyidx 0 should be used with unicast key, but
+ * allow this for client mode for now. */
+ idx = key->keyidx;
+ } else
+ return -EIO;
} else {
mac = addr;
+ if (key->alg == ALG_TKIP)
+ idx = ath_reserve_key_cache_slot_tkip(sc);
+ else
+ idx = ath_reserve_key_cache_slot(sc);
+ if (idx < 0)
+ return -EIO; /* no free key cache entries */
}
if (key->alg == ALG_TKIP)
- ret = ath_setkey_tkip(sc, key, &hk, mac);
+ ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
else
- ret = ath_keyset(sc, key->keyidx, &hk, mac);
+ ret = ath_keyset(sc, idx, &hk, mac);
if (!ret)
return -EIO;
- return 0;
+ set_bit(idx, sc->sc_keymap);
+ if (key->alg == ALG_TKIP) {
+ set_bit(idx + 64, sc->sc_keymap);
+ if (sc->sc_splitmic) {
+ set_bit(idx + 32, sc->sc_keymap);
+ set_bit(idx + 64 + 32, sc->sc_keymap);
+ }
+ }
+
+ return idx;
}
static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
{
- int freeslot;
+ ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
+ if (key->hw_key_idx < IEEE80211_WEP_NKID)
+ return;
- freeslot = (key->keyidx >= 4) ? 1 : 0;
- ath_key_reset(sc, key->keyidx, freeslot);
+ clear_bit(key->hw_key_idx, sc->sc_keymap);
+ if (key->alg != ALG_TKIP)
+ return;
+
+ clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
+ if (sc->sc_splitmic) {
+ clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
+ clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
+ }
}
-static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
+static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
{
#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
- ht_info->ht_supported = 1;
- ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
- |(u16)IEEE80211_HT_CAP_SM_PS
- |(u16)IEEE80211_HT_CAP_SGI_40
- |(u16)IEEE80211_HT_CAP_DSSSCCK40;
+ ht_info->ht_supported = true;
+ ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SM_PS |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_DSSSCCK40;
ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536;
ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8;
- /* setup supported mcs set */
- memset(ht_info->supp_mcs_set, 0, 16);
- ht_info->supp_mcs_set[0] = 0xff;
- ht_info->supp_mcs_set[1] = 0xff;
- ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
-}
-
-static int ath_rate2idx(struct ath_softc *sc, int rate)
-{
- int i = 0, cur_band, n_rates;
- struct ieee80211_hw *hw = sc->hw;
-
- cur_band = hw->conf.channel->band;
- n_rates = sc->sbands[cur_band].n_bitrates;
-
- for (i = 0; i < n_rates; i++) {
- if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
- break;
- }
-
- /*
- * NB:mac80211 validates rx rate index against the supported legacy rate
- * index only (should be done against ht rates also), return the highest
- * legacy rate index for rx rate which does not match any one of the
- * supported basic and extended rates to make mac80211 happy.
- * The following hack will be cleaned up once the issue with
- * the rx rate index validation in mac80211 is fixed.
- */
- if (i == n_rates)
- return n_rates - 1;
- return i;
-}
-
-static void ath9k_rx_prepare(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_channel *curchan = hw->conf.channel;
-
- memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-
- rx_status->mactime = status->tsf;
- rx_status->band = curchan->band;
- rx_status->freq = curchan->center_freq;
- rx_status->noise = sc->sc_ani.sc_noise_floor;
- rx_status->signal = rx_status->noise + status->rssi;
- rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
- rx_status->antenna = status->antenna;
-
- /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */
- rx_status->qual = status->rssi * 100 / 64;
-
- if (status->flags & ATH_RX_MIC_ERROR)
- rx_status->flag |= RX_FLAG_MMIC_ERROR;
- if (status->flags & ATH_RX_FCS_ERROR)
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-
- rx_status->flag |= RX_FLAG_TSFT;
-}
-
-static u8 parse_mpdudensity(u8 mpdudensity)
-{
- /*
- * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
- * 0 for no restriction
- * 1 for 1/4 us
- * 2 for 1/2 us
- * 3 for 1 us
- * 4 for 2 us
- * 5 for 4 us
- * 6 for 8 us
- * 7 for 16 us
- */
- switch (mpdudensity) {
- case 0:
- return 0;
- case 1:
- case 2:
- case 3:
- /* Our lower layer calculations limit our precision to
- 1 microsecond */
- return 1;
- case 4:
- return 2;
- case 5:
- return 4;
- case 6:
- return 8;
- case 7:
- return 16;
- default:
- return 0;
- }
-}
-
-static void ath9k_ht_conf(struct ath_softc *sc,
- struct ieee80211_bss_conf *bss_conf)
-{
-#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
- struct ath_ht_info *ht_info = &sc->sc_ht_info;
-
- if (bss_conf->assoc_ht) {
- ht_info->ext_chan_offset =
- bss_conf->ht_bss_conf->bss_cap &
- IEEE80211_HT_IE_CHA_SEC_OFFSET;
-
- if (!(bss_conf->ht_conf->cap &
- IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
- (bss_conf->ht_bss_conf->bss_cap &
- IEEE80211_HT_IE_CHA_WIDTH))
- ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
- else
- ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
-
- ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
- ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
- bss_conf->ht_conf->ampdu_factor);
- ht_info->mpdudensity =
- parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
-
- }
-
-#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
+ /* set up supported mcs set */
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ ht_info->mcs.rx_mask[0] = 0xff;
+ ht_info->mcs.rx_mask[1] = 0xff;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_channel *curchan = hw->conf.channel;
- struct ath_vap *avp;
- int pos;
- DECLARE_MAC_BUF(mac);
+ struct ath_vap *avp = (void *)vif->drv_priv;
if (bss_conf->assoc) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n",
- __func__,
- bss_conf->aid);
-
- avp = sc->sc_vaps[0];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
- __func__);
- return;
- }
+ DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, sc->sc_curbssid);
/* New association, store aid */
- if (avp->av_opmode == ATH9K_M_STA) {
+ if (avp->av_opmode == NL80211_IFTYPE_STATION) {
sc->sc_curaid = bss_conf->aid;
ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
sc->sc_curaid);
@@ -393,175 +933,16 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
- /* Update chainmask */
- ath_update_chainmask(sc, bss_conf->assoc_ht);
-
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: bssid %s aid 0x%x\n",
- __func__,
- print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
- __func__,
- curchan->center_freq);
-
- pos = ath_get_channel(sc, curchan);
- if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Invalid channel\n", __func__);
- return;
- }
-
- if (hw->conf.ht_conf.ht_supported)
- sc->sc_ah->ah_channels[pos].chanmode =
- ath_get_extchanmode(sc, curchan);
- else
- sc->sc_ah->ah_channels[pos].chanmode =
- (curchan->band == IEEE80211_BAND_2GHZ) ?
- CHANNEL_G : CHANNEL_A;
-
- /* set h/w channel */
- if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to set channel\n",
- __func__);
-
- ath_rate_newstate(sc, avp);
- /* Update ratectrl about the new state */
- ath_rc_node_update(hw, avp->rc_node);
-
/* Start ANI */
mod_timer(&sc->sc_ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
} else {
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Bss Info DISSOC\n", __func__);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
sc->sc_curaid = 0;
}
}
-void ath_get_beaconconfig(struct ath_softc *sc,
- int if_id,
- struct ath_beacon_config *conf)
-{
- struct ieee80211_hw *hw = sc->hw;
-
- /* fill in beacon config data */
-
- conf->beacon_interval = hw->conf.beacon_int;
- conf->listen_interval = 100;
- conf->dtim_count = 1;
- conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
-}
-
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- struct ath_xmit_status *tx_status, struct ath_node *an)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
- DPRINTF(sc, ATH_DBG_XMIT,
- "%s: TX complete: skb: %p\n", __func__, skb);
-
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
- tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
- /* free driver's private data area of tx_info */
- if (tx_info->driver_data[0] != NULL)
- kfree(tx_info->driver_data[0]);
- tx_info->driver_data[0] = NULL;
- }
-
- if (tx_status->flags & ATH_TX_BAR) {
- tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
- tx_status->flags &= ~ATH_TX_BAR;
- }
-
- if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
- /* Frame was not ACKed, but an ACK was expected */
- tx_info->status.excessive_retries = 1;
- }
- } else {
- /* Frame was ACKed */
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
- }
-
- tx_info->status.retry_count = tx_status->retries;
-
- ieee80211_tx_status(hw, skb);
- if (an)
- ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
-}
-
-int _ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix)
-{
- struct ieee80211_hw *hw = sc->hw;
- struct ath_node *an = NULL;
- struct ieee80211_rx_status rx_status;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- int padsize;
- enum ATH_RX_TYPE st;
-
- /* see if any padding is done by the hw and remove it */
- if (hdrlen & 3) {
- padsize = hdrlen % 4;
- memmove(skb->data + padsize, skb->data, hdrlen);
- skb_pull(skb, padsize);
- }
-
- /* Prepare rx status */
- ath9k_rx_prepare(sc, skb, status, &rx_status);
-
- if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
- !(status->flags & ATH_RX_DECRYPT_ERROR)) {
- rx_status.flag |= RX_FLAG_DECRYPTED;
- } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
- && !(status->flags & ATH_RX_DECRYPT_ERROR)
- && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, sc->sc_keymap))
- rx_status.flag |= RX_FLAG_DECRYPTED;
- }
-
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, hdr->addr2);
- spin_unlock_bh(&sc->node_lock);
-
- if (an) {
- ath_rx_input(sc, an,
- hw->conf.ht_conf.ht_supported,
- skb, status, &st);
- }
- if (!an || (st != ATH_RX_CONSUMED))
- __ieee80211_rx(hw, skb, &rx_status);
-
- return 0;
-}
-
-int ath_rx_subframe(struct ath_node *an,
- struct sk_buff *skb,
- struct ath_recv_status *status)
-{
- struct ath_softc *sc = an->an_sc;
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_rx_status rx_status;
-
- /* Prepare rx status */
- ath9k_rx_prepare(sc, skb, status, &rx_status);
- if (!(status->flags & ATH_RX_DECRYPT_ERROR))
- rx_status.flag |= RX_FLAG_DECRYPTED;
-
- __ieee80211_rx(hw, skb, &rx_status);
-
- return 0;
-}
-
/********************************/
/* LED functions */
/********************************/
@@ -677,7 +1058,8 @@ fail:
ath_deinit_leds(sc);
}
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+
/*******************/
/* Rfkill */
/*******************/
@@ -689,14 +1071,14 @@ static void ath_radio_enable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset channel %u (%uMhz) "
- "flags 0x%x hal status %u\n", __func__,
+ "Unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n",
ath9k_hw_mhz2ieee(ah,
ah->ah_curchan->channel,
ah->ah_curchan->channelFlags),
@@ -708,7 +1090,7 @@ static void ath_radio_enable(struct ath_softc *sc)
ath_update_txpow(sc);
if (ath_startrecv(sc) != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to restart recv logic\n", __func__);
+ "Unable to restart recv logic\n");
return;
}
@@ -747,14 +1129,14 @@ static void ath_radio_disable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah, ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask,
sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing,
false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset channel %u (%uMhz) "
- "flags 0x%x hal status %u\n", __func__,
+ "Unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n",
ath9k_hw_mhz2ieee(ah,
ah->ah_curchan->channel,
ah->ah_curchan->channelFlags),
@@ -834,7 +1216,7 @@ static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
- "radio as it is disabled by h/w \n");
+ "radio as it is disabled by h/w\n");
return -EPERM;
}
ath_radio_enable(sc);
@@ -878,61 +1260,258 @@ static void ath_deinit_rfkill(struct ath_softc *sc)
sc->rf_kill.rfkill = NULL;
}
}
+
+static int ath_start_rfkill_poll(struct ath_softc *sc)
+{
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ queue_delayed_work(sc->hw->workqueue,
+ &sc->rf_kill.rfkill_poll, 0);
+
+ if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+ if (rfkill_register(sc->rf_kill.rfkill)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to register rfkill\n");
+ rfkill_free(sc->rf_kill.rfkill);
+
+ /* Deinitialize the device */
+ ath_detach(sc);
+ if (sc->pdev->irq)
+ free_irq(sc->pdev->irq, sc);
+ pci_iounmap(sc->pdev, sc->mem);
+ pci_release_region(sc->pdev, 0);
+ pci_disable_device(sc->pdev);
+ ieee80211_free_hw(sc->hw);
+ return -EIO;
+ } else {
+ sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+ }
+ }
+
+ return 0;
+}
#endif /* CONFIG_RFKILL */
-static int ath_detach(struct ath_softc *sc)
+static void ath_detach(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
+ int i = 0;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
-
- /* Deinit LED control */
- ath_deinit_leds(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
-#ifdef CONFIG_RFKILL
- /* deinit rfkill */
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
ath_deinit_rfkill(sc);
#endif
-
- /* Unregister hw */
+ ath_deinit_leds(sc);
ieee80211_unregister_hw(hw);
-
- /* unregister Rate control */
- ath_rate_control_unregister();
-
- /* tx/rx cleanup */
-
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);
- /* Deinit */
+ tasklet_kill(&sc->intr_tq);
+ tasklet_kill(&sc->bcon_tasklet);
- ath_deinit(sc);
+ if (!(sc->sc_flags & SC_OP_INVALID))
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- return 0;
+ /* cleanup tx queues */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+ ath9k_hw_detach(sc->sc_ah);
+ ath9k_exit_debug(sc);
}
-static int ath_attach(u16 devid,
- struct ath_softc *sc)
+static int ath_init(u16 devid, struct ath_softc *sc)
{
- struct ieee80211_hw *hw = sc->hw;
- int error = 0;
+ struct ath_hal *ah = NULL;
+ int status;
+ int error = 0, i;
+ int csz = 0;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__);
+ /* XXX: hardware will not be ready until ath_open() being called */
+ sc->sc_flags |= SC_OP_INVALID;
- error = ath_init(devid, sc);
- if (error != 0)
- return error;
+ if (ath9k_init_debug(sc) < 0)
+ printk(KERN_ERR "Unable to create debugfs files\n");
- /* Init nodes */
+ spin_lock_init(&sc->sc_resetlock);
+ mutex_init(&sc->mutex);
+ tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+ tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
+ (unsigned long)sc);
- INIT_LIST_HEAD(&sc->node_list);
- spin_lock_init(&sc->node_lock);
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ bus_read_cachesize(sc, &csz);
+ /* XXX assert csz is non-zero */
+ sc->sc_cachelsz = csz << 2; /* convert to bytes */
- /* get mac address from hardware and set in mac80211 */
+ ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
+ if (ah == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to attach hardware; HAL status %u\n", status);
+ error = -ENXIO;
+ goto bad;
+ }
+ sc->sc_ah = ah;
- SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+ /* Get the hardware key cache size. */
+ sc->sc_keymax = ah->ah_caps.keycache_size;
+ if (sc->sc_keymax > ATH_KEYMAX) {
+ DPRINTF(sc, ATH_DBG_KEYCACHE,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, sc->sc_keymax);
+ sc->sc_keymax = ATH_KEYMAX;
+ }
+
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up.
+ */
+ for (i = 0; i < sc->sc_keymax; i++)
+ ath9k_hw_keyreset(ah, (u16) i);
+
+ /* Collect the channel list using the default country code */
+
+ error = ath_setup_channels(sc);
+ if (error)
+ goto bad;
+
+ /* default to MONITOR mode */
+ sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR;
+
+
+ /* Setup rate tables */
+
+ ath_rate_attach(sc);
+ ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
+ ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
+
+ /*
+ * Allocate hardware transmit queues: one queue for
+ * beacon frames and one data queue for each QoS
+ * priority. Note that the hal handles reseting
+ * these queues at the needed time.
+ */
+ sc->beacon.beaconq = ath_beaconq_setup(ah);
+ if (sc->beacon.beaconq == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup a beacon xmit queue\n");
+ error = -EIO;
+ goto bad2;
+ }
+ sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+ if (sc->beacon.cabq == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
+ error = -EIO;
+ goto bad2;
+ }
+
+ sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
+ ath_cabq_update(sc);
+
+ for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
+ sc->tx.hwq_map[i] = -1;
+
+ /* Setup data queues */
+ /* NB: ensure BK queue is the lowest priority h/w queue */
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BK traffic\n");
+ error = -EIO;
+ goto bad2;
+ }
+
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BE traffic\n");
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VI traffic\n");
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VO traffic\n");
+ error = -EIO;
+ goto bad2;
+ }
+
+ /* Initializes the noise floor to a reasonable default value.
+ * Later on this will be updated during ANI processing. */
+
+ sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+ setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
+
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)) {
+ /*
+ * Whether we should enable h/w TKIP MIC.
+ * XXX: if we don't support WME TKIP MIC, then we wouldn't
+ * report WMM capable, so it's always safe to turn on
+ * TKIP MIC in this case.
+ */
+ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
+ 0, 1, NULL);
+ }
+
+ /*
+ * Check whether the separate key cache entries
+ * are required to handle both tx+rx MIC keys.
+ * With split mic keys the number of stations is limited
+ * to 27 otherwise 59.
+ */
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_MIC, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
+ 0, NULL))
+ sc->sc_splitmic = 1;
+
+ /* turn on mcast key search if possible */
+ if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+ (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
+ 1, NULL);
+
+ sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
+ sc->sc_config.txpowlimit_override = 0;
+
+ /* 11n Capabilities */
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+ sc->sc_flags |= SC_OP_TXAGGR;
+ sc->sc_flags |= SC_OP_RXAGGR;
+ }
+
+ sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
+ sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
+
+ ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+ sc->rx.defant = ath9k_hw_getdefantenna(ah);
+
+ ath9k_hw_getmac(ah, sc->sc_myaddr);
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
+ ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
+ ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
+ ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+ }
+
+ sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
+
+ /* initialize beacon slots */
+ for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
+ sc->beacon.bslot[i] = ATH_IF_ID_ANY;
+
+ /* save MISC configurations */
+ sc->sc_config.swBeaconProcess = 1;
/* setup channels and rates */
@@ -942,55 +1521,81 @@ static int ath_attach(u16 devid,
sc->rates[IEEE80211_BAND_2GHZ];
sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
- if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
- /* Setup HT capabilities for 2.4Ghz*/
- setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
-
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &sc->sbands[IEEE80211_BAND_2GHZ];
-
if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
sc->sbands[IEEE80211_BAND_5GHZ].channels =
sc->channels[IEEE80211_BAND_5GHZ];
sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
sc->rates[IEEE80211_BAND_5GHZ];
- sc->sbands[IEEE80211_BAND_5GHZ].band =
- IEEE80211_BAND_5GHZ;
+ sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ }
- if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
- /* Setup HT capabilities for 5Ghz*/
- setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
+ return 0;
+bad2:
+ /* cleanup tx queues */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+bad:
+ if (ah)
+ ath9k_hw_detach(ah);
- hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &sc->sbands[IEEE80211_BAND_5GHZ];
- }
+ return error;
+}
+
+static int ath_attach(u16 devid, struct ath_softc *sc)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ int error = 0;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
+
+ error = ath_init(devid, sc);
+ if (error != 0)
+ return error;
+
+ /* get mac address from hardware and set in mac80211 */
+
+ SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_AMPDU_AGGREGATION;
- /* FIXME: Have to figure out proper hw init values later */
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 4;
- hw->ampdu_queues = 1;
+ hw->max_rates = 4;
+ hw->max_rate_tries = ATH_11N_TXMAXTRY;
+ hw->sta_data_size = sizeof(struct ath_node);
+ hw->vif_data_size = sizeof(struct ath_vap);
- /* Register rate control */
hw->rate_control_algorithm = "ath9k_rate_control";
- error = ath_rate_control_register();
- if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to register rate control "
- "algorithm:%d\n", __func__, error);
- ath_rate_control_unregister();
- goto bad;
- }
- error = ieee80211_register_hw(hw);
- if (error != 0) {
- ath_rate_control_unregister();
- goto bad;
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+ setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+ setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
- /* Initialize LED control */
- ath_init_leds(sc);
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ];
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &sc->sbands[IEEE80211_BAND_5GHZ];
-#ifdef CONFIG_RFKILL
+ /* initialize tx/rx engine */
+ error = ath_tx_init(sc, ATH_TXBUF);
+ if (error != 0)
+ goto detach;
+
+ error = ath_rx_init(sc, ATH_RXBUF);
+ if (error != 0)
+ goto detach;
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/* Initialze h/w Rfkill */
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
@@ -1000,88 +1605,371 @@ static int ath_attach(u16 devid,
goto detach;
#endif
- /* initialize tx/rx engine */
-
- error = ath_tx_init(sc, ATH_TXBUF);
- if (error != 0)
- goto detach;
+ error = ieee80211_register_hw(hw);
- error = ath_rx_init(sc, ATH_RXBUF);
- if (error != 0)
- goto detach;
+ /* Initialize LED control */
+ ath_init_leds(sc);
return 0;
detach:
ath_detach(sc);
-bad:
return error;
}
+int ath_reset(struct ath_softc *sc, bool retry_tx)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+ int error = 0;
+
+ ath9k_hw_set_interrupts(ah, 0);
+ ath_draintxq(sc, retry_tx);
+ ath_stoprecv(sc);
+ ath_flushrecv(sc);
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan,
+ sc->tx_chan_width,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, false, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to reset hardware; hal status %u\n", status);
+ error = -EIO;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ if (ath_startrecv(sc) != 0)
+ DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+
+ /*
+ * We may be doing a reset in response to a request
+ * that changes the channel so update any state that
+ * might change as a result.
+ */
+ ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan));
+
+ ath_update_txpow(sc);
+
+ if (sc->sc_flags & SC_OP_BEACONS)
+ ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
+
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+ if (retry_tx) {
+ int i;
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ spin_lock_bh(&sc->tx.txq[i].axq_lock);
+ ath_txq_schedule(sc, &sc->tx.txq[i]);
+ spin_unlock_bh(&sc->tx.txq[i].axq_lock);
+ }
+ }
+ }
+
+ return error;
+}
+
+/*
+ * This function will allocate both the DMA descriptor structure, and the
+ * buffers it contains. These are used to contain the descriptors used
+ * by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+ struct list_head *head, const char *name,
+ int nbuf, int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+ name, nbuf, ndesc);
+
+ /* ath_desc must be a multiple of DWORDs */
+ if ((sizeof(struct ath_desc) % 4) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n");
+ ASSERT((sizeof(struct ath_desc) % 4) == 0);
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dd->dd_name = name;
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+ /*
+ * Need additional DMA memory because we can't use
+ * descriptors that cross the 4K page boundary. Assume
+ * one skipped descriptor per 4K page.
+ */
+ if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ u32 ndesc_skipped =
+ ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+ u32 dma_len;
+
+ while (ndesc_skipped) {
+ dma_len = ndesc_skipped * sizeof(struct ath_desc);
+ dd->dd_desc_len += dma_len;
+
+ ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+ };
+ }
+
+ /* allocate descriptors */
+ dd->dd_desc = pci_alloc_consistent(sc->pdev,
+ dd->dd_desc_len,
+ &dd->dd_desc_paddr);
+ if (dd->dd_desc == NULL) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ ds = dd->dd_desc;
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+ dd->dd_name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+ /* allocate buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = kmalloc(bsize, GFP_KERNEL);
+ if (bf == NULL) {
+ error = -ENOMEM;
+ goto fail2;
+ }
+ memset(bf, 0, bsize);
+ dd->dd_bufptr = bf;
+
+ INIT_LIST_HEAD(head);
+ for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+
+ if (!(sc->sc_ah->ah_caps.hw_caps &
+ ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ /*
+ * Skip descriptor addresses which can cause 4KB
+ * boundary crossing (addr + length) with a 32 dword
+ * descriptor fetch.
+ */
+ while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+ ASSERT((caddr_t) bf->bf_desc <
+ ((caddr_t) dd->dd_desc +
+ dd->dd_desc_len));
+
+ ds += ndesc;
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+ }
+ }
+ list_add_tail(&bf->list, head);
+ }
+ return 0;
+fail2:
+ pci_free_consistent(sc->pdev,
+ dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+fail:
+ memset(dd, 0, sizeof(*dd));
+ return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head)
+{
+ pci_free_consistent(sc->pdev,
+ dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+
+ INIT_LIST_HEAD(head);
+ kfree(dd->dd_bufptr);
+ memset(dd, 0, sizeof(*dd));
+}
+
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case 0:
+ qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO];
+ break;
+ case 1:
+ qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI];
+ break;
+ case 2:
+ qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+ break;
+ case 3:
+ qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK];
+ break;
+ default:
+ qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE];
+ break;
+ }
+
+ return qnum;
+}
+
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case ATH9K_WME_AC_VO:
+ qnum = 0;
+ break;
+ case ATH9K_WME_AC_VI:
+ qnum = 1;
+ break;
+ case ATH9K_WME_AC_BE:
+ qnum = 2;
+ break;
+ case ATH9K_WME_AC_BK:
+ qnum = 3;
+ break;
+ default:
+ qnum = -1;
+ break;
+ }
+
+ return qnum;
+}
+
+/**********************/
+/* mac80211 callbacks */
+/**********************/
+
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ieee80211_channel *curchan = hw->conf.channel;
- int error = 0, pos;
+ struct ath9k_channel *init_channel;
+ int error = 0, pos, status;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
- "initial channel: %d MHz\n", __func__, curchan->center_freq);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
+ "initial channel: %d MHz\n", curchan->center_freq);
/* setup initial channel */
pos = ath_get_channel(sc, curchan);
if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
- return -EINVAL;
+ DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq);
+ error = -EINVAL;
+ goto error;
}
+ sc->tx_chan_width = ATH9K_HT_MACMODE_20;
sc->sc_ah->ah_channels[pos].chanmode =
(curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
+ init_channel = &sc->sc_ah->ah_channels[pos];
- /* open ath_dev */
- error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
- if (error) {
+ /* Reset SERDES registers */
+ ath9k_hw_configpcipowersave(sc->sc_ah, 0);
+
+ /*
+ * The basic interface to setting the hardware in a good
+ * state is ``reset''. On return the hardware is known to
+ * be powered up and with interrupts disabled. This must
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(sc->sc_ah, init_channel,
+ sc->tx_chan_width,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, false, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to complete ath_open\n", __func__);
- return error;
+ "Unable to reset hardware; hal status %u "
+ "(freq %u flags 0x%x)\n", status,
+ init_channel->channel, init_channel->channelFlags);
+ error = -EIO;
+ spin_unlock_bh(&sc->sc_resetlock);
+ goto error;
}
+ spin_unlock_bh(&sc->sc_resetlock);
-#ifdef CONFIG_RFKILL
- /* Start rfkill polling */
- if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- queue_delayed_work(sc->hw->workqueue,
- &sc->rf_kill.rfkill_poll, 0);
-
- if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
- if (rfkill_register(sc->rf_kill.rfkill)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to register rfkill\n");
- rfkill_free(sc->rf_kill.rfkill);
+ /*
+ * This is needed only to setup initial state
+ * but it's best done after a reset.
+ */
+ ath_update_txpow(sc);
- /* Deinitialize the device */
- if (sc->pdev->irq)
- free_irq(sc->pdev->irq, sc);
- ath_detach(sc);
- pci_iounmap(sc->pdev, sc->mem);
- pci_release_region(sc->pdev, 0);
- pci_disable_device(sc->pdev);
- ieee80211_free_hw(hw);
- return -EIO;
- } else {
- sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
- }
+ /*
+ * Setup the hardware after reset:
+ * The receive engine is set going.
+ * Frame transmit is handled entirely
+ * in the frame output path; there's nothing to do
+ * here except setup the interrupt mask.
+ */
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "Unable to start recv logic\n");
+ error = -EIO;
+ goto error;
}
+
+ /* Setup our intr mask. */
+ sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
+ | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
+ | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
+
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
+ sc->sc_imask |= ATH9K_INT_GTT;
+
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+ sc->sc_imask |= ATH9K_INT_CST;
+
+ /*
+ * Enable MIB interrupts when there are hardware phy counters.
+ * Note we only do this (at the moment) for station mode.
+ */
+ if (ath9k_hw_phycounters(sc->sc_ah) &&
+ ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
+ (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)))
+ sc->sc_imask |= ATH9K_INT_MIB;
+ /*
+ * Some hardware processes the TIM IE and fires an
+ * interrupt when the TIM bit is set. For hardware
+ * that does, if not overridden by configuration,
+ * enable the TIM interrupt when operating as station.
+ */
+ if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
+ (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) &&
+ !sc->sc_config.swBeaconProcess)
+ sc->sc_imask |= ATH9K_INT_TIM;
+
+ ath_setcurmode(sc, ath_chan2mode(init_channel));
+
+ sc->sc_flags &= ~SC_OP_INVALID;
+
+ /* Disable BMISS interrupt when we're not associated */
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+
+ ieee80211_wake_queues(sc->hw);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+ error = ath_start_rfkill_poll(sc);
#endif
- ieee80211_wake_queues(hw);
- return 0;
+error:
+ return error;
}
static int ath9k_tx(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_softc *sc = hw->priv;
+ struct ath_tx_control txctl;
int hdrlen, padsize;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ memset(&txctl, 0, sizeof(struct ath_tx_control));
/*
* As a temporary workaround, assign seq# here; this will likely need
@@ -1091,9 +1979,9 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- sc->seq_no += 0x10;
+ sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}
/* Add the padding after the header if this is not already done */
@@ -1106,45 +1994,68 @@ static int ath9k_tx(struct ieee80211_hw *hw,
memmove(skb->data, skb->data + padsize, hdrlen);
}
- DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
- __func__,
- skb);
+ /* Check if a tx queue is available */
- if (ath_tx_start(sc, skb) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
- dev_kfree_skb_any(skb);
- /* FIXME: Check for proper return value from ATH_DEV */
- return 0;
+ txctl.txq = ath_test_get_txq(sc, skb);
+ if (!txctl.txq)
+ goto exit;
+
+ DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
+
+ if (ath_tx_start(sc, skb, &txctl) != 0) {
+ DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
+ goto exit;
}
return 0;
+exit:
+ dev_kfree_skb_any(skb);
+ return 0;
}
static void ath9k_stop(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
- int error;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
+ if (sc->sc_flags & SC_OP_INVALID) {
+ DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ return;
+ }
- error = ath_suspend(sc);
- if (error)
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Device is no longer present\n", __func__);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n");
+
+ ieee80211_stop_queues(sc->hw);
+
+ /* make sure h/w will not generate any interrupt
+ * before setting the invalid flag. */
+ ath9k_hw_set_interrupts(sc->sc_ah, 0);
- ieee80211_stop_queues(hw);
+ if (!(sc->sc_flags & SC_OP_INVALID)) {
+ ath_draintxq(sc, false);
+ ath_stoprecv(sc);
+ ath9k_hw_phy_disable(sc->sc_ah);
+ } else
+ sc->rx.rxlink = NULL;
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
+ /* disable HAL and put h/w to sleep */
+ ath9k_hw_disable(sc->sc_ah);
+ ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+ sc->sc_flags |= SC_OP_INVALID;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ath_softc *sc = hw->priv;
- int error, ic_opmode = 0;
+ struct ath_vap *avp = (void *)conf->vif->drv_priv;
+ enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
/* Support only vap for now */
@@ -1153,32 +2064,34 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
switch (conf->type) {
case NL80211_IFTYPE_STATION:
- ic_opmode = ATH9K_M_STA;
+ ic_opmode = NL80211_IFTYPE_STATION;
break;
case NL80211_IFTYPE_ADHOC:
- ic_opmode = ATH9K_M_IBSS;
+ ic_opmode = NL80211_IFTYPE_ADHOC;
break;
case NL80211_IFTYPE_AP:
- ic_opmode = ATH9K_M_HOSTAP;
+ ic_opmode = NL80211_IFTYPE_AP;
break;
default:
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Interface type %d not yet supported\n",
- __func__, conf->type);
+ "Interface type %d not yet supported\n", conf->type);
return -EOPNOTSUPP;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
- __func__,
- ic_opmode);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode);
- error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
- if (error) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to attach vap, error: %d\n",
- __func__, error);
- return error;
- }
+ /* Set the VAP opmode */
+ avp->av_opmode = ic_opmode;
+ avp->av_bslot = -1;
+
+ if (ic_opmode == NL80211_IFTYPE_AP)
+ ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+
+ sc->sc_vaps[0] = conf->vif;
+ sc->sc_nvaps++;
+
+ /* Set the device opmode */
+ sc->sc_ah->ah_opmode = ic_opmode;
if (conf->type == NL80211_IFTYPE_AP) {
/* TODO: is this a suitable place to start ANI for AP mode? */
@@ -1194,78 +2107,76 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ath_softc *sc = hw->priv;
- struct ath_vap *avp;
- int error;
-
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
+ struct ath_vap *avp = (void *)conf->vif->drv_priv;
- avp = sc->sc_vaps[0];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
- __func__);
- return;
- }
+ DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
-#ifdef CONFIG_SLOW_ANT_DIV
- ath_slow_ant_div_stop(&sc->sc_antdiv);
-#endif
/* Stop ANI */
del_timer_sync(&sc->sc_ani.timer);
- /* Update ratectrl */
- ath_rate_newstate(sc, avp);
-
/* Reclaim beacon resources */
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
- sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
- ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP ||
+ sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) {
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath_beacon_return(sc, avp);
}
- /* Set interrupt mask */
- sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
sc->sc_flags &= ~SC_OP_BEACONS;
- error = ath_vap_detach(sc, 0);
- if (error)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to detach vap, error: %d\n",
- __func__, error);
+ sc->sc_vaps[0] = NULL;
+ sc->sc_nvaps--;
}
-static int ath9k_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf)
+static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
{
struct ath_softc *sc = hw->priv;
- struct ieee80211_channel *curchan = hw->conf.channel;
- int pos;
+ struct ieee80211_conf *conf = &hw->conf;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
- __func__,
- curchan->center_freq);
+ mutex_lock(&sc->mutex);
+ if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
+ IEEE80211_CONF_CHANGE_HT)) {
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int pos;
- pos = ath_get_channel(sc, curchan);
- if (pos == -1) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
- return -EINVAL;
- }
+ DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ curchan->center_freq);
- sc->sc_ah->ah_channels[pos].chanmode =
- (curchan->band == IEEE80211_BAND_2GHZ) ?
- CHANNEL_G : CHANNEL_A;
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
+ curchan->center_freq);
+ mutex_unlock(&sc->mutex);
+ return -EINVAL;
+ }
- if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
+ sc->tx_chan_width = ATH9K_HT_MACMODE_20;
sc->sc_ah->ah_channels[pos].chanmode =
- ath_get_extchanmode(sc, curchan);
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
- sc->sc_config.txpowlimit = 2 * conf->power_level;
+ if (conf->ht.enabled) {
+ if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
+ conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
+ sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
- /* set h/w channel */
- if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
- __func__);
+ sc->sc_ah->ah_channels[pos].chanmode =
+ ath_get_extchanmode(sc, curchan,
+ conf->ht.channel_type);
+ }
+
+ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
+ DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
+ mutex_unlock(&sc->mutex);
+ return -EINVAL;
+ }
+
+ ath_update_chainmask(sc, conf->ht.enabled);
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ sc->sc_config.txpowlimit = 2 * conf->power_level;
+ mutex_unlock(&sc->mutex);
return 0;
}
@@ -1275,23 +2186,15 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
{
struct ath_softc *sc = hw->priv;
struct ath_hal *ah = sc->sc_ah;
- struct ath_vap *avp;
+ struct ath_vap *avp = (void *)vif->drv_priv;
u32 rfilt = 0;
int error, i;
- DECLARE_MAC_BUF(mac);
-
- avp = sc->sc_vaps[0];
- if (avp == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
- __func__);
- return -EINVAL;
- }
/* TODO: Need to decide which hw opmode to use for multi-interface
* cases */
if (vif->type == NL80211_IFTYPE_AP &&
- ah->ah_opmode != ATH9K_M_HOSTAP) {
- ah->ah_opmode = ATH9K_M_HOSTAP;
+ ah->ah_opmode != NL80211_IFTYPE_AP) {
+ ah->ah_opmode = NL80211_IFTYPE_STATION;
ath9k_hw_setopmode(ah);
ath9k_hw_write_associd(ah, sc->sc_myaddr, 0);
/* Request full reset to get hw opmode changed properly */
@@ -1303,9 +2206,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- /* Update ratectrl about the new state */
- ath_rate_newstate(sc, avp);
-
/* Set BSSID */
memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
sc->sc_curaid = 0;
@@ -1315,27 +2215,9 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
/* Set aggregation protection mode parameters */
sc->sc_config.ath_aggr_prot = 0;
- /*
- * Reset our TSF so that its value is lower than the
- * beacon that we are trying to catch.
- * Only then hw will update its TSF register with the
- * new beacon. Reset the TSF before setting the BSSID
- * to avoid allowing in any frames that would update
- * our TSF only to have us clear it
- * immediately thereafter.
- */
- ath9k_hw_reset_tsf(sc->sc_ah);
-
- /* Disable BMISS interrupt when we're not associated */
- ath9k_hw_set_interrupts(sc->sc_ah,
- sc->sc_imask &
- ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
- sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: RX filter 0x%x bssid %s aid 0x%x\n",
- __func__, rfilt,
- print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+ "RX filter 0x%x bssid %pM aid 0x%x\n",
+ rfilt, sc->sc_curbssid, sc->sc_curaid);
/* need to reconfigure the beacon */
sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -1357,7 +2239,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
* causes reconfiguration; we may be called
* with beacon transmission active.
*/
- ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
error = ath_beacon_alloc(sc, 0);
if (error != 0)
@@ -1403,7 +2285,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
- sc->rx_filter = *total_flags;
+ sc->rx.rxfilter = *total_flags;
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
@@ -1412,8 +2294,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0);
}
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n",
- __func__, sc->rx_filter);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -1422,37 +2303,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
- struct ath_node *an;
- unsigned long flags;
- DECLARE_MAC_BUF(mac);
-
- spin_lock_irqsave(&sc->node_lock, flags);
- an = ath_node_find(sc, sta->addr);
- spin_unlock_irqrestore(&sc->node_lock, flags);
switch (cmd) {
case STA_NOTIFY_ADD:
- spin_lock_irqsave(&sc->node_lock, flags);
- if (!an) {
- ath_node_attach(sc, sta->addr, 0);
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
- __func__, print_mac(mac, sta->addr));
- } else {
- ath_node_get(sc, sta->addr);
- }
- spin_unlock_irqrestore(&sc->node_lock, flags);
+ ath_node_attach(sc, sta);
break;
case STA_NOTIFY_REMOVE:
- if (!an)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Removal of a non-existent node\n",
- __func__);
- else {
- ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
- __func__,
- print_mac(mac, sta->addr));
- }
+ ath_node_detach(sc, sta);
break;
default:
break;
@@ -1477,20 +2334,14 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw,
qnum = ath_get_hal_qnum(queue, sc);
DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Configure tx [queue/halq] [%d/%d], "
+ "Configure tx [queue/halq] [%d/%d], "
"aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- __func__,
- queue,
- qnum,
- params->aifs,
- params->cw_min,
- params->cw_max,
- params->txop);
+ queue, qnum, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
ret = ath_txq_update(sc, qnum, &qi);
if (ret)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: TXQ Update failed\n", __func__);
+ DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
return ret;
}
@@ -1504,23 +2355,22 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
int ret = 0;
- DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
+ DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
ret = ath_key_config(sc, addr, key);
- if (!ret) {
- set_bit(key->keyidx, sc->sc_keymap);
- key->hw_key_idx = key->keyidx;
+ if (ret >= 0) {
+ key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->alg == ALG_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ ret = 0;
}
break;
case DISABLE_KEY:
ath_key_delete(sc, key);
- clear_bit(key->keyidx, sc->sc_keymap);
break;
default:
ret = -EINVAL;
@@ -1537,8 +2387,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
- __func__,
+ DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
@@ -1547,8 +2396,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
- __func__,
+ DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
@@ -1557,18 +2405,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
- if (changed & BSS_CHANGED_HT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
- __func__,
- bss_conf->assoc_ht);
- ath9k_ht_conf(sc, bss_conf);
- }
-
if (changed & BSS_CHANGED_ASSOC) {
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
- __func__,
+ DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc);
- ath9k_bss_assoc_info(sc, bss_conf);
+ ath9k_bss_assoc_info(sc, vif, bss_conf);
}
}
@@ -1601,50 +2441,37 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to start RX aggregation\n",
- __func__);
+ if (!(sc->sc_flags & SC_OP_RXAGGR))
+ ret = -ENOTSUPP;
break;
case IEEE80211_AMPDU_RX_STOP:
- ret = ath_rx_aggr_stop(sc, sta->addr, tid);
- if (ret < 0)
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to stop RX aggregation\n",
- __func__);
break;
case IEEE80211_AMPDU_TX_START:
- ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+ ret = ath_tx_aggr_start(sc, sta, tid, ssn);
if (ret < 0)
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to start TX aggregation\n",
- __func__);
+ "Unable to start TX aggregation\n");
else
ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
- ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+ ret = ath_tx_aggr_stop(sc, sta, tid);
if (ret < 0)
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to stop TX aggregation\n",
- __func__);
+ "Unable to stop TX aggregation\n");
ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
break;
+ case IEEE80211_AMPDU_TX_RESUME:
+ ath_tx_aggr_resume(sc, sta, tid);
+ break;
default:
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unknown AMPDU action\n", __func__);
+ DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n");
}
return ret;
}
-static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value)
-{
- return -EOPNOTSUPP;
-}
-
static struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
@@ -1654,42 +2481,97 @@ static struct ieee80211_ops ath9k_ops = {
.config = ath9k_config,
.config_interface = ath9k_config_interface,
.configure_filter = ath9k_configure_filter,
- .get_stats = NULL,
.sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx,
- .get_tx_stats = NULL,
.bss_info_changed = ath9k_bss_info_changed,
- .set_tim = NULL,
.set_key = ath9k_set_key,
- .hw_scan = NULL,
- .get_tkip_seq = NULL,
- .set_rts_threshold = NULL,
- .set_frag_threshold = NULL,
- .set_retry_limit = NULL,
.get_tsf = ath9k_get_tsf,
.reset_tsf = ath9k_reset_tsf,
- .tx_last_beacon = NULL,
.ampdu_action = ath9k_ampdu_action,
- .set_frag_threshold = ath9k_no_fragmentation,
};
+static struct {
+ u32 version;
+ const char * name;
+} ath_mac_bb_names[] = {
+ { AR_SREV_VERSION_5416_PCI, "5416" },
+ { AR_SREV_VERSION_5416_PCIE, "5418" },
+ { AR_SREV_VERSION_9100, "9100" },
+ { AR_SREV_VERSION_9160, "9160" },
+ { AR_SREV_VERSION_9280, "9280" },
+ { AR_SREV_VERSION_9285, "9285" }
+};
+
+static struct {
+ u16 version;
+ const char * name;
+} ath_rf_names[] = {
+ { 0, "5133" },
+ { AR_RAD5133_SREV_MAJOR, "5133" },
+ { AR_RAD5122_SREV_MAJOR, "5122" },
+ { AR_RAD2133_SREV_MAJOR, "2133" },
+ { AR_RAD2122_SREV_MAJOR, "2122" }
+};
+
+/*
+ * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
+ */
+static const char *
+ath_mac_bb_name(u32 mac_bb_version)
+{
+ int i;
+
+ for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) {
+ if (ath_mac_bb_names[i].version == mac_bb_version) {
+ return ath_mac_bb_names[i].name;
+ }
+ }
+
+ return "????";
+}
+
+/*
+ * Return the RF name. "????" is returned if the RF is unknown.
+ */
+static const char *
+ath_rf_name(u16 rf_version)
+{
+ int i;
+
+ for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) {
+ if (ath_rf_names[i].version == rf_version) {
+ return ath_rf_names[i].name;
+ }
+ }
+
+ return "????";
+}
+
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
void __iomem *mem;
struct ath_softc *sc;
struct ieee80211_hw *hw;
- const char *athname;
u8 csz;
u32 val;
int ret = 0;
+ struct ath_hal *ah;
if (pci_enable_device(pdev))
return -EIO;
- /* XXX 32-bit addressing only */
- if (pci_set_dma_mask(pdev, 0xffffffff)) {
- printk(KERN_ERR "ath_pci: 32-bit DMA not available\n");
- ret = -ENODEV;
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+
+ if (ret) {
+ printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
+ goto bad;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+
+ if (ret) {
+ printk(KERN_ERR "ath9k: 32-bit DMA consistent "
+ "DMA enable failed\n");
goto bad;
}
@@ -1746,16 +2628,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bad2;
}
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
-
- hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
-
SET_IEEE80211_DEV(hw, &pdev->dev);
pci_set_drvdata(pdev, hw);
@@ -1778,11 +2650,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bad4;
}
- athname = ath9k_hw_probe(id->vendor, id->device);
-
- printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n",
+ ah = sc->sc_ah;
+ printk(KERN_INFO
+ "%s: Atheros AR%s MAC/BB Rev:%x "
+ "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
wiphy_name(hw->wiphy),
- athname ? athname : "Atheros ???",
+ ath_mac_bb_name(ah->ah_macVersion),
+ ah->ah_macRev,
+ ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+ ah->ah_phyRev,
(unsigned long)mem, pdev->irq);
return 0;
@@ -1803,17 +2679,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
- enum ath9k_int status;
- if (pdev->irq) {
- ath9k_hw_set_interrupts(sc->sc_ah, 0);
- /* clear the ISR */
- ath9k_hw_getisr(sc->sc_ah, &status);
- sc->sc_flags |= SC_OP_INVALID;
- free_irq(pdev->irq, sc);
- }
ath_detach(sc);
-
+ if (pdev->irq)
+ free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->mem);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
@@ -1829,7 +2698,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
@@ -1866,7 +2735,7 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-#ifdef CONFIG_RFKILL
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/*
* check the h/w rfkill state on resume
* and start the rfkill poll timer
@@ -1896,11 +2765,24 @@ static struct pci_driver ath_pci_driver = {
static int __init init_ath_pci(void)
{
+ int error;
+
printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
+ /* Register rate control algorithm */
+ error = ath_rate_control_register();
+ if (error != 0) {
+ printk(KERN_ERR
+ "Unable to register rate control algorithm: %d\n",
+ error);
+ ath_rate_control_unregister();
+ return error;
+ }
+
if (pci_register_driver(&ath_pci_driver) < 0) {
printk(KERN_ERR
"ath_pci: No devices found, driver not installed.\n");
+ ath_rate_control_unregister();
pci_unregister_driver(&ath_pci_driver);
return -ENODEV;
}
@@ -1911,7 +2793,8 @@ module_init(init_ath_pci);
static void __exit exit_ath_pci(void)
{
+ ath_rate_control_unregister();
pci_unregister_driver(&ath_pci_driver);
- printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+ printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
module_exit(exit_ath_pci);
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c
index eb9121fdfd3..766982a8196 100644
--- a/drivers/net/wireless/ath9k/phy.c
+++ b/drivers/net/wireless/ath9k/phy.c
@@ -52,8 +52,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
bModeSynth = 1;
} else {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u MHz\n", __func__,
- freq);
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -86,7 +85,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
- "%s: invalid channel %u MHz\n", __func__, freq);
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -215,7 +214,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
if (AR_SREV_9280_10_OR_LATER(ah))
return true;
- eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
+ eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
@@ -235,15 +234,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
if (eepMinorRev >= 2) {
if (IS_CHAN_2GHZ(chan)) {
- ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
- db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
+ ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
+ db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
ob2GHz, 3, 197, 0);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
db2GHz, 3, 194, 0);
} else {
- ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
- db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
+ ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
+ db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
ob5GHz, 3, 203, 0);
ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
@@ -348,8 +347,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
|| ahp->ah_analogBank6TPCData == NULL
|| ahp->ah_analogBank7Data == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: cannot allocate RF banks\n",
- __func__);
+ "Cannot allocate RF banks\n");
*status = -ENOMEM;
return false;
}
@@ -360,8 +358,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
if (ahp->ah_addac5416_21 == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: cannot allocate ah_addac5416_21\n",
- __func__);
+ "Cannot allocate ah_addac5416_21\n");
*status = -ENOMEM;
return false;
}
@@ -371,8 +368,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
if (ahp->ah_bank6Temp == NULL) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: cannot allocate ah_bank6Temp\n",
- __func__);
+ "Cannot allocate ah_bank6Temp\n");
*status = -ENOMEM;
return false;
}
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h
index 14702344448..3a406a5c059 100644
--- a/drivers/net/wireless/ath9k/phy.h
+++ b/drivers/net/wireless/ath9k/phy.h
@@ -50,6 +50,9 @@ bool ath9k_hw_init_rf(struct ath_hal *ah,
#define AR_PHY_FC_SHORT_GI_40 0x00000080
#define AR_PHY_FC_WALSH 0x00000100
#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200
+#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800
+
+#define AR_PHY_TEST2 0x9808
#define AR_PHY_TIMING2 0x9810
#define AR_PHY_TIMING3 0x9814
@@ -100,6 +103,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah,
#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF
#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0
+#define AR_PHY_TSTDAC_CONST 0x983c
+
#define AR_PHY_SETTLING 0x9844
#define AR_PHY_SETTLING_SWITCH 0x00003F80
#define AR_PHY_SETTLING_SWITCH_S 7
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index cca2fc5b076..04ab457a8fa 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -15,143 +15,136 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Atheros rate control algorithm
- */
-
#include "core.h"
-/* FIXME: remove this include! */
-#include "../net/mac80211/rate.h"
-
-static u32 tx_triglevel_max;
static struct ath_rate_table ar5416_11na_ratetable = {
42,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
0, 2, 1, 0, 0, 0, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
0, 3, 1, 1, 1, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
2, 4, 2, 2, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 6, 2, 3, 3, 3, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
4, 10, 3, 4, 4, 4, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 14, 3, 5, 5, 5, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 20, 3, 6, 6, 6, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 23, 3, 7, 7, 7, 7, 0 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
0, 2, 3, 8, 24, 8, 24, 3216 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
2, 4, 3, 9, 25, 9, 25, 6434 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
2, 6, 3, 10, 26, 10, 26, 9650 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
4, 10, 3, 11, 27, 11, 27, 12868 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
4, 14, 3, 12, 28, 12, 28, 19304 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
4, 20, 3, 13, 29, 13, 29, 25740 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
4, 23, 3, 14, 30, 14, 30, 28956 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 15, 32, 32180 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
8, 0, 2, 3, 16, 33, 16, 33, 6430 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
2, 4, 3, 17, 34, 17, 34, 12860 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
2, 6, 3, 18, 35, 18, 35, 19300 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
4, 10, 3, 19, 36, 19, 36, 25736 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
4, 14, 3, 20, 37, 20, 37, 38600 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
4, 20, 3, 21, 38, 21, 38, 51472 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
4, 23, 3, 22, 39, 22, 39, 57890 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 23, 41, 64320 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
0, 2, 3, 8, 24, 24, 24, 6684 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
2, 4, 3, 9, 25, 25, 25, 13368 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
2, 6, 3, 10, 26, 26, 26, 20052 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
4, 10, 3, 11, 27, 27, 27, 26738 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
4, 14, 3, 12, 28, 28, 28, 40104 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
4, 20, 3, 13, 29, 29, 29, 53476 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
4, 23, 3, 14, 30, 30, 30, 60156 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 32, 32, 66840 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
4, 25, 3, 15, 31, 32, 32, 74200 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
0, 2, 3, 16, 33, 33, 33, 13360 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
2, 4, 3, 17, 34, 34, 34, 26720 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
2, 6, 3, 18, 35, 35, 35, 40080 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
4, 10, 3, 19, 36, 36, 36, 53440 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
4, 14, 3, 20, 37, 37, 37, 80160 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
4, 20, 3, 21, 38, 38, 38, 106880 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
4, 23, 3, 22, 39, 39, 39, 120240 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 41, 41, 133600 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
4, 25, 3, 23, 40, 41, 41, 148400 },
},
@@ -160,153 +153,149 @@ static struct ath_rate_table ar5416_11na_ratetable = {
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
-/* TRUE_ALL - valid for 20/40/Legacy,
- * TRUE - Legacy only,
- * TRUE_20 - HT 20 only,
- * TRUE_40 - HT 40 only */
-
/* 4ms frame limit not used for NG mode. The values filled
* for HT are the 64K max aggregate limit */
static struct ath_rate_table ar5416_11ng_ratetable = {
46,
+ {0},
{
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 1, 0, 0, 0, 0, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 1, 1, 1, 1, 1, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 2, 2, 2, 2, 2, 0 },
- { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 2, 3, 3, 3, 3, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 2, 1, 4, 4, 4, 4, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 3, 1, 5, 5, 5, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
6, 4, 1, 6, 6, 6, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
6, 6, 2, 7, 7, 7, 7, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
8, 10, 3, 8, 8, 8, 8, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
8, 14, 3, 9, 9, 9, 9, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 20, 3, 10, 10, 10, 10, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
8, 23, 3, 11, 11, 11, 11, 0 },
- { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
4, 2, 3, 12, 28, 12, 28, 3216 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
6, 4, 3, 13, 29, 13, 29, 6434 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
6, 6, 3, 14, 30, 14, 30, 9650 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
8, 10, 3, 15, 31, 15, 31, 12868 },
- { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
8, 14, 3, 16, 32, 16, 32, 19304 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
8, 20, 3, 17, 33, 17, 33, 25740 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
8, 23, 3, 18, 34, 18, 34, 28956 },
- { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
8, 25, 3, 19, 35, 19, 36, 32180 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
4, 2, 3, 20, 37, 20, 37, 6430 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
6, 4, 3, 21, 38, 21, 38, 12860 },
- { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
6, 6, 3, 22, 39, 22, 39, 19300 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
8, 10, 3, 23, 40, 23, 40, 25736 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
8, 14, 3, 24, 41, 24, 41, 38600 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
8, 20, 3, 25, 42, 25, 42, 51472 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
8, 23, 3, 26, 43, 26, 44, 57890 },
- { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
8, 25, 3, 27, 44, 27, 45, 64320 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
8, 2, 3, 12, 28, 28, 28, 6684 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
8, 4, 3, 13, 29, 29, 29, 13368 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
8, 6, 3, 14, 30, 30, 30, 20052 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
8, 10, 3, 15, 31, 31, 31, 26738 },
- { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
8, 14, 3, 16, 32, 32, 32, 40104 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
8, 20, 3, 17, 33, 33, 33, 53476 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
8, 23, 3, 18, 34, 34, 34, 60156 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
8, 23, 3, 19, 35, 36, 36, 66840 },
- { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
8, 25, 3, 19, 35, 36, 36, 74200 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
8, 2, 3, 20, 37, 37, 37, 13360 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
8, 4, 3, 21, 38, 38, 38, 26720 },
- { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
8, 6, 3, 22, 39, 39, 39, 40080 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
8, 10, 3, 23, 40, 40, 40, 53440 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
8, 14, 3, 24, 41, 41, 41, 80160 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
8, 20, 3, 25, 42, 42, 42, 106880 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
8, 23, 3, 26, 43, 43, 43, 120240 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
8, 23, 3, 27, 44, 45, 45, 133600 },
- { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
8, 25, 3, 27, 44, 45, 45, 148400 },
},
@@ -317,29 +306,30 @@ static struct ath_rate_table ar5416_11ng_ratetable = {
static struct ath_rate_table ar5416_11a_ratetable = {
8,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
0, 2, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 23, 3, 7, 0 },
},
@@ -348,109 +338,44 @@ static struct ath_rate_table ar5416_11a_ratetable = {
0, /* Phy rates allowed initially */
};
-static struct ath_rate_table ar5416_11a_ratetable_Half = {
- 8,
- {
- { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */
- 2700, 0x0b, 0x00, (0x80|6),
- 0, 2, 1, 0, 0},
- { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */
- 3900, 0x0f, 0x00, 9,
- 0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */
- 5000, 0x0a, 0x00, (0x80|12),
- 2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */
- 6950, 0x0e, 0x00, 18,
- 2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */
- 8650, 0x09, 0x00, (0x80|24),
- 4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */
- 11500, 0x0d, 0x00, 36,
- 4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */
- 13700, 0x08, 0x00, 48,
- 4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */
- 14650, 0x0c, 0x00, 54,
- 4, 23, 3, 7, 0 },
- },
- 50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static struct ath_rate_table ar5416_11a_ratetable_Quarter = {
- 8,
- {
- { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */
- 1350, 0x0b, 0x00, (0x80|3),
- 0, 2, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */
- 1950, 0x0f, 0x00, 4,
- 0, 3, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */
- 2500, 0x0a, 0x00, (0x80|6),
- 2, 4, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */
- 3475, 0x0e, 0x00, 9,
- 2, 6, 2, 3, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */
- 4325, 0x09, 0x00, (0x80|12),
- 4, 10, 3, 4, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */
- 5750, 0x0d, 0x00, 18,
- 4, 14, 3, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */
- 6850, 0x08, 0x00, 24,
- 4, 19, 3, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */
- 7325, 0x0c, 0x00, 27,
- 4, 23, 3, 7, 0 },
- },
- 50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
static struct ath_rate_table ar5416_11g_ratetable = {
12,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
0, 0, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
1, 1, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
2, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
3, 3, 2, 3, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
4, 2, 1, 4, 0 },
- { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
4, 3, 1, 5, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
6, 4, 1, 6, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
6, 6, 2, 7, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
8, 10, 3, 8, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
8, 14, 3, 9, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
8, 19, 3, 10, 0 },
- { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
8, 23, 3, 11, 0 },
},
@@ -461,17 +386,18 @@ static struct ath_rate_table ar5416_11g_ratetable = {
static struct ath_rate_table ar5416_11b_ratetable = {
4,
+ {0},
{
- { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, (0x80|2),
0, 0, 1, 0, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1800, 0x1a, 0x04, (0x80|4),
1, 1, 1, 1, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4300, 0x19, 0x04, (0x80|11),
1, 2, 2, 2, 0 },
- { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
7100, 0x18, 0x04, (0x80|22),
1, 4, 100, 3, 0 },
},
@@ -480,48 +406,6 @@ static struct ath_rate_table ar5416_11b_ratetable = {
0, /* Phy rates allowed initially */
};
-static void ar5416_attach_ratetables(struct ath_rate_softc *sc)
-{
- /*
- * Attach rate tables.
- */
- sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable;
-
- sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
- &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
- &ar5416_11na_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
- &ar5416_11ng_ratetable;
- sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
- &ar5416_11ng_ratetable;
-}
-
-static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter;
- return;
-}
-
-static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half;
- return;
-}
-
-static void ar5416_setfull_ratetable(struct ath_rate_softc *sc)
-{
- sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
- return;
-}
-
-/*
- * Return the median of three numbers
- */
static inline int8_t median(int8_t a, int8_t b, int8_t c)
{
if (a >= b) {
@@ -541,68 +425,65 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c)
}
}
-static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_sort_validrates(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv)
{
u8 i, j, idx, idx_next;
- for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) {
+ for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
for (j = 0; j <= i-1; j++) {
- idx = rate_ctrl->valid_rate_index[j];
- idx_next = rate_ctrl->valid_rate_index[j+1];
+ idx = ath_rc_priv->valid_rate_index[j];
+ idx_next = ath_rc_priv->valid_rate_index[j+1];
if (rate_table->info[idx].ratekbps >
rate_table->info[idx_next].ratekbps) {
- rate_ctrl->valid_rate_index[j] = idx_next;
- rate_ctrl->valid_rate_index[j+1] = idx;
+ ath_rc_priv->valid_rate_index[j] = idx_next;
+ ath_rc_priv->valid_rate_index[j+1] = idx;
}
}
}
}
-/* Access functions for valid_txrate_mask */
-
-static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl)
+static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
{
u8 i;
- for (i = 0; i < rate_ctrl->rate_table_size; i++)
- rate_ctrl->valid_rate_index[i] = FALSE;
+ for (i = 0; i < ath_rc_priv->rate_table_size; i++)
+ ath_rc_priv->valid_rate_index[i] = 0;
}
-static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
- ASSERT(index <= rate_ctrl->rate_table_size);
- rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE;
+ ASSERT(index <= ath_rc_priv->rate_table_size);
+ ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index)
{
- ASSERT(index <= rate_ctrl->rate_table_size);
- return rate_ctrl->valid_rate_index[index];
+ ASSERT(index <= ath_rc_priv->rate_table_size);
+ return ath_rc_priv->valid_rate_index[index];
}
-/* Iterators for valid_txrate_mask */
-static inline int
-ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl,
- u8 cur_valid_txrate,
- u8 *next_idx)
+static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate,
+ u8 *next_idx)
{
u8 i;
- for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) {
- if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = rate_ctrl->valid_rate_index[i+1];
- return TRUE;
+ for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) {
+ if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = ath_rc_priv->valid_rate_index[i+1];
+ return 1;
}
}
/* No more valid rates */
*next_idx = 0;
- return FALSE;
+
+ return 0;
}
/* Return true only for single stream */
@@ -610,83 +491,72 @@ ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
{
if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG))
- return FALSE;
+ return 0;
if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
- return FALSE;
+ return 0;
if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
- return FALSE;
+ return 0;
if (!ignore_cw && WLAN_RC_PHY_HT(phy))
if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
- return FALSE;
+ return 0;
if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
- return FALSE;
- return TRUE;
+ return 0;
+ return 1;
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_tx_ratectrl *rate_ctrl,
+ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
- for (i = 1; i < rate_ctrl->max_valid_rate ; i++) {
- if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
- *next_idx = rate_ctrl->valid_rate_index[i-1];
- return TRUE;
+ for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) {
+ if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = ath_rc_priv->valid_rate_index[i-1];
+ return 1;
}
}
- return FALSE;
+
+ return 0;
}
-/*
- * Initialize the Valid Rate Index from valid entries in Rate Table
- */
-static u8
-ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u32 capflag)
+static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ u32 capflag)
{
- struct ath_tx_ratectrl *rate_ctrl;
u8 i, hi = 0;
u32 valid;
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
for (i = 0; i < rate_table->rate_cnt; i++) {
valid = (ath_rc_priv->single_stream ?
rate_table->info[i].valid_single_stream :
rate_table->info[i].valid);
- if (valid == TRUE) {
+ if (valid == 1) {
u32 phy = rate_table->info[i].phy;
u8 valid_rate_count = 0;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
- valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy];
+ valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
- rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, i, TRUE);
+ ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, i, 1);
hi = A_MAX(hi, i);
}
}
+
return hi;
}
-/*
- * Initialize the Valid Rate Index from Rate Set
- */
-static u8
-ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- struct ath_rateset *rateset,
- u32 capflag)
+static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ struct ath_rateset *rateset,
+ u32 capflag)
{
- /* XXX: Clean me up and make identation friendly */
u8 i, j, hi = 0;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
/* Use intersection of working rates and valid rates */
for (i = 0; i < rateset->rs_nrates; i++) {
@@ -695,196 +565,89 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
u32 valid = (ath_rc_priv->single_stream ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
+ u8 rate = rateset->rs_rates[i];
+ u8 dot11rate = rate_table->info[j].dot11rate;
/* We allow a rate only if its valid and the
* capflag matches one of the validity
- * (TRUE/TRUE_20/TRUE_40) flags */
-
- /* XXX: catch the negative of this branch
- * first and then continue */
- if (((rateset->rs_rates[i] & 0x7F) ==
- (rate_table->info[j].dot11rate & 0x7F)) &&
- ((valid & WLAN_RC_CAP_MODE(capflag)) ==
- WLAN_RC_CAP_MODE(capflag)) &&
- !WLAN_RC_PHY_HT(phy)) {
+ * (VALID/VALID_20/VALID_40) flags */
+ if (((rate & 0x7F) == (dot11rate & 0x7F)) &&
+ ((valid & WLAN_RC_CAP_MODE(capflag)) ==
+ WLAN_RC_CAP_MODE(capflag)) &&
+ !WLAN_RC_PHY_HT(phy)) {
u8 valid_rate_count = 0;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
valid_rate_count =
- rate_ctrl->valid_phy_ratecnt[phy];
+ ath_rc_priv->valid_phy_ratecnt[phy];
- rate_ctrl->valid_phy_rateidx[phy]
+ ath_rc_priv->valid_phy_rateidx[phy]
[valid_rate_count] = j;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
}
+
return hi;
}
-static u8
-ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 *mcs_set, u32 capflag)
+static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
+ u8 *mcs_set, u32 capflag)
{
+ struct ath_rateset *rateset = (struct ath_rateset *)mcs_set;
+
u8 i, j, hi = 0;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
/* Use intersection of working rates and valid rates */
- for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) {
+ for (i = 0; i < rateset->rs_nrates; i++) {
for (j = 0; j < rate_table->rate_cnt; j++) {
u32 phy = rate_table->info[j].phy;
u32 valid = (ath_rc_priv->single_stream ?
rate_table->info[j].valid_single_stream :
rate_table->info[j].valid);
+ u8 rate = rateset->rs_rates[i];
+ u8 dot11rate = rate_table->info[j].dot11rate;
- if (((((struct ath_rateset *)
- mcs_set)->rs_rates[i] & 0x7F) !=
- (rate_table->info[j].dot11rate & 0x7F)) ||
+ if (((rate & 0x7F) != (dot11rate & 0x7F)) ||
!WLAN_RC_PHY_HT(phy) ||
!WLAN_RC_PHY_HT_VALID(valid, capflag))
continue;
- if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ if (!ath_rc_valid_phyrate(phy, capflag, 0))
continue;
- rate_ctrl->valid_phy_rateidx[phy]
- [rate_ctrl->valid_phy_ratecnt[phy]] = j;
- rate_ctrl->valid_phy_ratecnt[phy] += 1;
- ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ ath_rc_priv->valid_phy_rateidx[phy]
+ [ath_rc_priv->valid_phy_ratecnt[phy]] = j;
+ ath_rc_priv->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(ath_rc_priv, j, 1);
hi = A_MAX(hi, j);
}
}
- return hi;
-}
-
-/*
- * Attach to a device instance. Setup the public definition
- * of how much per-node space we need and setup the private
- * phy tables that have rate control parameters.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah)
-{
- struct ath_rate_softc *asc;
-
- /* we are only in user context so we can sleep for memory */
- asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL);
- if (asc == NULL)
- return NULL;
-
- ar5416_attach_ratetables(asc);
-
- /* Save Maximum TX Trigger Level (used for 11n) */
- tx_triglevel_max = ah->ah_caps.tx_triglevel_max;
- /* return alias for ath_rate_softc * */
- return asc;
-}
-
-static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp,
- struct ath_rate_softc *rsc,
- gfp_t gfp)
-{
- struct ath_rate_node *anode;
-
- anode = kzalloc(sizeof(struct ath_rate_node), gfp);
- if (anode == NULL)
- return NULL;
-
- anode->avp = avp;
- anode->asc = rsc;
- avp->rc_node = anode;
-
- return anode;
-}
-
-static void ath_rate_node_free(struct ath_rate_node *anode)
-{
- if (anode != NULL)
- kfree(anode);
-}
-
-void ath_rate_detach(struct ath_rate_softc *asc)
-{
- if (asc != NULL)
- kfree(asc);
-}
-
-u8 ath_rate_findrateix(struct ath_softc *sc,
- u8 dot11rate)
-{
- const struct ath_rate_table *ratetable;
- struct ath_rate_softc *rsc = sc->sc_rc;
- int i;
-
- ratetable = rsc->hw_rate_table[sc->sc_curmode];
-
- if (WARN_ON(!ratetable))
- return 0;
-
- for (i = 0; i < ratetable->rate_cnt; i++) {
- if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f))
- return i;
- }
- return 0;
-}
-
-/*
- * Update rate-control state on a device state change. When
- * operating as a station this includes associate/reassociate
- * with an AP. Otherwise this gets called, for example, when
- * the we transition to run state when operating as an AP.
- */
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
-{
- struct ath_rate_softc *asc = sc->sc_rc;
-
- /* For half and quarter rate channles use different
- * rate tables
- */
- if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF)
- ar5416_sethalf_ratetable(asc);
- else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER)
- ar5416_setquarter_ratetable(asc);
- else /* full rate */
- ar5416_setfull_ratetable(asc);
-
- if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) {
- asc->fixedrix =
- sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff];
- /* NB: check the fixed rate exists */
- if (asc->fixedrix == 0xff)
- asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
- } else {
- asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
- }
+ return hi;
}
static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
int probe_allowed, int *is_probing,
int is_retry)
{
u32 dt, best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
int8_t rssi_last, rssi_reduce = 0, index = 0;
- struct ath_tx_ratectrl *rate_ctrl = NULL;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ?
- (ath_rc_priv) : NULL);
- *is_probing = FALSE;
+ *is_probing = 0;
- rssi_last = median(rate_ctrl->rssi_last,
- rate_ctrl->rssi_last_prev,
- rate_ctrl->rssi_last_prev2);
+ rssi_last = median(ath_rc_priv->rssi_last,
+ ath_rc_priv->rssi_last_prev,
+ ath_rc_priv->rssi_last_prev2);
/*
* Age (reduce) last ack rssi based on how old it is.
@@ -896,7 +659,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
*/
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - rate_ctrl->rssi_time;
+ dt = now_msec - ath_rc_priv->rssi_time;
if (dt >= 185)
rssi_reduce = 10;
@@ -915,7 +678,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
*/
best_thruput = 0;
- maxindex = rate_ctrl->max_valid_rate-1;
+ maxindex = ath_rc_priv->max_valid_rate-1;
minindex = 0;
best_rate = minindex;
@@ -927,8 +690,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
for (index = maxindex; index >= minindex ; index--) {
u8 per_thres;
- rate = rate_ctrl->valid_rate_index[index];
- if (rate > rate_ctrl->rate_max_phy)
+ rate = ath_rc_priv->valid_rate_index[index];
+ if (rate > ath_rc_priv->rate_max_phy)
continue;
/*
@@ -942,7 +705,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = rate_ctrl->state[rate].per;
+ per_thres = ath_rc_priv->state[rate].per;
if (per_thres < 12)
per_thres = 12;
@@ -961,41 +724,35 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* of max retries, use the min rate for the next retry
*/
if (is_retry)
- rate = rate_ctrl->valid_rate_index[minindex];
+ rate = ath_rc_priv->valid_rate_index[minindex];
- rate_ctrl->rssi_last_lookup = rssi_last;
+ ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
* non-monoticity of 11g's rate table
*/
- if (rate >= rate_ctrl->rate_max_phy && probe_allowed) {
- rate = rate_ctrl->rate_max_phy;
+ if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) {
+ rate = ath_rc_priv->rate_max_phy;
/* Probe the next allowed phy state */
/* FIXME:XXXX Check to make sure ratMax is checked properly */
if (ath_rc_get_nextvalid_txrate(rate_table,
- rate_ctrl, rate, &next_rate) &&
- (now_msec - rate_ctrl->probe_time >
+ ath_rc_priv, rate, &next_rate) &&
+ (now_msec - ath_rc_priv->probe_time >
rate_table->probe_interval) &&
- (rate_ctrl->hw_maxretry_pktcnt >= 1)) {
+ (ath_rc_priv->hw_maxretry_pktcnt >= 1)) {
rate = next_rate;
- rate_ctrl->probe_rate = rate;
- rate_ctrl->probe_time = now_msec;
- rate_ctrl->hw_maxretry_pktcnt = 0;
- *is_probing = TRUE;
+ ath_rc_priv->probe_rate = rate;
+ ath_rc_priv->probe_time = now_msec;
+ ath_rc_priv->hw_maxretry_pktcnt = 0;
+ *is_probing = 1;
}
}
- /*
- * Make sure rate is not higher than the allowed maximum.
- * We should also enforce the min, but I suspect the min is
- * normally 1 rather than 0 because of the rate 9 vs 6 issue
- * in the old code.
- */
- if (rate > (rate_ctrl->rate_table_size - 1))
- rate = rate_ctrl->rate_table_size - 1;
+ if (rate > (ath_rc_priv->rate_table_size - 1))
+ rate = ath_rc_priv->rate_table_size - 1;
ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
(rate_table->info[rate].valid_single_stream &&
@@ -1004,40 +761,36 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
return rate;
}
-static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table ,
- struct ath_rc_series *series,
- u8 tries,
- u8 rix,
- int rtsctsenable)
+static void ath_rc_rate_set_series(struct ath_rate_table *rate_table ,
+ struct ieee80211_tx_rate *rate,
+ u8 tries, u8 rix, int rtsctsenable)
{
- series->tries = tries;
- series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) |
- (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ?
- ATH_RC_DS_FLAG : 0) |
- (WLAN_RC_PHY_40(rate_table->info[rix].phy) ?
- ATH_RC_CW40_FLAG : 0) |
- (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ?
- ATH_RC_SGI_FLAG : 0);
-
- series->rix = rate_table->info[rix].base_index;
- series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen;
+ rate->count = tries;
+ rate->idx = rix;
+
+ if (rtsctsenable)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (WLAN_RC_PHY_HT(rate_table->info[rix].phy))
+ rate->flags |= IEEE80211_TX_RC_MCS;
}
static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_rate_table *rate_table,
u8 rix, u16 stepdown,
u16 min_rate)
{
u32 j;
u8 nextindex;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)(ath_rc_priv);
if (min_rate) {
for (j = RATE_TABLE_SIZE; j > 0; j--) {
if (ath_rc_get_nextlowervalid_txrate(rate_table,
- rate_ctrl, rix, &nextindex))
+ ath_rc_priv, rix, &nextindex))
rix = nextindex;
else
break;
@@ -1045,7 +798,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
} else {
for (j = stepdown; j > 0; j--) {
if (ath_rc_get_nextlowervalid_txrate(rate_table,
- rate_ctrl, rix, &nextindex))
+ ath_rc_priv, rix, &nextindex))
rix = nextindex;
else
break;
@@ -1055,41 +808,39 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc,
}
static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- int num_tries, int num_rates, unsigned int rcflag,
- struct ath_rc_series series[], int *is_probe,
+ struct ath_rate_priv *ath_rc_priv,
+ int num_tries, int num_rates,
+ struct ieee80211_tx_info *tx_info, int *is_probe,
int is_retry)
{
u8 try_per_rate = 0, i = 0, rix, nrix;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
struct ath_rate_table *rate_table;
+ struct ieee80211_tx_rate *rates = tx_info->control.rates;
- rate_table =
- (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
- (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
+ rate_table = sc->cur_rate_table;
+ rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1,
is_probe, is_retry);
nrix = rix;
- if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) {
+ if (*is_probe) {
/* set one try for probe rates. For the
* probes don't enable rts */
ath_rc_rate_set_series(rate_table,
- &series[i++], 1, nrix, FALSE);
+ &rates[i++], 1, nrix, 0);
try_per_rate = (num_tries/num_rates);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
nrix = ath_rc_rate_getidx(sc,
- ath_rc_priv, rate_table, nrix, 1, FALSE);
+ ath_rc_priv, rate_table, nrix, 1, 0);
ath_rc_rate_set_series(rate_table,
- &series[i++], try_per_rate, nrix, 0);
+ &rates[i++], try_per_rate, nrix, 0);
} else {
try_per_rate = (num_tries/num_rates);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table,
- &series[i++], try_per_rate, nrix, FALSE);
+ &rates[i++], try_per_rate, nrix, 0);
}
/* Fill in the other rates for multirate retry */
@@ -1099,14 +850,13 @@ static void ath_rc_ratefind(struct ath_softc *sc,
try_num = ((i + 1) == num_rates) ?
num_tries - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == num_rates) &&
- (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
+ min_rate = (((i + 1) == num_rates) && 0);
nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
rate_table, nrix, 1, min_rate);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table,
- &series[i], try_num, nrix, TRUE);
+ &rates[i], try_num, nrix, 1);
}
/*
@@ -1124,115 +874,29 @@ static void ath_rc_ratefind(struct ath_softc *sc,
* So, set fourth rate in series to be same as third one for
* above conditions.
*/
- if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) ||
- (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
- (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
- u8 dot11rate = rate_table->info[rix].dot11rate;
+ if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) &&
+ (sc->hw->conf.ht.enabled)) {
+ u8 dot11rate = rate_table->info[rix].dot11rate;
u8 phy = rate_table->info[rix].phy;
if (i == 4 &&
((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
(dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
- series[3].rix = series[2].rix;
- series[3].flags = series[2].flags;
- series[3].max_4ms_framelen = series[2].max_4ms_framelen;
- }
- }
-}
-
-/*
- * Return the Tx rate series.
- */
-static void ath_rate_findrate(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- int num_tries,
- int num_rates,
- unsigned int rcflag,
- struct ath_rc_series series[],
- int *is_probe,
- int is_retry)
-{
- struct ath_vap *avp = ath_rc_priv->avp;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- if (!num_rates || !num_tries)
- return;
-
- if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) {
- ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates,
- rcflag, series, is_probe, is_retry);
- } else {
- /* Fixed rate */
- int idx;
- u8 flags;
- u32 rix;
- struct ath_rate_softc *asc = ath_rc_priv->asc;
- struct ath_rate_table *rate_table;
-
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
-
- for (idx = 0; idx < 4; idx++) {
- unsigned int mcs;
- u8 series_rix = 0;
-
- series[idx].tries = IEEE80211_RATE_IDX_ENTRY(
- avp->av_config.av_fixed_retryset, idx);
-
- mcs = IEEE80211_RATE_IDX_ENTRY(
- avp->av_config.av_fixed_rateset, idx);
-
- if (idx == 3 && (mcs & 0xf0) == 0x70)
- mcs = (mcs & ~0xf0)|0x80;
-
- if (!(mcs & 0x80))
- flags = 0;
- else
- flags = ((ath_rc_priv->ht_cap &
- WLAN_RC_DS_FLAG) ?
- ATH_RC_DS_FLAG : 0) |
- ((ath_rc_priv->ht_cap &
- WLAN_RC_40_FLAG) ?
- ATH_RC_CW40_FLAG : 0) |
- ((ath_rc_priv->ht_cap &
- WLAN_RC_SGI_FLAG) ?
- ((ath_rc_priv->ht_cap &
- WLAN_RC_40_FLAG) ?
- ATH_RC_SGI_FLAG : 0) : 0);
-
- series[idx].rix = sc->sc_rixmap[mcs];
- series_rix = series[idx].rix;
-
- /* XXX: Give me some cleanup love */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[series_rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[series_rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[series_rix].cw40index;
- else
- rix = rate_table->info[series_rix].base_index;
- series[idx].max_4ms_framelen =
- rate_table->info[rix].max_4ms_framelen;
- series[idx].flags = flags;
+ rates[3].idx = rates[2].idx;
+ rates[3].flags = rates[2].flags;
}
}
}
-static void ath_rc_update_ht(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- struct ath_tx_info_priv *info_priv,
- int tx_rate, int xretries, int retries)
+static bool ath_rc_update_per(struct ath_softc *sc,
+ struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_tx_info_priv *tx_info_priv,
+ int tx_rate, int xretries, int retries,
+ u32 now_msec)
{
- struct ath_tx_ratectrl *rate_ctrl;
- u32 now_msec = jiffies_to_msecs(jiffies);
- int state_change = FALSE, rate, count;
+ bool state_change = false;
+ int count;
u8 last_per;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
- struct ath_rate_table *rate_table =
- (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
-
static u32 nretry_to_per_lookup[10] = {
100 * 0 / 1,
100 * 1 / 4,
@@ -1246,56 +910,35 @@ static void ath_rc_update_ht(struct ath_softc *sc,
100 * 9 / 10
};
- if (!ath_rc_priv)
- return;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
-
- ASSERT(tx_rate >= 0);
- if (tx_rate < 0)
- return;
-
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- info_priv->tx.ts_rssi =
- info_priv->tx.ts_rssi < 3 ? 0 :
- info_priv->tx.ts_rssi - 3;
-
- last_per = rate_ctrl->state[tx_rate].per;
+ last_per = ath_rc_priv->state[tx_rate].per;
if (xretries) {
- /* Update the PER. */
if (xretries == 1) {
- rate_ctrl->state[tx_rate].per += 30;
- if (rate_ctrl->state[tx_rate].per > 100)
- rate_ctrl->state[tx_rate].per = 100;
+ ath_rc_priv->state[tx_rate].per += 30;
+ if (ath_rc_priv->state[tx_rate].per > 100)
+ ath_rc_priv->state[tx_rate].per = 100;
} else {
/* xretries == 2 */
- count = sizeof(nretry_to_per_lookup) /
- sizeof(nretry_to_per_lookup[0]);
+ count = ARRAY_SIZE(nretry_to_per_lookup);
if (retries >= count)
retries = count - 1;
+
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- rate_ctrl->state[tx_rate].per =
- (u8)(rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- ((100) >> 3));
+ ath_rc_priv->state[tx_rate].per =
+ (u8)(last_per - (last_per >> 3) + (100 >> 3));
}
/* xretries == 1 or 2 */
- if (rate_ctrl->probe_rate == tx_rate)
- rate_ctrl->probe_rate = 0;
+ if (ath_rc_priv->probe_rate == tx_rate)
+ ath_rc_priv->probe_rate = 0;
- } else { /* xretries == 0 */
- /* Update the PER. */
- /* Make sure it doesn't index out of array's bounds. */
- count = sizeof(nretry_to_per_lookup) /
- sizeof(nretry_to_per_lookup[0]);
+ } else { /* xretries == 0 */
+ count = ARRAY_SIZE(nretry_to_per_lookup);
if (retries >= count)
retries = count - 1;
- if (info_priv->n_bad_frames) {
+
+ if (tx_info_priv->n_bad_frames) {
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
* Assuming that n_frames is not 0. The current PER
* from the retries is 100 * retries / (retries+1),
@@ -1308,37 +951,35 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* the above PER. The expression below is a
* simplified version of the sum of these two terms.
*/
- if (info_priv->n_frames > 0)
- rate_ctrl->state[tx_rate].per
- = (u8)
- (rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- ((100*(retries*info_priv->n_frames +
- info_priv->n_bad_frames) /
- (info_priv->n_frames *
- (retries+1))) >> 3));
+ if (tx_info_priv->n_frames > 0) {
+ int n_frames, n_bad_frames;
+ u8 cur_per, new_per;
+
+ n_bad_frames = retries * tx_info_priv->n_frames +
+ tx_info_priv->n_bad_frames;
+ n_frames = tx_info_priv->n_frames * (retries + 1);
+ cur_per = (100 * n_bad_frames / n_frames) >> 3;
+ new_per = (u8)(last_per - (last_per >> 3) + cur_per);
+ ath_rc_priv->state[tx_rate].per = new_per;
+ }
} else {
- /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
-
- rate_ctrl->state[tx_rate].per = (u8)
- (rate_ctrl->state[tx_rate].per -
- (rate_ctrl->state[tx_rate].per >> 3) +
- (nretry_to_per_lookup[retries] >> 3));
+ ath_rc_priv->state[tx_rate].per =
+ (u8)(last_per - (last_per >> 3) +
+ (nretry_to_per_lookup[retries] >> 3));
}
- rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev;
- rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last;
- rate_ctrl->rssi_last = info_priv->tx.ts_rssi;
- rate_ctrl->rssi_time = now_msec;
+ ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
+ ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
+ ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
+ ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
* this was a probe. Otherwise, ignore the probe.
*/
-
- if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) {
- if (retries > 0 || 2 * info_priv->n_bad_frames >
- info_priv->n_frames) {
+ if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
+ if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
+ tx_info_priv->n_frames) {
/*
* Since we probed with just a single attempt,
* any retries means the probe failed. Also,
@@ -1346,17 +987,18 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* the subframes were bad then also consider
* the probe a failure.
*/
- rate_ctrl->probe_rate = 0;
+ ath_rc_priv->probe_rate = 0;
} else {
u8 probe_rate = 0;
- rate_ctrl->rate_max_phy = rate_ctrl->probe_rate;
- probe_rate = rate_ctrl->probe_rate;
+ ath_rc_priv->rate_max_phy =
+ ath_rc_priv->probe_rate;
+ probe_rate = ath_rc_priv->probe_rate;
- if (rate_ctrl->state[probe_rate].per > 30)
- rate_ctrl->state[probe_rate].per = 20;
+ if (ath_rc_priv->state[probe_rate].per > 30)
+ ath_rc_priv->state[probe_rate].per = 20;
- rate_ctrl->probe_rate = 0;
+ ath_rc_priv->probe_rate = 0;
/*
* Since this probe succeeded, we allow the next
@@ -1364,8 +1006,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* to move up faster if the probes are
* succesful.
*/
- rate_ctrl->probe_time = now_msec -
- rate_table->probe_interval / 2;
+ ath_rc_priv->probe_time =
+ now_msec - rate_table->probe_interval / 2;
}
}
@@ -1375,74 +1017,114 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* this was because of collisions or poor signal.
*
* Later: if rssi_ack is close to
- * rate_ctrl->state[txRate].rssi_thres and we see lots
+ * ath_rc_priv->state[txRate].rssi_thres and we see lots
* of retries, then we could increase
- * rate_ctrl->state[txRate].rssi_thres.
+ * ath_rc_priv->state[txRate].rssi_thres.
*/
- rate_ctrl->hw_maxretry_pktcnt = 0;
+ ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
+ int32_t rssi_ackAvg;
+ int8_t rssi_thres;
+ int8_t rssi_ack_vmin;
+
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
*/
- if (tx_rate == rate_ctrl->rate_max_phy &&
- rate_ctrl->hw_maxretry_pktcnt < 255) {
- rate_ctrl->hw_maxretry_pktcnt++;
+ if (tx_rate == ath_rc_priv->rate_max_phy &&
+ ath_rc_priv->hw_maxretry_pktcnt < 255) {
+ ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (info_priv->tx.ts_rssi >=
- rate_table->info[tx_rate].rssi_ack_validmin) {
- /* Average the rssi */
- if (tx_rate != rate_ctrl->rssi_sum_rate) {
- rate_ctrl->rssi_sum_rate = tx_rate;
- rate_ctrl->rssi_sum =
- rate_ctrl->rssi_sum_cnt = 0;
- }
+ if (tx_info_priv->tx.ts_rssi <
+ rate_table->info[tx_rate].rssi_ack_validmin)
+ goto exit;
- rate_ctrl->rssi_sum += info_priv->tx.ts_rssi;
- rate_ctrl->rssi_sum_cnt++;
-
- if (rate_ctrl->rssi_sum_cnt > 4) {
- int32_t rssi_ackAvg =
- (rate_ctrl->rssi_sum + 2) / 4;
- int8_t rssi_thres =
- rate_ctrl->state[tx_rate].
- rssi_thres;
- int8_t rssi_ack_vmin =
- rate_table->info[tx_rate].
- rssi_ack_validmin;
-
- rate_ctrl->rssi_sum =
- rate_ctrl->rssi_sum_cnt = 0;
-
- /* Now reduce the current
- * rssi threshold. */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- rate_ctrl->state[tx_rate].
- rssi_thres--;
- }
-
- state_change = TRUE;
- }
+ /* Average the rssi */
+ if (tx_rate != ath_rc_priv->rssi_sum_rate) {
+ ath_rc_priv->rssi_sum_rate = tx_rate;
+ ath_rc_priv->rssi_sum =
+ ath_rc_priv->rssi_sum_cnt = 0;
}
+
+ ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
+ ath_rc_priv->rssi_sum_cnt++;
+
+ if (ath_rc_priv->rssi_sum_cnt < 4)
+ goto exit;
+
+ rssi_ackAvg =
+ (ath_rc_priv->rssi_sum + 2) / 4;
+ rssi_thres =
+ ath_rc_priv->state[tx_rate].rssi_thres;
+ rssi_ack_vmin =
+ rate_table->info[tx_rate].rssi_ack_validmin;
+
+ ath_rc_priv->rssi_sum =
+ ath_rc_priv->rssi_sum_cnt = 0;
+
+ /* Now reduce the current rssi threshold */
+ if ((rssi_ackAvg < rssi_thres + 2) &&
+ (rssi_thres > rssi_ack_vmin)) {
+ ath_rc_priv->state[tx_rate].rssi_thres--;
+ }
+
+ state_change = true;
}
}
+exit:
+ return state_change;
+}
+
+/* Update PER, RSSI and whatever else that the code thinks it is doing.
+ If you can make sense of all this, you really need to go out more. */
+
+static void ath_rc_update_ht(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ath_tx_info_priv *tx_info_priv,
+ int tx_rate, int xretries, int retries)
+{
+#define CHK_RSSI(rate) \
+ ((ath_rc_priv->state[(rate)].rssi_thres + \
+ rate_table->info[(rate)].rssi_ack_deltamin) > \
+ ath_rc_priv->state[(rate)+1].rssi_thres)
- /* For all cases */
+ u32 now_msec = jiffies_to_msecs(jiffies);
+ int rate;
+ u8 last_per;
+ bool state_change = false;
+ struct ath_rate_table *rate_table = sc->cur_rate_table;
+ int size = ath_rc_priv->rate_table_size;
+
+ if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
+ return;
+
+ /* To compensate for some imbalance between ctrl and ext. channel */
+
+ if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
+ tx_info_priv->tx.ts_rssi =
+ tx_info_priv->tx.ts_rssi < 3 ? 0 :
+ tx_info_priv->tx.ts_rssi - 3;
+
+ last_per = ath_rc_priv->state[tx_rate].per;
+
+ /* Update PER first */
+ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
+ tx_info_priv, tx_rate, xretries,
+ retries, now_msec);
/*
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
- rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
- (u8) tx_rate, &rate_ctrl->rate_max_phy);
+ rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
+ ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
- rate_ctrl->probe_time = now_msec;
+ ath_rc_priv->probe_time = now_msec;
}
if (state_change) {
@@ -1453,20 +1135,15 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* made to keep the rssi thresholds monotonically
* increasing between the CCK and OFDM rates.)
*/
- for (rate = tx_rate; rate <
- rate_ctrl->rate_table_size - 1; rate++) {
+ for (rate = tx_rate; rate < size - 1; rate++) {
if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
+ rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin >
- rate_ctrl->state[rate+1].rssi_thres) {
- rate_ctrl->state[rate+1].rssi_thres =
- rate_ctrl->state[rate].
- rssi_thres +
- rate_table->info[rate].
- rssi_ack_deltamin;
+ if (CHK_RSSI(rate)) {
+ ath_rc_priv->state[rate+1].rssi_thres =
+ ath_rc_priv->state[rate].rssi_thres +
+ rate_table->info[rate].rssi_ack_deltamin;
}
}
@@ -1476,27 +1153,20 @@ static void ath_rc_update_ht(struct ath_softc *sc,
rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin >
- rate_ctrl->state[rate+1].rssi_thres) {
- if (rate_ctrl->state[rate+1].rssi_thres <
- rate_table->info[rate].
- rssi_ack_deltamin)
- rate_ctrl->state[rate].rssi_thres = 0;
+ if (CHK_RSSI(rate)) {
+ if (ath_rc_priv->state[rate+1].rssi_thres <
+ rate_table->info[rate].rssi_ack_deltamin)
+ ath_rc_priv->state[rate].rssi_thres = 0;
else {
- rate_ctrl->state[rate].rssi_thres =
- rate_ctrl->state[rate+1].
- rssi_thres -
- rate_table->info[rate].
- rssi_ack_deltamin;
+ ath_rc_priv->state[rate].rssi_thres =
+ ath_rc_priv->state[rate+1].rssi_thres -
+ rate_table->info[rate].rssi_ack_deltamin;
}
- if (rate_ctrl->state[rate].rssi_thres <
- rate_table->info[rate].
- rssi_ack_validmin) {
- rate_ctrl->state[rate].rssi_thres =
- rate_table->info[rate].
- rssi_ack_validmin;
+ if (ath_rc_priv->state[rate].rssi_thres <
+ rate_table->info[rate].rssi_ack_validmin) {
+ ath_rc_priv->state[rate].rssi_thres =
+ rate_table->info[rate].rssi_ack_validmin;
}
}
}
@@ -1504,74 +1174,86 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (rate_ctrl->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->state[tx_rate].per < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
break;
- if (rate_ctrl->state[rate].per >
- rate_ctrl->state[rate+1].per) {
- rate_ctrl->state[rate].per =
- rate_ctrl->state[rate+1].per;
+ if (ath_rc_priv->state[rate].per >
+ ath_rc_priv->state[rate+1].per) {
+ ath_rc_priv->state[rate].per =
+ ath_rc_priv->state[rate+1].per;
}
}
}
/* Maintain monotonicity for rates above the current rate */
- for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) {
- if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per)
- rate_ctrl->state[rate+1].per =
- rate_ctrl->state[rate].per;
+ for (rate = tx_rate; rate < size - 1; rate++) {
+ if (ath_rc_priv->state[rate+1].per <
+ ath_rc_priv->state[rate].per)
+ ath_rc_priv->state[rate+1].per =
+ ath_rc_priv->state[rate].per;
}
/* Every so often, we reduce the thresholds and
* PER (different for CCK and OFDM). */
- if (now_msec - rate_ctrl->rssi_down_time >=
+ if (now_msec - ath_rc_priv->rssi_down_time >=
rate_table->rssi_reduce_interval) {
- for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
- if (rate_ctrl->state[rate].rssi_thres >
+ for (rate = 0; rate < size; rate++) {
+ if (ath_rc_priv->state[rate].rssi_thres >
rate_table->info[rate].rssi_ack_validmin)
- rate_ctrl->state[rate].rssi_thres -= 1;
+ ath_rc_priv->state[rate].rssi_thres -= 1;
}
- rate_ctrl->rssi_down_time = now_msec;
+ ath_rc_priv->rssi_down_time = now_msec;
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
- if (now_msec - rate_ctrl->per_down_time >=
+ if (now_msec - ath_rc_priv->per_down_time >=
rate_table->rssi_reduce_interval) {
- for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
- rate_ctrl->state[rate].per =
- 7 * rate_ctrl->state[rate].per / 8;
+ for (rate = 0; rate < size; rate++) {
+ ath_rc_priv->state[rate].per =
+ 7 * ath_rc_priv->state[rate].per / 8;
}
- rate_ctrl->per_down_time = now_msec;
+ ath_rc_priv->per_down_time = now_msec;
}
+
+#undef CHK_RSSI
}
-/*
- * This routine is called in rate control callback tx_status() to give
- * the status of previous frames.
- */
-static void ath_rc_update(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- struct ath_tx_info_priv *info_priv, int final_ts_idx,
- int xretries, int long_retry)
+static int ath_rc_get_rateindex(struct ath_rate_table *rate_table,
+ struct ieee80211_tx_rate *rate)
{
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ int rix;
+
+ if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (rate->flags & IEEE80211_TX_RC_SHORT_GI))
+ rix = rate_table->info[rate->idx].ht_index;
+ else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ rix = rate_table->info[rate->idx].sgi_index;
+ else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rix = rate_table->info[rate->idx].cw40index;
+ else
+ rix = rate_table->info[rate->idx].base_index;
+
+ return rix;
+}
+
+static void ath_rc_tx_status(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ieee80211_tx_info *tx_info,
+ int final_ts_idx, int xretries, int long_retry)
+{
+ struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
struct ath_rate_table *rate_table;
- struct ath_tx_ratectrl *rate_ctrl;
- struct ath_rc_series rcs[4];
+ struct ieee80211_tx_rate *rates = tx_info->status.rates;
u8 flags;
- u32 series = 0, rix;
+ u32 i = 0, rix;
- memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0]));
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
- ASSERT(rcs[0].tries != 0);
+ rate_table = sc->cur_rate_table;
/*
* If the first rate is not the final index, there
@@ -1579,32 +1261,22 @@ static void ath_rc_update(struct ath_softc *sc,
*/
if (final_ts_idx != 0) {
/* Process intermediate rates that failed.*/
- for (series = 0; series < final_ts_idx ; series++) {
- if (rcs[series].tries != 0) {
- flags = rcs[series].flags;
+ for (i = 0; i < final_ts_idx ; i++) {
+ if (rates[i].count != 0 && (rates[i].idx >= 0)) {
+ flags = rates[i].flags;
+
/* If HT40 and we have switched mode from
* 40 to 20 => don't update */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (rate_ctrl->rc_phy_mode !=
- (flags & ATH_RC_CW40_FLAG)))
+
+ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG))
return;
- if ((flags & ATH_RC_CW40_FLAG) &&
- (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[
- rcs[series].rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[
- rcs[series].rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[
- rcs[series].rix].cw40index;
- else
- rix = rate_table->info[
- rcs[series].rix].base_index;
+
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
ath_rc_update_ht(sc, ath_rc_priv,
- info_priv, rix,
+ tx_info_priv, rix,
xretries ? 1 : 2,
- rcs[series].tries);
+ rates[i].count);
}
}
} else {
@@ -1614,240 +1286,152 @@ static void ath_rc_update(struct ath_softc *sc,
* Treating it as an excessive retry penalizes the rate
* inordinately.
*/
- if (rcs[0].tries == 1 && xretries == 1)
+ if (rates[0].count == 1 && xretries == 1)
xretries = 2;
}
- flags = rcs[series].flags;
+ flags = rates[i].flags;
+
/* If HT40 and we have switched mode from 40 to 20 => don't update */
- if ((flags & ATH_RC_CW40_FLAG) &&
- (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG)))
+ if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+ (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) {
return;
+ }
- if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG))
- rix = rate_table->info[rcs[series].rix].ht_index;
- else if (flags & ATH_RC_SGI_FLAG)
- rix = rate_table->info[rcs[series].rix].sgi_index;
- else if (flags & ATH_RC_CW40_FLAG)
- rix = rate_table->info[rcs[series].rix].cw40index;
- else
- rix = rate_table->info[rcs[series].rix].base_index;
-
- ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix,
- xretries, long_retry);
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+ ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
+ xretries, long_retry);
}
-/*
- * Process a tx descriptor for a completed transmit (success or failure).
- */
-static void ath_rate_tx_complete(struct ath_softc *sc,
- struct ath_node *an,
- struct ath_rate_node *rc_priv,
- struct ath_tx_info_priv *info_priv)
+static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
+ enum ieee80211_band band,
+ bool is_ht, bool is_cw_40)
{
- int final_ts_idx = info_priv->tx.ts_rateindex;
- int tx_status = 0, is_underrun = 0;
- struct ath_vap *avp;
-
- avp = rc_priv->avp;
- if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) ||
- (info_priv->tx.ts_status & ATH9K_TXERR_FILT))
- return;
-
- if (info_priv->tx.ts_rssi > 0) {
- ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
- info_priv->tx.ts_rssi);
- }
-
- /*
- * If underrun error is seen assume it as an excessive retry only
- * if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
- * times. This affects how ratectrl updates PER for the failed rate.
- */
- if (info_priv->tx.ts_flags &
- (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
- ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) {
- tx_status = 1;
- is_underrun = 1;
+ int mode = 0;
+
+ switch(band) {
+ case IEEE80211_BAND_2GHZ:
+ mode = ATH9K_MODE_11G;
+ if (is_ht)
+ mode = ATH9K_MODE_11NG_HT20;
+ if (is_cw_40)
+ mode = ATH9K_MODE_11NG_HT40PLUS;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ mode = ATH9K_MODE_11A;
+ if (is_ht)
+ mode = ATH9K_MODE_11NA_HT20;
+ if (is_cw_40)
+ mode = ATH9K_MODE_11NA_HT40PLUS;
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n");
+ return NULL;
}
- if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
- (info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
- tx_status = 1;
+ BUG_ON(mode >= ATH9K_MODE_MAX);
- ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
- info_priv->tx.ts_longretry);
+ DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode);
+ return sc->hw_rate_table[mode];
}
-/*
- * Update the SIB's rate control information
- *
- * This should be called when the supported rates change
- * (e.g. SME operation, wireless mode change)
- *
- * It will determine which rates are valid for use.
- */
-static void ath_rc_sib_update(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- u32 capflag, int keep_state,
- struct ath_rateset *negotiated_rates,
- struct ath_rateset *negotiated_htrates)
+static void ath_rc_init(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta)
{
struct ath_rate_table *rate_table = NULL;
- struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
- struct ath_rateset *rateset = negotiated_rates;
- u8 *ht_mcs = (u8 *)negotiated_htrates;
- struct ath_tx_ratectrl *rate_ctrl =
- (struct ath_tx_ratectrl *)ath_rc_priv;
+ struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
+ u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
u8 i, j, k, hi = 0, hthi = 0;
- rate_table = (struct ath_rate_table *)
- asc->hw_rate_table[sc->sc_curmode];
+ /* FIXME: Adhoc */
+ if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) ||
+ (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) {
+ bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ rate_table = ath_choose_rate_table(sc, sband->band,
+ sta->ht_cap.ht_supported,
+ is_cw_40);
+ } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) {
+ /* cur_rate_table would be set on init through config() */
+ rate_table = sc->cur_rate_table;
+ }
+
+ if (!rate_table) {
+ DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+ return;
+ }
+
+ if (sta->ht_cap.ht_supported) {
+ ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
+ }
/* Initial rate table size. Will change depending
* on the working rate set */
- rate_ctrl->rate_table_size = MAX_TX_RATE_TBL;
+ ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
/* Initialize thresholds according to the global rate table */
- for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) {
- rate_ctrl->state[i].rssi_thres =
+ for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
+ ath_rc_priv->state[i].rssi_thres =
rate_table->info[i].rssi_ack_validmin;
- rate_ctrl->state[i].per = 0;
+ ath_rc_priv->state[i].per = 0;
}
/* Determine the valid rates */
- ath_rc_init_valid_txmask(rate_ctrl);
+ ath_rc_init_valid_txmask(ath_rc_priv);
for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < MAX_TX_RATE_PHY; j++)
- rate_ctrl->valid_phy_rateidx[i][j] = 0;
- rate_ctrl->valid_phy_ratecnt[i] = 0;
+ ath_rc_priv->valid_phy_rateidx[i][j] = 0;
+ ath_rc_priv->valid_phy_ratecnt[i] = 0;
}
- rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG);
+ ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
/* Set stream capability */
- ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
+ ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
if (!rateset->rs_nrates) {
/* No working rate, just initialize valid rates */
- hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table,
- capflag);
+ hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
+ ath_rc_priv->ht_cap);
} else {
/* Use intersection of working rates and valid rates */
- hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table,
- rateset, capflag);
- if (capflag & WLAN_RC_HT_FLAG) {
- hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv,
+ hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
+ rateset, ath_rc_priv->ht_cap);
+ if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) {
+ hthi = ath_rc_setvalid_htrates(ath_rc_priv,
rate_table,
ht_mcs,
- capflag);
+ ath_rc_priv->ht_cap);
}
hi = A_MAX(hi, hthi);
}
- rate_ctrl->rate_table_size = hi + 1;
- rate_ctrl->rate_max_phy = 0;
- ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
+ ath_rc_priv->rate_table_size = hi + 1;
+ ath_rc_priv->rate_max_phy = 0;
+ ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
- for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) {
- rate_ctrl->valid_rate_index[k++] =
- rate_ctrl->valid_phy_rateidx[i][j];
+ for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
+ ath_rc_priv->valid_rate_index[k++] =
+ ath_rc_priv->valid_phy_rateidx[i][j];
}
- if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE)
- || !rate_ctrl->valid_phy_ratecnt[i])
+ if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1)
+ || !ath_rc_priv->valid_phy_ratecnt[i])
continue;
- rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1];
+ ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
}
- ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
- ASSERT(k <= MAX_TX_RATE_TBL);
-
- rate_ctrl->max_valid_rate = k;
- /*
- * Some third party vendors don't send the supported rate series in
- * order. So sorting to make sure its in order, otherwise our RateFind
- * Algo will select wrong rates
- */
- ath_rc_sort_validrates(rate_table, rate_ctrl);
- rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4];
-}
-
-/*
- * Update rate-control state on station associate/reassociate.
- */
-static int ath_rate_newassoc(struct ath_softc *sc,
- struct ath_rate_node *ath_rc_priv,
- unsigned int capflag,
- struct ath_rateset *negotiated_rates,
- struct ath_rateset *negotiated_htrates)
-{
-
-
- ath_rc_priv->ht_cap =
- ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
- ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) |
- ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) |
- ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0);
-
- ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0,
- negotiated_rates, negotiated_htrates);
-
- return 0;
-}
-
-/*
- * This routine is called to initialize the rate control parameters
- * in the SIB. It is called initially during system initialization
- * or when a station is associated with the AP.
- */
-static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
-{
- struct ath_tx_ratectrl *rate_ctrl;
-
- rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
- rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies);
-}
-
-
-static void ath_setup_rates(struct ath_softc *sc,
- struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta,
- struct ath_rate_node *rc_priv)
-
-{
- int i, j = 0;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sta->supp_rates[sband->band] & BIT(i)) {
- rc_priv->neg_rates.rs_rates[j]
- = (sband->bitrates[i].bitrate * 2) / 10;
- j++;
- }
- }
- rc_priv->neg_rates.rs_nrates = j;
-}
-
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
-{
- struct ath_softc *sc = hw->priv;
- u32 capflag = 0;
-
- if (hw->conf.ht_conf.ht_supported) {
- capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
- if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
- capflag |= ATH_RC_CW40_FLAG;
- }
-
- ath_rate_newassoc(sc, rc_priv, capflag,
- &rc_priv->neg_rates,
- &rc_priv->neg_ht_rates);
+ ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
+ ASSERT(k <= RATE_TABLE_SIZE);
+ ath_rc_priv->max_valid_rate = k;
+ ath_rc_sort_validrates(rate_table, ath_rc_priv);
+ ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
+ sc->cur_rate_table = rate_table;
}
/* Rate Control callbacks */
@@ -1856,163 +1440,88 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct sk_buff *skb)
{
struct ath_softc *sc = priv;
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_node *an;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
+ struct ath_tx_info_priv *tx_info_priv = NULL;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
+ int final_ts_idx, tx_status = 0, is_underrun = 0;
__le16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+ tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ final_ts_idx = tx_info_priv->tx.ts_rateindex;
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, hdr->addr1);
- spin_unlock_bh(&sc->node_lock);
+ if (!priv_sta || !ieee80211_is_data(fc) ||
+ !tx_info_priv->update_rc)
+ goto exit;
- if (!an || !priv_sta || !ieee80211_is_data(fc)) {
- if (tx_info->driver_data[0] != NULL) {
- kfree(tx_info->driver_data[0]);
- tx_info->driver_data[0] = NULL;
- }
- return;
- }
- if (tx_info->driver_data[0] != NULL) {
- ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
- kfree(tx_info->driver_data[0]);
- tx_info->driver_data[0] = NULL;
- }
-}
-
-static void ath_tx_aggr_resp(struct ath_softc *sc,
- struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta,
- struct ath_node *an,
- u8 tidno)
-{
- struct ath_atx_tid *txtid;
- u16 buffersize = 0;
- int state;
- struct sta_info *si;
-
- if (!(sc->sc_flags & SC_OP_TXAGGR))
- return;
-
- txtid = ATH_AN_2_TID(an, tidno);
- if (!txtid->paused)
- return;
+ if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+ goto exit;
/*
- * XXX: This is entirely busted, we aren't supposed to
- * access the sta from here because it's internal
- * to mac80211, and looking at the state without
- * locking is wrong too.
+ * If underrun error is seen assume it as an excessive retry only
+ * if prefetch trigger level have reached the max (0x3f for 5416)
+ * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * times. This affects how ratectrl updates PER for the failed rate.
*/
- si = container_of(sta, struct sta_info, sta);
- buffersize = IEEE80211_MIN_AMPDU_BUF <<
- sband->ht_info.ampdu_factor; /* FIXME */
- state = si->ampdu_mlme.tid_state_tx[tidno];
-
- if (state & HT_ADDBA_RECEIVED_MSK) {
- txtid->addba_exchangecomplete = 1;
- txtid->addba_exchangeinprogress = 0;
- txtid->baw_size = buffersize;
-
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Resuming tid, buffersize: %d\n",
- __func__,
- buffersize);
-
- ath_tx_resume_tid(sc, txtid);
+ if (tx_info_priv->tx.ts_flags &
+ (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
+ ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) {
+ tx_status = 1;
+ is_underrun = 1;
}
+
+ if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
+ (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
+ tx_status = 1;
+
+ ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
+ (is_underrun) ? ATH_11N_TXMAXTRY :
+ tx_info_priv->tx.ts_longretry);
+
+exit:
+ kfree(tx_info_priv);
}
-static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- struct sk_buff *skb, struct rate_selection *sel)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
+ struct ieee80211_supported_band *sband = txrc->sband;
+ struct sk_buff *skb = txrc->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_softc *sc = priv;
struct ieee80211_hw *hw = sc->hw;
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_rate_node *ath_rc_priv = priv_sta;
- struct ath_node *an;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- int is_probe = FALSE, chk, ret;
- s8 lowest_idx;
+ int is_probe = 0;
__le16 fc = hdr->frame_control;
- u8 *qc, tid;
- DECLARE_MAC_BUF(mac);
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
-
- /* allocate driver private area of tx_info */
- tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
- ASSERT(tx_info->driver_data[0] != NULL);
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- lowest_idx = rate_lowest_index(sband, sta);
- tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
/* lowest rate for management and multicast/broadcast frames */
- if (!ieee80211_is_data(fc) ||
- is_multicast_ether_addr(hdr->addr1) || !sta) {
- sel->rate_idx = lowest_idx;
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
+ !sta) {
+ tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
+ tx_info->control.rates[0].count =
+ is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;
return;
}
/* Find tx rate for unicast frames */
- ath_rate_findrate(sc, ath_rc_priv,
- ATH_11N_TXMAXTRY, 4,
- ATH_RC_PROBE_ALLOWED,
- tx_info_priv->rcs,
- &is_probe,
- false);
- if (is_probe)
- sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
-
- /* Ratecontrol sometimes returns invalid rate index */
- if (tx_info_priv->rcs[0].rix != 0xff)
- ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix;
- else
- tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
-
- sel->rate_idx = tx_info_priv->rcs[0].rix;
+ ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4,
+ tx_info, &is_probe, false);
/* Check if aggregation has to be enabled for this tid */
-
- if (hw->conf.ht_conf.ht_supported) {
+ if (hw->conf.ht.enabled) {
if (ieee80211_is_data_qos(fc)) {
+ u8 *qc, tid;
+ struct ath_node *an;
+
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
+ an = (struct ath_node *)sta->drv_priv;
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, hdr->addr1);
- spin_unlock_bh(&sc->node_lock);
-
- if (!an) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Node not found to "
- "init/chk TX aggr\n", __func__);
- return;
- }
-
- chk = ath_tx_aggr_check(sc, an, tid);
- if (chk == AGGR_REQUIRED) {
- ret = ieee80211_start_tx_ba_session(hw,
- hdr->addr1, tid);
- if (ret)
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Unable to start tx "
- "aggr for: %s\n",
- __func__,
- print_mac(mac, hdr->addr1));
- else
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Started tx aggr for: %s\n",
- __func__,
- print_mac(mac, hdr->addr1));
- } else if (chk == AGGR_EXCHANGE_PROGRESS)
- ath_tx_aggr_resp(sc, sband, sta, an, tid);
+ if(ath_tx_aggr_check(sc, an, tid))
+ ieee80211_start_tx_ba_session(hw, hdr->addr1, tid);
}
}
}
@@ -2021,34 +1530,33 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct ath_softc *sc = priv;
- struct ath_rate_node *ath_rc_priv = priv_sta;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
int i, j = 0;
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sta->supp_rates[sband->band] & BIT(i)) {
+ ath_rc_priv->neg_rates.rs_rates[j]
+ = (sband->bitrates[i].bitrate * 2) / 10;
+ j++;
+ }
+ }
+ ath_rc_priv->neg_rates.rs_nrates = j;
- ath_setup_rates(sc, sband, sta, ath_rc_priv);
- if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
- for (i = 0; i < MCS_SET_SIZE; i++) {
- if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
+ if (sta->ht_cap.ht_supported) {
+ for (i = 0, j = 0; i < 77; i++) {
+ if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
if (j == ATH_RATE_MAX)
break;
}
ath_rc_priv->neg_ht_rates.rs_nrates = j;
}
- ath_rc_node_update(sc->hw, priv_sta);
-}
-static void ath_rate_clear(void *priv)
-{
- return;
+ ath_rc_init(sc, priv_sta, sband, sta);
}
static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
- struct ath_softc *sc = hw->priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
return hw->priv;
}
@@ -2060,19 +1568,17 @@ static void ath_rate_free(void *priv)
static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
struct ath_softc *sc = priv;
- struct ath_vap *avp = sc->sc_vaps[0];
- struct ath_rate_node *rate_priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+ struct ath_rate_priv *rate_priv;
- rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
+ rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
if (!rate_priv) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: Unable to allocate private rc structure\n",
- __func__);
+ "Unable to allocate private rc structure\n");
return NULL;
}
- ath_rc_sib_init(rate_priv);
+
+ rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
+ rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max;
return rate_priv;
}
@@ -2080,11 +1586,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
void *priv_sta)
{
- struct ath_rate_node *rate_priv = priv_sta;
- struct ath_softc *sc = priv;
-
- DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
- ath_rate_node_free(rate_priv);
+ struct ath_rate_priv *rate_priv = priv_sta;
+ kfree(rate_priv);
}
static struct rate_control_ops ath_rate_ops = {
@@ -2093,13 +1596,69 @@ static struct rate_control_ops ath_rate_ops = {
.tx_status = ath_tx_status,
.get_rate = ath_get_rate,
.rate_init = ath_rate_init,
- .clear = ath_rate_clear,
.alloc = ath_rate_alloc,
.free = ath_rate_free,
.alloc_sta = ath_rate_alloc_sta,
.free_sta = ath_rate_free_sta,
};
+static void ath_setup_rate_table(struct ath_softc *sc,
+ struct ath_rate_table *rate_table)
+{
+ int i;
+
+ for (i = 0; i < 256; i++)
+ rate_table->rateCodeToIndex[i] = (u8)-1;
+
+ for (i = 0; i < rate_table->rate_cnt; i++) {
+ u8 code = rate_table->info[i].ratecode;
+ u8 cix = rate_table->info[i].ctrl_rate;
+ u8 sh = rate_table->info[i].short_preamble;
+
+ rate_table->rateCodeToIndex[code] = i;
+ rate_table->rateCodeToIndex[code | sh] = i;
+
+ rate_table->info[i].lpAckDuration =
+ ath9k_hw_computetxtime(sc->sc_ah, rate_table,
+ WLAN_CTRL_FRAME_SIZE,
+ cix,
+ false);
+ rate_table->info[i].spAckDuration =
+ ath9k_hw_computetxtime(sc->sc_ah, rate_table,
+ WLAN_CTRL_FRAME_SIZE,
+ cix,
+ true);
+ }
+}
+
+void ath_rate_attach(struct ath_softc *sc)
+{
+ sc->hw_rate_table[ATH9K_MODE_11B] =
+ &ar5416_11b_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11A] =
+ &ar5416_11a_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11G] =
+ &ar5416_11g_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT20] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT20] =
+ &ar5416_11ng_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
+ &ar5416_11ng_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
+ &ar5416_11ng_ratetable;
+
+ ath_setup_rate_table(sc, &ar5416_11b_ratetable);
+ ath_setup_rate_table(sc, &ar5416_11a_ratetable);
+ ath_setup_rate_table(sc, &ar5416_11g_ratetable);
+ ath_setup_rate_table(sc, &ar5416_11na_ratetable);
+ ath_setup_rate_table(sc, &ar5416_11ng_ratetable);
+}
+
int ath_rate_control_register(void)
{
return ieee80211_rate_control_register(&ath_rate_ops);
@@ -2109,4 +1668,3 @@ void ath_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&ath_rate_ops);
}
-
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
index b95b41508b9..97c60d12e8a 100644
--- a/drivers/net/wireless/ath9k/rc.h
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -20,84 +20,24 @@
#define RC_H
#include "ath9k.h"
-/*
- * Interface definitions for transmit rate control modules for the
- * Atheros driver.
- *
- * A rate control module is responsible for choosing the transmit rate
- * for each data frame. Management+control frames are always sent at
- * a fixed rate.
- *
- * Only one module may be present at a time; the driver references
- * rate control interfaces by symbol name. If multiple modules are
- * to be supported we'll need to switch to a registration-based scheme
- * as is currently done, for example, for authentication modules.
- *
- * An instance of the rate control module is attached to each device
- * at attach time and detached when the device is destroyed. The module
- * may associate data with each device and each node (station). Both
- * sets of storage are opaque except for the size of the per-node storage
- * which must be provided when the module is attached.
- *
- * The rate control module is notified for each state transition and
- * station association/reassociation. Otherwise it is queried for a
- * rate for each outgoing frame and provided status from each transmitted
- * frame. Any ancillary processing is the responsibility of the module
- * (e.g. if periodic processing is required then the module should setup
- * it's own timer).
- *
- * In addition to the transmit rate for each frame the module must also
- * indicate the number of attempts to make at the specified rate. If this
- * number is != ATH_TXMAXTRY then an additional callback is made to setup
- * additional transmit state. The rate control code is assumed to write
- * this additional data directly to the transmit descriptor.
- */
struct ath_softc;
-#define TRUE 1
-#define FALSE 0
+#define ATH_RATE_MAX 30
+#define RATE_TABLE_SIZE 64
+#define MAX_TX_RATE_PHY 48
-#define ATH_RATE_MAX 30
-#define MCS_SET_SIZE 128
+/* VALID_ALL - valid for 20/40/Legacy,
+ * VALID - Legacy only,
+ * VALID_20 - HT 20 only,
+ * VALID_40 - HT 40 only */
-enum ieee80211_fixed_rate_mode {
- IEEE80211_FIXED_RATE_NONE = 0,
- IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */
-};
-
-/*
- * Use the hal os glue code to get ms time
- */
-#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
-
-#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS
-#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS
-#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI
-#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS
-#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI
-#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS
-#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI
-
-#define WLAN_PHY_OFDM PHY_OFDM
-#define WLAN_PHY_CCK PHY_CCK
-
-#define TRUE_20 0x2
-#define TRUE_40 0x4
-#define TRUE_2040 (TRUE_20|TRUE_40)
-#define TRUE_ALL (TRUE_2040|TRUE)
-
-enum {
- WLAN_RC_PHY_HT_20_SS = 4,
- WLAN_RC_PHY_HT_20_DS,
- WLAN_RC_PHY_HT_40_SS,
- WLAN_RC_PHY_HT_40_DS,
- WLAN_RC_PHY_HT_20_SS_HGI,
- WLAN_RC_PHY_HT_20_DS_HGI,
- WLAN_RC_PHY_HT_40_SS_HGI,
- WLAN_RC_PHY_HT_40_DS_HGI,
- WLAN_RC_PHY_MAX
-};
+#define INVALID 0x0
+#define VALID 0x1
+#define VALID_20 0x2
+#define VALID_40 0x4
+#define VALID_2040 (VALID_20|VALID_40)
+#define VALID_ALL (VALID_2040|VALID)
#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
|| (_phy == WLAN_RC_PHY_HT_40_DS) \
@@ -114,26 +54,22 @@ enum {
#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
-/* Returns the capflag mode */
#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
- (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
+ (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID))
/* Return TRUE if flag supports HT20 && client supports HT20 or
* return TRUE if flag supports HT40 && client supports HT40.
* This is used becos some rates overlap between HT20/HT40.
*/
-
-#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
- & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
- (capflag & WLAN_RC_40_FLAG)))
+#define WLAN_RC_PHY_HT_VALID(flag, capflag) \
+ (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \
+ ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG)))
#define WLAN_RC_DS_FLAG (0x01)
#define WLAN_RC_40_FLAG (0x02)
#define WLAN_RC_SGI_FLAG (0x04)
#define WLAN_RC_HT_FLAG (0x08)
-#define RATE_TABLE_SIZE 64
-
/**
* struct ath_rate_table - Rate Control table
* @valid: valid for use in rate control
@@ -150,10 +86,11 @@ enum {
* @max_4ms_framelen: maximum frame length(bytes) for tx duration
* @probe_interval: interval for rate control to probe for other rates
* @rssi_reduce_interval: interval for rate control to reduce rssi
- * @initial_ratemax: initial ratemax value used in ath_rc_sib_update()
+ * @initial_ratemax: initial ratemax value
*/
struct ath_rate_table {
int rate_cnt;
+ u8 rateCodeToIndex[256];
struct {
int valid;
int valid_single_stream;
@@ -171,42 +108,26 @@ struct ath_rate_table {
u8 sgi_index;
u8 ht_index;
u32 max_4ms_framelen;
+ u16 lpAckDuration;
+ u16 spAckDuration;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
u32 rssi_reduce_interval;
u8 initial_ratemax;
};
-#define ATH_RC_PROBE_ALLOWED 0x00000001
-#define ATH_RC_MINRATE_LASTRATE 0x00000002
-
-struct ath_rc_series {
- u8 rix;
- u8 tries;
- u8 flags;
- u32 max_4ms_framelen;
-};
-
-/* rcs_flags definition */
-#define ATH_RC_DS_FLAG 0x01
-#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */
-#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */
-#define ATH_RC_HT_FLAG 0x08 /* HT */
-#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */
-
-/*
- * State structures for new rate adaptation code
- */
-#define MAX_TX_RATE_TBL 64
-#define MAX_TX_RATE_PHY 48
-
struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
};
+struct ath_rateset {
+ u8 rs_nrates;
+ u8 rs_rates[ATH_RATE_MAX];
+};
+
/**
- * struct ath_tx_ratectrl - TX Rate control Information
+ * struct ath_rate_priv - Rate Control priv data
* @state: RC state
* @rssi_last: last ACK rssi
* @rssi_last_lookup: last ACK rssi used for lookup
@@ -225,9 +146,13 @@ struct ath_tx_ratectrl_state {
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
* @probe_interval: interval for ratectrl to probe for other rates
+ * @prev_data_rix: rate idx of last data frame
+ * @ht_cap: HT capabilities
+ * @single_stream: When TRUE, only single TX stream possible
+ * @neg_rates: Negotatied rates
+ * @neg_ht_rates: Negotiated HT rates
*/
-struct ath_tx_ratectrl {
- struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL];
+struct ath_rate_priv {
int8_t rssi_last;
int8_t rssi_last_lookup;
int8_t rssi_last_prev;
@@ -237,89 +162,40 @@ struct ath_tx_ratectrl {
int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
- u32 rssi_time;
- u32 rssi_down_time;
- u32 probe_time;
u8 hw_maxretry_pktcnt;
u8 max_valid_rate;
- u8 valid_rate_index[MAX_TX_RATE_TBL];
- u32 per_down_time;
-
- /* 11n state */
+ u8 valid_rate_index[RATE_TABLE_SIZE];
+ u8 ht_cap;
+ u8 single_stream;
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
- u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
+ u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rc_phy_mode;
u8 rate_max_phy;
+ u32 rssi_time;
+ u32 rssi_down_time;
+ u32 probe_time;
+ u32 per_down_time;
u32 probe_interval;
-};
-
-struct ath_rateset {
- u8 rs_nrates;
- u8 rs_rates[ATH_RATE_MAX];
-};
-
-/* per-device state */
-struct ath_rate_softc {
- /* phy tables that contain rate control data */
- const void *hw_rate_table[ATH9K_MODE_MAX];
-
- /* -1 or index of fixed rate */
- int fixedrix;
-};
-
-/* per-node state */
-struct ath_rate_node {
- struct ath_tx_ratectrl tx_ratectrl;
-
- /* rate idx of last data frame */
u32 prev_data_rix;
-
- /* ht capabilities */
- u8 ht_cap;
-
- /* When TRUE, only single stream Tx possible */
- u8 single_stream;
-
- /* Negotiated rates */
+ u32 tx_triglevel_max;
+ struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
-
- /* Negotiated HT rates */
struct ath_rateset neg_ht_rates;
-
struct ath_rate_softc *asc;
- struct ath_vap *avp;
};
-/* Driver data of ieee80211_tx_info */
struct ath_tx_info_priv {
- struct ath_rc_series rcs[4];
struct ath_tx_status tx;
int n_frames;
int n_bad_frames;
- u8 min_rate;
+ bool update_rc;
};
-/*
- * Attach/detach a rate control module.
- */
-struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
-void ath_rate_detach(struct ath_rate_softc *asc);
-
-/*
- * Update/reset rate control state for 802.11 state transitions.
- * Important mostly as the analog to ath_rate_newassoc when operating
- * in station mode.
- */
-void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
-void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
-
-/*
- * Return rate index for given Dot11 Rate.
- */
-u8 ath_rate_findrateix(struct ath_softc *sc,
- u8 dot11_rate);
+#define ATH_TX_INFO_PRIV(tx_info) \
+ ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
-/* Routines to register/unregister rate control algorithm */
+void ath_rate_attach(struct ath_softc *sc);
+u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
int ath_rate_control_register(void);
void ath_rate_control_unregister(void);
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 4983402af55..462e08c3d09 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Implementation of receive path.
- */
-
#include "core.h"
/*
@@ -27,10 +23,7 @@
* MAC acknowledges BA status as long as it copies frames to host
* buffer (or rx fifo). This can incorrectly acknowledge packets
* to a sender if last desc is self-linked.
- *
- * NOTE: Caller should hold the rxbuf lock.
*/
-
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
@@ -40,354 +33,53 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
ATH_RXBUF_RESET(bf);
ds = bf->bf_desc;
- ds->ds_link = 0; /* link to null */
+ ds->ds_link = 0; /* link to null */
ds->ds_data = bf->bf_buf_addr;
- /* XXX For RADAR?
- * virtual addr of the beginning of the buffer. */
+ /* virtual addr of the beginning of the buffer. */
skb = bf->bf_mpdu;
ASSERT(skb != NULL);
ds->ds_vdata = skb->data;
- /* setup rx descriptors */
- ath9k_hw_setuprxdesc(ah,
- ds,
- skb_tailroom(skb), /* buffer size */
+ /* setup rx descriptors. The rx.bufsize here tells the harware
+ * how much data it can DMA to us and that we are prepared
+ * to process */
+ ath9k_hw_setuprxdesc(ah, ds,
+ sc->rx.bufsize,
0);
- if (sc->sc_rxlink == NULL)
+ if (sc->rx.rxlink == NULL)
ath9k_hw_putrxbuf(ah, bf->bf_daddr);
else
- *sc->sc_rxlink = bf->bf_daddr;
+ *sc->rx.rxlink = bf->bf_daddr;
- sc->sc_rxlink = &ds->ds_link;
+ sc->rx.rxlink = &ds->ds_link;
ath9k_hw_rxena(ah);
}
-/* Process received BAR frame */
-
-static int ath_bar_rx(struct ath_softc *sc,
- struct ath_node *an,
- struct sk_buff *skb)
-{
- struct ieee80211_bar *bar;
- struct ath_arx_tid *rxtid;
- struct sk_buff *tskb;
- struct ath_recv_status *rx_status;
- int tidno, index, cindex;
- u16 seqno;
-
- /* look at BAR contents */
-
- bar = (struct ieee80211_bar *)skb->data;
- tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M)
- >> IEEE80211_BAR_CTL_TID_S;
- seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT;
-
- /* process BAR - indicate all pending RX frames till the BAR seqno */
-
- rxtid = &an->an_aggr.rx.tid[tidno];
-
- spin_lock_bh(&rxtid->tidlock);
-
- /* get relative index */
-
- index = ATH_BA_INDEX(rxtid->seq_next, seqno);
-
- /* drop BAR if old sequence (index is too large) */
-
- if ((index > rxtid->baw_size) &&
- (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))))
- /* discard frame, ieee layer may not treat frame as a dup */
- goto unlock_and_free;
-
- /* complete receive processing for all pending frames upto BAR seqno */
-
- cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- while ((rxtid->baw_head != rxtid->baw_tail) &&
- (rxtid->baw_head != cindex)) {
- tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
- rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
- rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
- if (tskb != NULL)
- ath_rx_subframe(an, tskb, rx_status);
-
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- }
-
- /* ... and indicate rest of the frames in-order */
-
- while (rxtid->baw_head != rxtid->baw_tail &&
- rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) {
- tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
- rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
- rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
- ath_rx_subframe(an, tskb, rx_status);
-
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- }
-
-unlock_and_free:
- spin_unlock_bh(&rxtid->tidlock);
- /* free bar itself */
- dev_kfree_skb(skb);
- return IEEE80211_FTYPE_CTL;
-}
-
-/* Function to handle a subframe of aggregation when HT is enabled */
-
-static int ath_ampdu_input(struct ath_softc *sc,
- struct ath_node *an,
- struct sk_buff *skb,
- struct ath_recv_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- struct ath_arx_tid *rxtid;
- struct ath_rxbuf *rxbuf;
- u8 type, subtype;
- u16 rxseq;
- int tid = 0, index, cindex, rxdiff;
- __le16 fc;
- u8 *qc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
-
- /* collect stats of frames with non-zero version */
-
- if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) {
- dev_kfree_skb(skb);
- return -1;
- }
-
- type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
- subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
-
- if (ieee80211_is_back_req(fc))
- return ath_bar_rx(sc, an, skb);
-
- /* special aggregate processing only for qos unicast data frames */
-
- if (!ieee80211_is_data(fc) ||
- !ieee80211_is_data_qos(fc) ||
- is_multicast_ether_addr(hdr->addr1))
- return ath_rx_subframe(an, skb, rx_status);
-
- /* lookup rx tid state */
-
- if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
- }
-
- if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
- /* Drop the frame not belonging to me. */
- if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
- dev_kfree_skb(skb);
- return -1;
- }
- }
-
- rxtid = &an->an_aggr.rx.tid[tid];
-
- spin_lock(&rxtid->tidlock);
-
- rxdiff = (rxtid->baw_tail - rxtid->baw_head) &
- (ATH_TID_MAX_BUFS - 1);
-
- /*
- * If the ADDBA exchange has not been completed by the source,
- * process via legacy path (i.e. no reordering buffer is needed)
- */
- if (!rxtid->addba_exchangecomplete) {
- spin_unlock(&rxtid->tidlock);
- return ath_rx_subframe(an, skb, rx_status);
- }
-
- /* extract sequence number from recvd frame */
-
- rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
-
- if (rxtid->seq_reset) {
- rxtid->seq_reset = 0;
- rxtid->seq_next = rxseq;
- }
-
- index = ATH_BA_INDEX(rxtid->seq_next, rxseq);
-
- /* drop frame if old sequence (index is too large) */
-
- if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) {
- /* discard frame, ieee layer may not treat frame as a dup */
- spin_unlock(&rxtid->tidlock);
- dev_kfree_skb(skb);
- return IEEE80211_FTYPE_DATA;
- }
-
- /* sequence number is beyond block-ack window */
-
- if (index >= rxtid->baw_size) {
-
- /* complete receive processing for all pending frames */
-
- while (index >= rxtid->baw_size) {
-
- rxbuf = rxtid->rxbuf + rxtid->baw_head;
-
- if (rxbuf->rx_wbuf != NULL) {
- ath_rx_subframe(an, rxbuf->rx_wbuf,
- &rxbuf->rx_status);
- rxbuf->rx_wbuf = NULL;
- }
-
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-
- index--;
- }
- }
-
- /* add buffer to the recv ba window */
-
- cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- rxbuf = rxtid->rxbuf + cindex;
-
- if (rxbuf->rx_wbuf != NULL) {
- spin_unlock(&rxtid->tidlock);
- /* duplicate frame */
- dev_kfree_skb(skb);
- return IEEE80211_FTYPE_DATA;
- }
-
- rxbuf->rx_wbuf = skb;
- rxbuf->rx_time = get_timestamp();
- rxbuf->rx_status = *rx_status;
-
- /* advance tail if sequence received is newer
- * than any received so far */
-
- if (index >= rxdiff) {
- rxtid->baw_tail = cindex;
- INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS);
- }
-
- /* indicate all in-order received frames */
-
- while (rxtid->baw_head != rxtid->baw_tail) {
- rxbuf = rxtid->rxbuf + rxtid->baw_head;
- if (!rxbuf->rx_wbuf)
- break;
-
- ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status);
- rxbuf->rx_wbuf = NULL;
-
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- }
-
- /*
- * start a timer to flush all received frames if there are pending
- * receive frames
- */
- if (rxtid->baw_head != rxtid->baw_tail)
- mod_timer(&rxtid->timer, ATH_RX_TIMEOUT);
- else
- del_timer_sync(&rxtid->timer);
-
- spin_unlock(&rxtid->tidlock);
- return IEEE80211_FTYPE_DATA;
-}
-
-/* Timer to flush all received sub-frames */
-
-static void ath_rx_timer(unsigned long data)
+static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
{
- struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data;
- struct ath_node *an = rxtid->an;
- struct ath_rxbuf *rxbuf;
- int nosched;
-
- spin_lock_bh(&rxtid->tidlock);
- while (rxtid->baw_head != rxtid->baw_tail) {
- rxbuf = rxtid->rxbuf + rxtid->baw_head;
- if (!rxbuf->rx_wbuf) {
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- continue;
- }
-
- /*
- * Stop if the next one is a very recent frame.
- *
- * Call get_timestamp in every iteration to protect against the
- * case in which a new frame is received while we are executing
- * this function. Using a timestamp obtained before entering
- * the loop could lead to a very large time interval
- * (a negative value typecast to unsigned), breaking the
- * function's logic.
- */
- if ((get_timestamp() - rxbuf->rx_time) <
- (ATH_RX_TIMEOUT * HZ / 1000))
- break;
-
- ath_rx_subframe(an, rxbuf->rx_wbuf,
- &rxbuf->rx_status);
- rxbuf->rx_wbuf = NULL;
-
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- }
-
- /*
- * start a timer to flush all received frames if there are pending
- * receive frames
- */
- if (rxtid->baw_head != rxtid->baw_tail)
- nosched = 0;
- else
- nosched = 1; /* no need to re-arm the timer again */
-
- spin_unlock_bh(&rxtid->tidlock);
+ /* XXX block beacon interrupts */
+ ath9k_hw_setantenna(sc->sc_ah, antenna);
+ sc->rx.defant = antenna;
+ sc->rx.rxotherant = 0;
}
-/* Free all pending sub-frames in the re-ordering buffer */
-
-static void ath_rx_flush_tid(struct ath_softc *sc,
- struct ath_arx_tid *rxtid, int drop)
+/*
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the current h/w TSF.
+*/
+static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
{
- struct ath_rxbuf *rxbuf;
- unsigned long flag;
-
- spin_lock_irqsave(&rxtid->tidlock, flag);
- while (rxtid->baw_head != rxtid->baw_tail) {
- rxbuf = rxtid->rxbuf + rxtid->baw_head;
- if (!rxbuf->rx_wbuf) {
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- continue;
- }
-
- if (drop)
- dev_kfree_skb(rxbuf->rx_wbuf);
- else
- ath_rx_subframe(rxtid->an,
- rxbuf->rx_wbuf,
- &rxbuf->rx_status);
-
- rxbuf->rx_wbuf = NULL;
+ u64 tsf;
- INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
- INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
- }
- spin_unlock_irqrestore(&rxtid->tidlock, flag);
+ tsf = ath9k_hw_gettsf64(sc->sc_ah);
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+ return (tsf & ~0x7fff) | rstamp;
}
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
- u32 len)
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
{
struct sk_buff *skb;
u32 off;
@@ -398,6 +90,13 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
* in rx'd frames.
*/
+ /* Note: the kernel can allocate a value greater than
+ * what we ask it to give us. We really only need 4 KB as that
+ * is this hardware supports and in fact we need at least 3849
+ * as that is the MAX AMSDU size this hardware supports.
+ * Unfortunately this means we may get 8 KB here from the
+ * kernel... and that is actually what is observed on some
+ * systems :( */
skb = dev_alloc_skb(len + sc->sc_cachelsz - 1);
if (skb != NULL) {
off = ((unsigned long) skb->data) % sc->sc_cachelsz;
@@ -405,67 +104,131 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
skb_reserve(skb, sc->sc_cachelsz - off);
} else {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: skbuff alloc of size %u failed\n",
- __func__, len);
+ "skbuff alloc of size %u failed\n", len);
return NULL;
}
return skb;
}
-static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb)
+/*
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
+ */
+static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
+ struct ieee80211_rx_status *rx_status, bool *decrypt_error,
+ struct ath_softc *sc)
{
- struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
+ struct ieee80211_hdr *hdr;
+ u8 ratecode;
+ __le16 fc;
- ASSERT(bf != NULL);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
- spin_lock_bh(&sc->sc_rxbuflock);
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ if (ds->ds_rxstat.rs_more) {
/*
- * This buffer is still held for hw acess.
- * Mark it as free to be re-queued it later.
+ * Frame spans multiple descriptors; this cannot happen yet
+ * as we don't support jumbograms. If not in monitor mode,
+ * discard the frame. Enable this if you want to see
+ * error frames in Monitor mode.
*/
- bf->bf_status |= ATH_BUFSTATUS_FREE;
- } else {
- /* XXX: we probably never enter here, remove after
- * verification */
- list_add_tail(&bf->list, &sc->sc_rxbuf);
- ath_rx_buf_link(sc, bf);
+ if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR)
+ goto rx_next;
+ } else if (ds->ds_rxstat.rs_status != 0) {
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
+ goto rx_next;
+
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+ *decrypt_error = true;
+ } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
+ else
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ goto rx_next;
+ } else {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ goto rx_next;
+ }
+ }
}
- spin_unlock_bh(&sc->sc_rxbuflock);
-}
-/*
- * The skb indicated to upper stack won't be returned to us.
- * So we have to allocate a new one and queue it by ourselves.
- */
-static int ath_rx_indicate(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_recv_status *status,
- u16 keyix)
-{
- struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
- struct sk_buff *nskb;
- int type;
-
- /* indicate frame to the stack, which will free the old skb. */
- type = _ath_rx_indicate(sc, skb, status, keyix);
-
- /* allocate a new skb and queue it to for H/W processing */
- nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
- if (nskb != NULL) {
- bf->bf_mpdu = nskb;
- bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data,
- skb_end_pointer(nskb) - nskb->head,
- PCI_DMA_FROMDEVICE);
- bf->bf_dmacontext = bf->bf_buf_addr;
- ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
+ ratecode = ds->ds_rxstat.rs_rate;
+
+ if (ratecode & 0x80) {
+ /* HT rate */
+ rx_status->flag |= RX_FLAG_HT;
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
+ rx_status->flag |= RX_FLAG_40MHZ;
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+ rx_status->flag |= RX_FLAG_SHORT_GI;
+ rx_status->rate_idx = ratecode & 0x7f;
+ } else {
+ int i = 0, cur_band, n_rates;
+ struct ieee80211_hw *hw = sc->hw;
- /* queue the new wbuf to H/W */
- ath_rx_requeue(sc, nskb);
+ cur_band = hw->conf.channel->band;
+ n_rates = sc->sbands[cur_band].n_bitrates;
+
+ for (i = 0; i < n_rates; i++) {
+ if (sc->sbands[cur_band].bitrates[i].hw_value ==
+ ratecode) {
+ rx_status->rate_idx = i;
+ break;
+ }
+
+ if (sc->sbands[cur_band].bitrates[i].hw_value_short ==
+ ratecode) {
+ rx_status->rate_idx = i;
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ break;
+ }
+ }
}
- return type;
+ rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
+ rx_status->band = sc->hw->conf.channel->band;
+ rx_status->freq = sc->hw->conf.channel->center_freq;
+ rx_status->noise = sc->sc_ani.sc_noise_floor;
+ rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->antenna = ds->ds_rxstat.rs_antenna;
+
+ /* at 45 you will be able to use MCS 15 reliably. A more elaborate
+ * scheme can be used here but it requires tables of SNR/throughput for
+ * each possible mode used. */
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+
+ /* rssi can be more than 45 though, anything above that
+ * should be considered at 100% */
+ if (rx_status->qual > 100)
+ rx_status->qual = 100;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ return 1;
+rx_next:
+ return 0;
}
static void ath_opmode_init(struct ath_softc *sc)
@@ -489,11 +252,7 @@ static void ath_opmode_init(struct ath_softc *sc)
/* calculate and install multicast filter */
mfilt[0] = mfilt[1] = ~0;
-
ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
- DPRINTF(sc, ATH_DBG_CONFIG ,
- "%s: RX filter 0x%x, MC filter %08x:%08x\n",
- __func__, rfilt, mfilt[0], mfilt[1]);
}
int ath_rx_init(struct ath_softc *sc, int nbufs)
@@ -503,38 +262,29 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
int error = 0;
do {
- spin_lock_init(&sc->sc_rxflushlock);
+ spin_lock_init(&sc->rx.rxflushlock);
sc->sc_flags &= ~SC_OP_RXFLUSH;
- spin_lock_init(&sc->sc_rxbuflock);
+ spin_lock_init(&sc->rx.rxbuflock);
- /*
- * Cisco's VPN software requires that drivers be able to
- * receive encapsulated frames that are larger than the MTU.
- * Since we can't be sure how large a frame we'll get, setup
- * to handle the larges on possible.
- */
- sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+ sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(sc->sc_cachelsz,
(u16)64));
- DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n",
- __func__, sc->sc_cachelsz, sc->sc_rxbufsize);
+ DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+ sc->sc_cachelsz, sc->rx.bufsize);
/* Initialize rx descriptors */
- error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
"rx", nbufs, 1);
if (error != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: failed to allocate rx descriptors: %d\n",
- __func__, error);
+ "failed to allocate rx descriptors: %d\n", error);
break;
}
- /* Pre-allocate a wbuf for each rx buffer */
-
- list_for_each_entry(bf, &sc->sc_rxbuf, list) {
- skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
+ list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+ skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
if (skb == NULL) {
error = -ENOMEM;
break;
@@ -542,12 +292,20 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_mpdu = skb;
bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
- skb_end_pointer(skb) - skb->head,
- PCI_DMA_FROMDEVICE);
+ sc->rx.bufsize,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(sc->pdev,
+ bf->bf_buf_addr))) {
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "pci_dma_mapping_error() on RX init\n");
+ error = -ENOMEM;
+ break;
+ }
bf->bf_dmacontext = bf->bf_buf_addr;
- ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
}
- sc->sc_rxlink = NULL;
+ sc->rx.rxlink = NULL;
} while (0);
@@ -557,23 +315,19 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
return error;
}
-/* Reclaim all rx queue resources */
-
void ath_rx_cleanup(struct ath_softc *sc)
{
struct sk_buff *skb;
struct ath_buf *bf;
- list_for_each_entry(bf, &sc->sc_rxbuf, list) {
+ list_for_each_entry(bf, &sc->rx.rxbuf, list) {
skb = bf->bf_mpdu;
if (skb)
dev_kfree_skb(skb);
}
- /* cleanup rx descriptors */
-
- if (sc->sc_rxdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+ if (sc->rx.rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
}
/*
@@ -606,201 +360,115 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
| ATH9K_RX_FILTER_MCAST;
/* If not a STA, enable processing of Probe Requests */
- if (sc->sc_ah->ah_opmode != ATH9K_M_STA)
+ if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
/* Can't set HOSTAP into promiscous mode */
- if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) &&
- (sc->rx_filter & FIF_PROMISC_IN_BSS)) ||
- (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) {
+ if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) &&
+ (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
+ (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) {
rfilt |= ATH9K_RX_FILTER_PROM;
/* ??? To prevent from sending ACK */
rfilt &= ~ATH9K_RX_FILTER_UCAST;
}
- if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
- (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) ||
- (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION ||
+ sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)
rfilt |= ATH9K_RX_FILTER_BEACON;
/* If in HOSTAP mode, want to enable reception of PSPOLL frames
& beacon frames */
- if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP)
+ if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP)
rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+
return rfilt;
#undef RX_FILTER_PRESERVE
}
-/* Enable the receive h/w following a reset. */
-
int ath_startrecv(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf, *tbf;
- spin_lock_bh(&sc->sc_rxbuflock);
- if (list_empty(&sc->sc_rxbuf))
+ spin_lock_bh(&sc->rx.rxbuflock);
+ if (list_empty(&sc->rx.rxbuf))
goto start_recv;
- sc->sc_rxlink = NULL;
- list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) {
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
- /* restarting h/w, no need for holding descriptors */
- bf->bf_status &= ~ATH_BUFSTATUS_STALE;
- /*
- * Upper layer may not be done with the frame yet so
- * we can't just re-queue it to hardware. Remove it
- * from h/w queue. It'll be re-queued when upper layer
- * returns the frame and ath_rx_requeue_mpdu is called.
- */
- if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) {
- list_del(&bf->list);
- continue;
- }
- }
- /* chain descriptors */
+ sc->rx.rxlink = NULL;
+ list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
ath_rx_buf_link(sc, bf);
}
/* We could have deleted elements so the list may be empty now */
- if (list_empty(&sc->sc_rxbuf))
+ if (list_empty(&sc->rx.rxbuf))
goto start_recv;
- bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
+ bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
ath9k_hw_putrxbuf(ah, bf->bf_daddr);
- ath9k_hw_rxena(ah); /* enable recv descriptors */
+ ath9k_hw_rxena(ah);
start_recv:
- spin_unlock_bh(&sc->sc_rxbuflock);
- ath_opmode_init(sc); /* set filters, etc. */
- ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */
+ spin_unlock_bh(&sc->rx.rxbuflock);
+ ath_opmode_init(sc);
+ ath9k_hw_startpcureceive(ah);
+
return 0;
}
-/* Disable the receive h/w in preparation for a reset. */
-
bool ath_stoprecv(struct ath_softc *sc)
{
struct ath_hal *ah = sc->sc_ah;
- u64 tsf;
bool stopped;
- ath9k_hw_stoppcurecv(ah); /* disable PCU */
- ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */
- stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */
- mdelay(3); /* 3ms is long enough for 1 frame */
- tsf = ath9k_hw_gettsf64(ah);
- sc->sc_rxlink = NULL; /* just in case */
+ ath9k_hw_stoppcurecv(ah);
+ ath9k_hw_setrxfilter(ah, 0);
+ stopped = ath9k_hw_stopdmarecv(ah);
+ mdelay(3); /* 3ms is long enough for 1 frame */
+ sc->rx.rxlink = NULL;
+
return stopped;
}
-/* Flush receive queue */
-
void ath_flushrecv(struct ath_softc *sc)
{
- /*
- * ath_rx_tasklet may be used to handle rx interrupt and flush receive
- * queue at the same time. Use a lock to serialize the access of rx
- * queue.
- * ath_rx_tasklet cannot hold the spinlock while indicating packets.
- * Instead, do not claim the spinlock but check for a flush in
- * progress (see references to sc_rxflush)
- */
- spin_lock_bh(&sc->sc_rxflushlock);
+ spin_lock_bh(&sc->rx.rxflushlock);
sc->sc_flags |= SC_OP_RXFLUSH;
-
ath_rx_tasklet(sc, 1);
-
sc->sc_flags &= ~SC_OP_RXFLUSH;
- spin_unlock_bh(&sc->sc_rxflushlock);
+ spin_unlock_bh(&sc->rx.rxflushlock);
}
-/* Process an individual frame */
-
-int ath_rx_input(struct ath_softc *sc,
- struct ath_node *an,
- int is_ampdu,
- struct sk_buff *skb,
- struct ath_recv_status *rx_status,
- enum ATH_RX_TYPE *status)
-{
- if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) {
- *status = ATH_RX_CONSUMED;
- return ath_ampdu_input(sc, an, skb, rx_status);
- } else {
- *status = ATH_RX_NON_CONSUMED;
- return -1;
- }
-}
-
-/* Process receive queue, as well as LED, etc. */
-
int ath_rx_tasklet(struct ath_softc *sc, int flush)
{
#define PA2DESC(_sc, _pa) \
- ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
- ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+ ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \
+ ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr)))
- struct ath_buf *bf, *bf_held = NULL;
+ struct ath_buf *bf;
struct ath_desc *ds;
- struct ieee80211_hdr *hdr;
- struct sk_buff *skb = NULL;
- struct ath_recv_status rx_status;
+ struct sk_buff *skb = NULL, *requeue_skb;
+ struct ieee80211_rx_status rx_status;
struct ath_hal *ah = sc->sc_ah;
- int type, rx_processed = 0;
- u32 phyerr;
- u8 chainreset = 0;
- int retval;
- __le16 fc;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padsize, retval;
+ bool decrypt_error = false;
+ u8 keyix;
+
+ spin_lock_bh(&sc->rx.rxbuflock);
do {
/* If handling rx interrupt and flush is in progress => exit */
if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
break;
- spin_lock_bh(&sc->sc_rxbuflock);
- if (list_empty(&sc->sc_rxbuf)) {
- sc->sc_rxlink = NULL;
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (list_empty(&sc->rx.rxbuf)) {
+ sc->rx.rxlink = NULL;
break;
}
- bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
-
- /*
- * There is a race condition that BH gets scheduled after sw
- * writes RxE and before hw re-load the last descriptor to get
- * the newly chained one. Software must keep the last DONE
- * descriptor as a holding descriptor - software does so by
- * marking it with the STALE flag.
- */
- if (bf->bf_status & ATH_BUFSTATUS_STALE) {
- bf_held = bf;
- if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) {
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to
- * remove the last holding descriptor
- * in BH context.
- */
- list_del(&bf_held->list);
- bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
- sc->sc_rxlink = NULL;
-
- if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
- list_add_tail(&bf_held->list,
- &sc->sc_rxbuf);
- ath_rx_buf_link(sc, bf_held);
- }
- spin_unlock_bh(&sc->sc_rxbuflock);
- break;
- }
- bf = list_entry(bf->list.next, struct ath_buf, list);
- }
-
+ bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
ds = bf->bf_desc;
- ++rx_processed;
/*
* Must provide the virtual address of the current
@@ -813,8 +481,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* on. All this is necessary because of our use of
* a self-linked list to avoid rx overruns.
*/
- retval = ath9k_hw_rxprocdesc(ah,
- ds,
+ retval = ath9k_hw_rxprocdesc(ah, ds,
bf->bf_daddr,
PA2DESC(sc, ds->ds_link),
0);
@@ -822,8 +489,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ath_buf *tbf;
struct ath_desc *tds;
- if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (list_is_last(&bf->list, &sc->rx.rxbuf)) {
+ sc->rx.rxlink = NULL;
break;
}
@@ -841,451 +508,127 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/
tds = tbf->bf_desc;
- retval = ath9k_hw_rxprocdesc(ah,
- tds, tbf->bf_daddr,
- PA2DESC(sc, tds->ds_link), 0);
+ retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
+ PA2DESC(sc, tds->ds_link), 0);
if (retval == -EINPROGRESS) {
- spin_unlock_bh(&sc->sc_rxbuflock);
break;
}
}
- /* XXX: we do not support frames spanning
- * multiple descriptors */
- bf->bf_status |= ATH_BUFSTATUS_DONE;
-
skb = bf->bf_mpdu;
- if (skb == NULL) { /* XXX ??? can this happen */
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (!skb)
continue;
- }
+
/*
- * Now we know it's a completed frame, we can indicate the
- * frame. Remove the previous holding descriptor and leave
- * this one in the queue as the new holding descriptor.
+ * Synchronize the DMA transfer with CPU before
+ * 1. accessing the frame
+ * 2. requeueing the same buffer to h/w
*/
- if (bf_held) {
- list_del(&bf_held->list);
- bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
- if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
- list_add_tail(&bf_held->list, &sc->sc_rxbuf);
- /* try to requeue this descriptor */
- ath_rx_buf_link(sc, bf_held);
- }
- }
+ pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
+ sc->rx.bufsize,
+ PCI_DMA_FROMDEVICE);
- bf->bf_status |= ATH_BUFSTATUS_STALE;
- bf_held = bf;
/*
- * Release the lock here in case ieee80211_input() return
- * the frame immediately by calling ath_rx_mpdu_requeue().
+ * If we're asked to flush receive queue, directly
+ * chain it back at the queue without processing it.
*/
- spin_unlock_bh(&sc->sc_rxbuflock);
+ if (flush)
+ goto requeue;
- if (flush) {
- /*
- * If we're asked to flush receive queue, directly
- * chain it back at the queue without processing it.
- */
- goto rx_next;
- }
+ if (!ds->ds_rxstat.rs_datalen)
+ goto requeue;
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
- memset(&rx_status, 0, sizeof(struct ath_recv_status));
+ /* The status portion of the descriptor could get corrupted. */
+ if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
+ goto requeue;
- if (ds->ds_rxstat.rs_more) {
- /*
- * Frame spans multiple descriptors; this
- * cannot happen yet as we don't support
- * jumbograms. If not in monitor mode,
- * discard the frame.
- */
-#ifndef ERROR_FRAMES
- /*
- * Enable this if you want to see
- * error frames in Monitor mode.
- */
- if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR)
- goto rx_next;
-#endif
- /* fall thru for monitor mode handling... */
- } else if (ds->ds_rxstat.rs_status != 0) {
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
- rx_status.flags |= ATH_RX_FCS_ERROR;
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
- phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
- goto rx_next;
- }
+ if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+ goto requeue;
+
+ /* Ensure we always have an skb to requeue once we are done
+ * processing the current buffer's skb */
+ requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
+
+ /* If there is no memory we ignore the current RX'd frame,
+ * tell hardware it can give us a new frame using the old
+ * skb and put it at the tail of the sc->rx.rxbuf list for
+ * processing. */
+ if (!requeue_skb)
+ goto requeue;
+
+ /* Unmap the frame */
+ pci_unmap_single(sc->pdev, bf->bf_buf_addr,
+ sc->rx.bufsize,
+ PCI_DMA_FROMDEVICE);
- if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
- /*
- * Decrypt error. We only mark packet status
- * here and always push up the frame up to let
- * mac80211 handle the actual error case, be
- * it no decryption key or real decryption
- * error. This let us keep statistics there.
- */
- rx_status.flags |= ATH_RX_DECRYPT_ERROR;
- } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
- /*
- * Demic error. We only mark frame status here
- * and always push up the frame up to let
- * mac80211 handle the actual error case. This
- * let us keep statistics there. Hardware may
- * post a false-positive MIC error.
- */
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- ds->ds_rxstat.rs_status &=
- ~ATH9K_RXERR_MIC;
- else
- rx_status.flags |= ATH_RX_MIC_ERROR;
- }
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- goto rx_next;
- } else {
- if (ds->ds_rxstat.rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- goto rx_next;
- }
- }
- }
- /*
- * The status portion of the descriptor could get corrupted.
- */
- if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
- goto rx_next;
- /*
- * Sync and unmap the frame. At this point we're
- * committed to passing the sk_buff somewhere so
- * clear buf_skb; this means a new sk_buff must be
- * allocated when the rx descriptor is setup again
- * to receive another frame.
- */
skb_put(skb, ds->ds_rxstat.rs_datalen);
skb->protocol = cpu_to_be16(ETH_P_CONTROL);
- rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
- rx_status.rateieee =
- sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate;
- rx_status.rateKbps =
- sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps;
- rx_status.ratecode = ds->ds_rxstat.rs_rate;
- /* HT rate */
- if (rx_status.ratecode & 0x80) {
- /* TODO - add table to avoid division */
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
- rx_status.flags |= ATH_RX_40MHZ;
- rx_status.rateKbps =
- (rx_status.rateKbps * 27) / 13;
- }
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
- rx_status.rateKbps =
- (rx_status.rateKbps * 10) / 9;
- else
- rx_status.flags |= ATH_RX_SHORT_GI;
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - hdrlen % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ padsize = hdrlen & 3;
+ if (padsize && hdrlen >= 24) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
}
- /* sc_noise_floor is only available when the station
- attaches to an AP, so we use a default value
- if we are not yet attached. */
- rx_status.abs_rssi =
- ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
-
- pci_dma_sync_single_for_cpu(sc->pdev,
- bf->bf_buf_addr,
- skb_tailroom(skb),
- PCI_DMA_FROMDEVICE);
- pci_unmap_single(sc->pdev,
- bf->bf_buf_addr,
- sc->sc_rxbufsize,
- PCI_DMA_FROMDEVICE);
+ keyix = ds->ds_rxstat.rs_keyix;
- /* XXX: Ah! make me more readable, use a helper */
- if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
- if (ds->ds_rxstat.rs_moreaggr == 0) {
- rx_status.rssictl[0] =
- ds->ds_rxstat.rs_rssi_ctl0;
- rx_status.rssictl[1] =
- ds->ds_rxstat.rs_rssi_ctl1;
- rx_status.rssictl[2] =
- ds->ds_rxstat.rs_rssi_ctl2;
- rx_status.rssi = ds->ds_rxstat.rs_rssi;
- if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
- rx_status.rssiextn[0] =
- ds->ds_rxstat.rs_rssi_ext0;
- rx_status.rssiextn[1] =
- ds->ds_rxstat.rs_rssi_ext1;
- rx_status.rssiextn[2] =
- ds->ds_rxstat.rs_rssi_ext2;
- rx_status.flags |=
- ATH_RX_RSSI_EXTN_VALID;
- }
- rx_status.flags |= ATH_RX_RSSI_VALID |
- ATH_RX_CHAIN_RSSI_VALID;
- }
- } else {
- /*
- * Need to insert the "combined" rssi into the
- * status structure for upper layer processing
- */
- rx_status.rssi = ds->ds_rxstat.rs_rssi;
- rx_status.flags |= ATH_RX_RSSI_VALID;
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, sc->sc_keymap))
+ rx_status.flag |= RX_FLAG_DECRYPTED;
}
- /* Pass frames up to the stack. */
+ /* Send the frame to mac80211 */
+ __ieee80211_rx(sc->hw, skb, &rx_status);
- type = ath_rx_indicate(sc, skb,
- &rx_status, ds->ds_rxstat.rs_keyix);
+ /* We will now give hardware our shiny new allocated skb */
+ bf->bf_mpdu = requeue_skb;
+ bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data,
+ sc->rx.bufsize,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(sc->pdev,
+ bf->bf_buf_addr))) {
+ dev_kfree_skb_any(requeue_skb);
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "pci_dma_mapping_error() on RX\n");
+ break;
+ }
+ bf->bf_dmacontext = bf->bf_buf_addr;
/*
* change the default rx antenna if rx diversity chooses the
* other antenna 3 times in a row.
*/
- if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
- if (++sc->sc_rxotherant >= 3)
- ath_setdefantenna(sc,
- ds->ds_rxstat.rs_antenna);
+ if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
+ if (++sc->rx.rxotherant >= 3)
+ ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
} else {
- sc->sc_rxotherant = 0;
+ sc->rx.rxotherant = 0;
}
+requeue:
+ list_move_tail(&bf->list, &sc->rx.rxbuf);
+ ath_rx_buf_link(sc, bf);
+ } while (1);
-#ifdef CONFIG_SLOW_ANT_DIV
- if ((rx_status.flags & ATH_RX_RSSI_VALID) &&
- ieee80211_is_beacon(fc)) {
- ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat);
- }
-#endif
- /*
- * For frames successfully indicated, the buffer will be
- * returned to us by upper layers by calling
- * ath_rx_mpdu_requeue, either synchronusly or asynchronously.
- * So we don't want to do it here in this loop.
- */
- continue;
-
-rx_next:
- bf->bf_status |= ATH_BUFSTATUS_FREE;
- } while (TRUE);
-
- if (chainreset) {
- DPRINTF(sc, ATH_DBG_CONFIG,
- "%s: Reset rx chain mask. "
- "Do internal reset\n", __func__);
- ASSERT(flush == 0);
- ath_reset(sc, false);
- }
+ spin_unlock_bh(&sc->rx.rxbuflock);
return 0;
#undef PA2DESC
}
-
-/* Process ADDBA request in per-TID data structure */
-
-int ath_rx_aggr_start(struct ath_softc *sc,
- const u8 *addr,
- u16 tid,
- u16 *ssn)
-{
- struct ath_arx_tid *rxtid;
- struct ath_node *an;
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_supported_band *sband;
- u16 buffersize = 0;
-
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, (u8 *) addr);
- spin_unlock_bh(&sc->node_lock);
-
- if (!an) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Node not found to initialize RX aggregation\n",
- __func__);
- return -1;
- }
-
- sband = hw->wiphy->bands[hw->conf.channel->band];
- buffersize = IEEE80211_MIN_AMPDU_BUF <<
- sband->ht_info.ampdu_factor; /* FIXME */
-
- rxtid = &an->an_aggr.rx.tid[tid];
-
- spin_lock_bh(&rxtid->tidlock);
- if (sc->sc_flags & SC_OP_RXAGGR) {
- /* Allow aggregation reception
- * Adjust rx BA window size. Peer might indicate a
- * zero buffer size for a _dont_care_ condition.
- */
- if (buffersize)
- rxtid->baw_size = min(buffersize, rxtid->baw_size);
-
- /* set rx sequence number */
- rxtid->seq_next = *ssn;
-
- /* Allocate the receive buffers for this TID */
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Allcating rxbuffer for TID %d\n", __func__, tid);
-
- if (rxtid->rxbuf == NULL) {
- /*
- * If the rxbuff is not NULL at this point, we *probably*
- * already allocated the buffer on a previous ADDBA,
- * and this is a subsequent ADDBA that got through.
- * Don't allocate, but use the value in the pointer,
- * we zero it out when we de-allocate.
- */
- rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS *
- sizeof(struct ath_rxbuf), GFP_ATOMIC);
- }
- if (rxtid->rxbuf == NULL) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Unable to allocate RX buffer, "
- "refusing ADDBA\n", __func__);
- } else {
- /* Ensure the memory is zeroed out (all internal
- * pointers are null) */
- memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS *
- sizeof(struct ath_rxbuf));
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Allocated @%p\n", __func__, rxtid->rxbuf);
-
- /* Allow aggregation reception */
- rxtid->addba_exchangecomplete = 1;
- }
- }
- spin_unlock_bh(&rxtid->tidlock);
-
- return 0;
-}
-
-/* Process DELBA */
-
-int ath_rx_aggr_stop(struct ath_softc *sc,
- const u8 *addr,
- u16 tid)
-{
- struct ath_node *an;
-
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, (u8 *) addr);
- spin_unlock_bh(&sc->node_lock);
-
- if (!an) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: RX aggr stop for non-existent node\n", __func__);
- return -1;
- }
-
- ath_rx_aggr_teardown(sc, an, tid);
- return 0;
-}
-
-/* Rx aggregation tear down */
-
-void ath_rx_aggr_teardown(struct ath_softc *sc,
- struct ath_node *an, u8 tid)
-{
- struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid];
-
- if (!rxtid->addba_exchangecomplete)
- return;
-
- del_timer_sync(&rxtid->timer);
- ath_rx_flush_tid(sc, rxtid, 0);
- rxtid->addba_exchangecomplete = 0;
-
- /* De-allocate the receive buffer array allocated when addba started */
-
- if (rxtid->rxbuf) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Deallocating TID %d rxbuff @%p\n",
- __func__, tid, rxtid->rxbuf);
- kfree(rxtid->rxbuf);
-
- /* Set pointer to null to avoid reuse*/
- rxtid->rxbuf = NULL;
- }
-}
-
-/* Initialize per-node receive state */
-
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
-{
- if (sc->sc_flags & SC_OP_RXAGGR) {
- struct ath_arx_tid *rxtid;
- int tidno;
-
- /* Init per tid rx state */
- for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
- tidno < WME_NUM_TID;
- tidno++, rxtid++) {
- rxtid->an = an;
- rxtid->seq_reset = 1;
- rxtid->seq_next = 0;
- rxtid->baw_size = WME_MAX_BA;
- rxtid->baw_head = rxtid->baw_tail = 0;
-
- /*
- * Ensure the buffer pointer is null at this point
- * (needs to be allocated when addba is received)
- */
-
- rxtid->rxbuf = NULL;
- setup_timer(&rxtid->timer, ath_rx_timer,
- (unsigned long)rxtid);
- spin_lock_init(&rxtid->tidlock);
-
- /* ADDBA state */
- rxtid->addba_exchangecomplete = 0;
- }
- }
-}
-
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
-{
- if (sc->sc_flags & SC_OP_RXAGGR) {
- struct ath_arx_tid *rxtid;
- int tidno, i;
-
- /* Init per tid rx state */
- for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
- tidno < WME_NUM_TID;
- tidno++, rxtid++) {
-
- if (!rxtid->addba_exchangecomplete)
- continue;
-
- /* must cancel timer first */
- del_timer_sync(&rxtid->timer);
-
- /* drop any pending sub-frames */
- ath_rx_flush_tid(sc, rxtid, 1);
-
- for (i = 0; i < ATH_TID_MAX_BUFS; i++)
- ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL);
-
- rxtid->addba_exchangecomplete = 0;
- }
- }
-
-}
-
-/* Cleanup per-node receive state */
-
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
- ath_rx_node_cleanup(sc, an);
-}
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
index 60617ae6620..9fedb4911bc 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -671,7 +671,11 @@
#define AR_RC_APB 0x00000002
#define AR_RC_HOSTIF 0x00000100
-#define AR_WA 0x4004
+#define AR_WA 0x4004
+#define AR9285_WA_DEFAULT 0x004a05cb
+#define AR9280_WA_DEFAULT 0x0040073f
+#define AR_WA_DEFAULT 0x0000073f
+
#define AR_PM_STATE 0x4008
#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
@@ -738,6 +742,8 @@
#define AR_SREV_REVISION_9280_21 2
#define AR_SREV_VERSION_9285 0xC0
#define AR_SREV_REVISION_9285_10 0
+#define AR_SREV_REVISION_9285_11 1
+#define AR_SREV_REVISION_9285_12 2
#define AR_SREV_9100_OR_LATER(_ah) \
(((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE))
@@ -768,6 +774,16 @@
#define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285))
#define AR_SREV_9285_10_OR_LATER(_ah) \
(((_ah)->ah_macVersion >= AR_SREV_VERSION_9285))
+#define AR_SREV_9285_11(_ah) \
+ (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11))
+#define AR_SREV_9285_11_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
+ (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11)))
+#define AR_SREV_9285_12(_ah) \
+ (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12))
+#define AR_SREV_9285_12_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \
+ (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12)))
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
@@ -1017,6 +1033,97 @@ enum {
#define AR_AN_SYNTH9_REFDIVA 0xf8000000
#define AR_AN_SYNTH9_REFDIVA_S 27
+#define AR9285_AN_RF2G1 0x7820
+#define AR9285_AN_RF2G1_ENPACAL 0x00000800
+#define AR9285_AN_RF2G1_ENPACAL_S 11
+#define AR9285_AN_RF2G1_PDPADRV1 0x02000000
+#define AR9285_AN_RF2G1_PDPADRV1_S 25
+#define AR9285_AN_RF2G1_PDPADRV2 0x01000000
+#define AR9285_AN_RF2G1_PDPADRV2_S 24
+#define AR9285_AN_RF2G1_PDPAOUT 0x00800000
+#define AR9285_AN_RF2G1_PDPAOUT_S 23
+
+
+#define AR9285_AN_RF2G2 0x7824
+#define AR9285_AN_RF2G2_OFFCAL 0x00001000
+#define AR9285_AN_RF2G2_OFFCAL_S 12
+
+#define AR9285_AN_RF2G3 0x7828
+#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000
+#define AR9285_AN_RF2G3_PDVCCOMP_S 25
+#define AR9285_AN_RF2G3_OB_0 0x00E00000
+#define AR9285_AN_RF2G3_OB_0_S 21
+#define AR9285_AN_RF2G3_OB_1 0x001C0000
+#define AR9285_AN_RF2G3_OB_1_S 18
+#define AR9285_AN_RF2G3_OB_2 0x00038000
+#define AR9285_AN_RF2G3_OB_2_S 15
+#define AR9285_AN_RF2G3_OB_3 0x00007000
+#define AR9285_AN_RF2G3_OB_3_S 12
+#define AR9285_AN_RF2G3_OB_4 0x00000E00
+#define AR9285_AN_RF2G3_OB_4_S 9
+
+#define AR9285_AN_RF2G3_DB1_0 0x000001C0
+#define AR9285_AN_RF2G3_DB1_0_S 6
+#define AR9285_AN_RF2G3_DB1_1 0x00000038
+#define AR9285_AN_RF2G3_DB1_1_S 3
+#define AR9285_AN_RF2G3_DB1_2 0x00000007
+#define AR9285_AN_RF2G3_DB1_2_S 0
+#define AR9285_AN_RF2G4 0x782C
+#define AR9285_AN_RF2G4_DB1_3 0xE0000000
+#define AR9285_AN_RF2G4_DB1_3_S 29
+#define AR9285_AN_RF2G4_DB1_4 0x1C000000
+#define AR9285_AN_RF2G4_DB1_4_S 26
+
+#define AR9285_AN_RF2G4_DB2_0 0x03800000
+#define AR9285_AN_RF2G4_DB2_0_S 23
+#define AR9285_AN_RF2G4_DB2_1 0x00700000
+#define AR9285_AN_RF2G4_DB2_1_S 20
+#define AR9285_AN_RF2G4_DB2_2 0x000E0000
+#define AR9285_AN_RF2G4_DB2_2_S 17
+#define AR9285_AN_RF2G4_DB2_3 0x0001C000
+#define AR9285_AN_RF2G4_DB2_3_S 14
+#define AR9285_AN_RF2G4_DB2_4 0x00003800
+#define AR9285_AN_RF2G4_DB2_4_S 11
+
+#define AR9285_AN_RF2G6 0x7834
+#define AR9285_AN_RF2G6_CCOMP 0x00007800
+#define AR9285_AN_RF2G6_CCOMP_S 11
+#define AR9285_AN_RF2G6_OFFS 0x03f00000
+#define AR9285_AN_RF2G6_OFFS_S 20
+
+#define AR9285_AN_RF2G7 0x7838
+#define AR9285_AN_RF2G7_PWDDB 0x00000002
+#define AR9285_AN_RF2G7_PWDDB_S 1
+#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000
+#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29
+
+#define AR9285_AN_RF2G8 0x783C
+#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000
+#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14
+
+
+#define AR9285_AN_RF2G9 0x7840
+#define AR9285_AN_RXTXBB1 0x7854
+#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020
+#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5
+#define AR9285_AN_RXTXBB1_PDV2I 0x00000080
+#define AR9285_AN_RXTXBB1_PDV2I_S 7
+#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100
+#define AR9285_AN_RXTXBB1_PDDACIF_S 8
+#define AR9285_AN_RXTXBB1_SPARE9 0x00000001
+#define AR9285_AN_RXTXBB1_SPARE9_S 0
+
+#define AR9285_AN_TOP2 0x7868
+
+#define AR9285_AN_TOP3 0x786c
+#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C
+#define AR9285_AN_TOP3_XPABIAS_LVL_S 2
+#define AR9285_AN_TOP3_PWDDAC 0x00800000
+#define AR9285_AN_TOP3_PWDDAC_S 23
+
+#define AR9285_AN_TOP4 0x7870
+#define AR9285_AN_TOP4_DEFAULT 0x10142c00
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
index 62e28887ccd..64043e99fac 100644
--- a/drivers/net/wireless/ath9k/regd.c
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -42,7 +42,7 @@ ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp)
u8 *u = t - size;
if (cmp(u, t) <= 0)
break;
- swap(u, t, size);
+ swap_array(u, t, size);
}
}
@@ -78,8 +78,7 @@ static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
return true;
}
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: invalid regulatory domain/country code 0x%x\n",
- __func__, rd);
+ "invalid regulatory domain/country code 0x%x\n", rd);
return false;
}
@@ -107,13 +106,12 @@ static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah,
return true;
rd = ath9k_regd_get_eepromRD(ah);
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n",
- __func__, rd);
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd);
if (rd & COUNTRY_ERD_FLAG) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: EEPROM setting is country code %u\n",
- __func__, rd & ~COUNTRY_ERD_FLAG);
+ "EEPROM setting is country code %u\n",
+ rd & ~COUNTRY_ERD_FLAG);
return cc == (rd & ~COUNTRY_ERD_FLAG);
}
@@ -290,8 +288,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
}
if (!found) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Failed to find reg domain pair %u\n",
- __func__, regDmn);
+ "Failed to find reg domain pair %u\n", regDmn);
return false;
}
if (!(channelFlag & CHANNEL_2GHZ)) {
@@ -307,8 +304,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
if (!found) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Failed to find unitary reg domain %u\n",
- __func__, regDmn);
+ "Failed to find unitary reg domain %u\n", regDmn);
return false;
} else {
rd->pscan &= regPair->pscanMask;
@@ -430,30 +426,27 @@ ath9k_regd_add_channel(struct ath_hal *ah,
if (!(c_lo <= c && c <= c_hi)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: c %u out of range [%u..%u]\n",
- __func__, c, c_lo, c_hi);
+ "c %u out of range [%u..%u]\n",
+ c, c_lo, c_hi);
return false;
}
if ((fband->channelBW == CHANNEL_HALF_BW) &&
!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Skipping %u half rate channel\n",
- __func__, c);
+ "Skipping %u half rate channel\n", c);
return false;
}
if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Skipping %u quarter rate channel\n",
- __func__, c);
+ "Skipping %u quarter rate channel\n", c);
return false;
}
if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: c %u > maxChan %u\n",
- __func__, c, maxChan);
+ "c %u > maxChan %u\n", c, maxChan);
return false;
}
@@ -463,7 +456,7 @@ ath9k_regd_add_channel(struct ath_hal *ah,
return false;
}
- if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
+ if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
"Skipping HOSTAP channel\n");
return false;
@@ -606,8 +599,7 @@ static bool ath9k_regd_japan_check(struct ath_hal *ah,
}
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Skipping %d freq band\n",
- __func__, j_bandcheck[i].freqbandbit);
+ "Skipping %d freq band\n", j_bandcheck[i].freqbandbit);
return skipband;
}
@@ -632,20 +624,19 @@ ath9k_regd_init_channels(struct ath_hal *ah,
unsigned long *modes_avail;
DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
- __func__, cc,
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc,
enableOutdoor ? "Enable outdoor" : "",
enableExtendedChannels ? "Enable ecm" : "");
if (!ath9k_regd_is_ccode_valid(ah, cc)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: invalid country code %d\n", __func__, cc);
+ "Invalid country code %d\n", cc);
return false;
}
if (!ath9k_regd_is_eeprom_valid(ah)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: invalid EEPROM contents\n", __func__);
+ "Invalid EEPROM contents\n");
return false;
}
@@ -693,9 +684,9 @@ ath9k_regd_init_channels(struct ath_hal *ah,
~CHANNEL_2GHZ,
&rd5GHz)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: couldn't find unitary "
+ "Couldn't find unitary "
"5GHz reg domain for country %u\n",
- __func__, ah->ah_countryCode);
+ ah->ah_countryCode);
return false;
}
if (!ath9k_regd_get_wmode_regdomain(ah,
@@ -703,9 +694,9 @@ ath9k_regd_init_channels(struct ath_hal *ah,
CHANNEL_2GHZ,
&rd2GHz)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: couldn't find unitary 2GHz "
+ "Couldn't find unitary 2GHz "
"reg domain for country %u\n",
- __func__, ah->ah_countryCode);
+ ah->ah_countryCode);
return false;
}
@@ -717,9 +708,9 @@ ath9k_regd_init_channels(struct ath_hal *ah,
~CHANNEL_2GHZ,
&rd5GHz)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: couldn't find unitary 5GHz "
+ "Couldn't find unitary 5GHz "
"reg domain for country %u\n",
- __func__, ah->ah_countryCode);
+ ah->ah_countryCode);
return false;
}
}
@@ -749,15 +740,14 @@ ath9k_regd_init_channels(struct ath_hal *ah,
if (!test_bit(cm->mode, modes_avail)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: !avail mode %d flags 0x%x\n",
- __func__, cm->mode, cm->flags);
+ "!avail mode %d flags 0x%x\n",
+ cm->mode, cm->flags);
continue;
}
if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: channels 0x%x not supported "
- "by hardware\n",
- __func__, cm->flags);
+ "channels 0x%x not supported "
+ "by hardware\n", cm->flags);
continue;
}
@@ -788,8 +778,7 @@ ath9k_regd_init_channels(struct ath_hal *ah,
break;
default:
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: Unknown HAL mode 0x%x\n", __func__,
- cm->mode);
+ "Unknown HAL mode 0x%x\n", cm->mode);
continue;
}
@@ -841,9 +830,8 @@ ath9k_regd_init_channels(struct ath_hal *ah,
if (next >= maxchans) {
DPRINTF(ah->ah_sc,
ATH_DBG_REGULATORY,
- "%s: too many channels "
- "for channel table\n",
- __func__);
+ "too many channels "
+ "for channel table\n");
goto done;
}
if (ath9k_regd_add_channel(ah,
@@ -869,9 +857,8 @@ done:
if (next > ARRAY_SIZE(ah->ah_channels)) {
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: too many channels %u; truncating to %u\n",
- __func__, next,
- (int) ARRAY_SIZE(ah->ah_channels));
+ "too many channels %u; truncating to %u\n",
+ next, (int) ARRAY_SIZE(ah->ah_channels));
next = ARRAY_SIZE(ah->ah_channels);
}
#ifdef ATH_NF_PER_CHAN
@@ -919,7 +906,7 @@ ath9k_regd_check_channel(struct ath_hal *ah,
int n, lim;
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: channel %u/0x%x (0x%x) requested\n", __func__,
+ "channel %u/0x%x (0x%x) requested\n",
c->channel, c->channelFlags, flags);
cc = ah->ah_curchan;
@@ -950,15 +937,15 @@ ath9k_regd_check_channel(struct ath_hal *ah,
d = flags - (cc->channelFlags & CHAN_FLAGS);
}
DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "%s: channel %u/0x%x d %d\n", __func__,
+ "channel %u/0x%x d %d\n",
cc->channel, cc->channelFlags, d);
if (d > 0) {
base = cc + 1;
lim--;
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
- __func__, c->channel, c->channelFlags);
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n",
+ c->channel, c->channelFlags);
return NULL;
}
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h
index 0ecd344fbd9..512d990aa7e 100644
--- a/drivers/net/wireless/ath9k/regd.h
+++ b/drivers/net/wireless/ath9k/regd.h
@@ -125,7 +125,7 @@
#define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)
-#define swap(_a, _b, _size) { \
+#define swap_array(_a, _b, _size) { \
u8 *s = _b; \
int i = _size; \
do { \
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3a4757942b3..3bfc3b90f25 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -14,10 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * Implementation of transmit path.
- */
-
#include "core.h"
#define BITS_PER_BYTE 8
@@ -65,11 +61,12 @@ static u32 bits_per_symbol[][2] = {
* NB: must be called with txq lock held
*/
-static void ath_tx_txqaddbuf(struct ath_softc *sc,
- struct ath_txq *txq, struct list_head *head)
+static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+ struct list_head *head)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
+
/*
* Insert the frame on the outbound list and
* pass it on to the hardware.
@@ -86,18 +83,16 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc,
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
DPRINTF(sc, ATH_DBG_QUEUE,
- "%s: txq depth = %d\n", __func__, txq->axq_depth);
+ "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
if (txq->axq_link == NULL) {
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
DPRINTF(sc, ATH_DBG_XMIT,
- "%s: TXDP[%u] = %llx (%p)\n",
- __func__, txq->axq_qnum,
- ito64(bf->bf_daddr), bf->bf_desc);
+ "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
} else {
*txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n",
- __func__,
+ DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
txq->axq_qnum, txq->axq_link,
ito64(bf->bf_daddr), bf->bf_desc);
}
@@ -105,46 +100,94 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc,
ath9k_hw_txstart(ah, txq->axq_qnum);
}
-/* Get transmit rate index using rate in Kbps */
-
-static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
+static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_xmit_status *tx_status)
{
- int i;
- int ndx = 0;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ int hdrlen, padsize;
- for (i = 0; i < rt->rateCount; i++) {
- if (rt->info[i].rateKbps == rate) {
- ndx = i;
- break;
- }
+ DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+ tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+ kfree(tx_info_priv);
+ tx_info->rate_driver_data[0] = NULL;
+ }
+
+ if (tx_status->flags & ATH_TX_BAR) {
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ tx_status->flags &= ~ATH_TX_BAR;
+ }
+
+ if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
+ /* Frame was ACKed */
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
+
+ tx_info->status.rates[0].count = tx_status->retries;
+ if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
+ /* Change idx from internal table index to MCS index */
+ int idx = tx_info->status.rates[0].idx;
+ struct ath_rate_table *rate_table = sc->cur_rate_table;
+ if (idx >= 0 && idx < rate_table->rate_cnt)
+ tx_info->status.rates[0].idx =
+ rate_table->info[idx].ratecode & 0x7f;
+ }
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ padsize = hdrlen & 3;
+ if (padsize && hdrlen >= 24) {
+ /*
+ * Remove MAC header padding before giving the frame back to
+ * mac80211.
+ */
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
}
- return ndx;
+ ieee80211_tx_status(hw, skb);
}
/* Check if it's okay to send out aggregates */
-static int ath_aggr_query(struct ath_softc *sc,
- struct ath_node *an, u8 tidno)
+static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
{
struct ath_atx_tid *tid;
tid = ATH_AN_2_TID(an, tidno);
- if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress)
+ if (tid->state & AGGR_ADDBA_COMPLETE ||
+ tid->state & AGGR_ADDBA_PROGRESS)
return 1;
else
return 0;
}
-static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
+static void ath_get_beaconconfig(struct ath_softc *sc, int if_id,
+ struct ath_beacon_config *conf)
+{
+ struct ieee80211_hw *hw = sc->hw;
+
+ /* fill in beacon config data */
+
+ conf->beacon_interval = hw->conf.beacon_int;
+ conf->listen_interval = 100;
+ conf->dtim_count = 1;
+ conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
+}
+
+/* Calculate Atheros packet type from IEEE80211 packet header */
+
+static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
{
+ struct ieee80211_hdr *hdr;
enum ath9k_pkt_type htype;
__le16 fc;
+ hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
- /* Calculate Atheros packet type from IEEE80211 packet header */
-
if (ieee80211_is_beacon(fc))
htype = ATH9K_PKT_TYPE_BEACON;
else if (ieee80211_is_probe_resp(fc))
@@ -159,232 +202,123 @@ static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
return htype;
}
-static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl)
+static bool is_pae(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_tx_info_priv *tx_info_priv;
__le16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
- txctl->use_minrate = 1;
- txctl->min_rate = tx_info_priv->min_rate;
- } else if (ieee80211_is_data(fc)) {
+ if (ieee80211_is_data(fc)) {
if (ieee80211_is_nullfunc(fc) ||
- /* Port Access Entity (IEEE 802.1X) */
- (skb->protocol == cpu_to_be16(0x888E))) {
- txctl->use_minrate = 1;
- txctl->min_rate = tx_info_priv->min_rate;
+ /* Port Access Entity (IEEE 802.1X) */
+ (skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+ return true;
}
- if (is_multicast_ether_addr(hdr->addr1))
- txctl->mcast_rate = tx_info_priv->min_rate;
}
+ return false;
}
-/* This function will setup additional txctl information, mostly rate stuff */
-/* FIXME: seqno, ps */
-static int ath_tx_prepare(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_tx_control *txctl)
+static int get_hw_crypto_keytype(struct sk_buff *skb)
{
- struct ieee80211_hw *hw = sc->hw;
- struct ieee80211_hdr *hdr;
- struct ath_rc_series *rcs;
- struct ath_txq *txq = NULL;
- const struct ath9k_rate_table *rt;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_tx_info_priv *tx_info_priv;
- int hdrlen;
- u8 rix, antenna;
- __le16 fc;
- u8 *qc;
-
- txctl->dev = sc;
- hdr = (struct ieee80211_hdr *)skb->data;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
-
- rt = sc->sc_currates;
- BUG_ON(!rt);
-
- /* Fill misc fields */
-
- spin_lock_bh(&sc->node_lock);
- txctl->an = ath_node_get(sc, hdr->addr1);
- /* create a temp node, if the node is not there already */
- if (!txctl->an)
- txctl->an = ath_node_attach(sc, hdr->addr1, 0);
- spin_unlock_bh(&sc->node_lock);
-
- if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
- txctl->tidno = qc[0] & 0xf;
- }
-
- txctl->if_id = 0;
- txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
- txctl->txpower = MAX_RATE_POWER; /* FIXME */
-
- /* Fill Key related fields */
-
- txctl->keytype = ATH9K_KEY_TYPE_CLEAR;
- txctl->keyix = ATH9K_TXKEYIX_INVALID;
if (tx_info->control.hw_key) {
- txctl->keyix = tx_info->control.hw_key->hw_key_idx;
- txctl->frmlen += tx_info->control.hw_key->icv_len;
-
if (tx_info->control.hw_key->alg == ALG_WEP)
- txctl->keytype = ATH9K_KEY_TYPE_WEP;
+ return ATH9K_KEY_TYPE_WEP;
else if (tx_info->control.hw_key->alg == ALG_TKIP)
- txctl->keytype = ATH9K_KEY_TYPE_TKIP;
+ return ATH9K_KEY_TYPE_TKIP;
else if (tx_info->control.hw_key->alg == ALG_CCMP)
- txctl->keytype = ATH9K_KEY_TYPE_AES;
- }
-
- /* Fill packet type */
-
- txctl->atype = get_hal_packet_type(hdr);
-
- /* Fill qnum */
-
- if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) {
- txctl->qnum = 0;
- txq = sc->sc_cabq;
- } else {
- txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
- txq = &sc->sc_txq[txctl->qnum];
- }
- spin_lock_bh(&txq->axq_lock);
-
- /* Try to avoid running out of descriptors */
- if (txq->axq_depth >= (ATH_TXBUF - 20) &&
- !(txctl->flags & ATH9K_TXDESC_CAB)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "%s: TX queue: %d is full, depth: %d\n",
- __func__,
- txctl->qnum,
- txq->axq_depth);
- ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
- txq->stopped = 1;
- spin_unlock_bh(&txq->axq_lock);
- return -1;
+ return ATH9K_KEY_TYPE_AES;
}
- spin_unlock_bh(&txq->axq_lock);
-
- /* Fill rate */
-
- fill_min_rates(skb, txctl);
+ return ATH9K_KEY_TYPE_CLEAR;
+}
- /* Fill flags */
+/* Called only when tx aggregation is enabled and HT is supported */
- txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+static void assign_aggr_tid_seqno(struct sk_buff *skb,
+ struct ath_buf *bf)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+ struct ath_node *an;
+ struct ath_atx_tid *tid;
+ __le16 fc;
+ u8 *qc;
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
- txctl->flags |= ATH9K_TXDESC_NOACK;
- if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
- txctl->flags |= ATH9K_TXDESC_RTSENA;
+ if (!tx_info->control.sta)
+ return;
- /*
- * Setup for rate calculations.
- */
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- rcs = tx_info_priv->rcs;
+ an = (struct ath_node *)tx_info->control.sta->drv_priv;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
- if (ieee80211_is_data(fc) && !txctl->use_minrate) {
+ /* Get tidno */
- /* Enable HT only for DATA frames and not for EAPOL */
- txctl->ht = (hw->conf.ht_conf.ht_supported &&
- (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ bf->bf_tidno = qc[0] & 0xf;
+ }
- if (is_multicast_ether_addr(hdr->addr1)) {
- rcs[0].rix = (u8)
- ath_tx_findindex(rt, txctl->mcast_rate);
+ /* Get seqno */
- /*
- * mcast packets are not re-tried.
- */
- rcs[0].tries = 1;
- }
+ if (ieee80211_is_data(fc) && !is_pae(skb)) {
/* For HT capable stations, we save tidno for later use.
* We also override seqno set by upper layer with the one
* in tx aggregation state.
*
- * First, the fragmentation stat is determined.
* If fragmentation is on, the sequence number is
* not overridden, since it has been
* incremented by the fragmentation routine.
+ *
+ * FIXME: check if the fragmentation threshold exceeds
+ * IEEE80211 max.
*/
- if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
- txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
- struct ath_atx_tid *tid;
+ tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
+ IEEE80211_SEQ_SEQ_SHIFT);
+ bf->bf_seqno = tid->seq_next;
+ INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+ }
+}
- tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
+static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_txq *txq)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ int flags = 0;
- hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
- IEEE80211_SEQ_SEQ_SHIFT);
- txctl->seqno = tid->seq_next;
- INCR(tid->seq_next, IEEE80211_SEQ_MAX);
- }
- } else {
- /* for management and control frames,
- * or for NULL and EAPOL frames */
- if (txctl->min_rate)
- rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate);
- else
- rcs[0].rix = 0;
- rcs[0].tries = ATH_MGT_TXMAXTRY;
- }
- rix = rcs[0].rix;
+ flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+ flags |= ATH9K_TXDESC_INTREQ;
- if (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
- /*
- ** Force hardware to use computed duration for next
- ** fragment by disabling multi-rate retry, which
- ** updates duration based on the multi-rate
- ** duration table.
- */
- rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
- rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
- /* reset tries but keep rate index */
- rcs[0].tries = ATH_TXMAXTRY;
- }
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ flags |= ATH9K_TXDESC_NOACK;
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ flags |= ATH9K_TXDESC_RTSENA;
- /*
- * Determine if a tx interrupt should be generated for
- * this descriptor. We take a tx interrupt to reap
- * descriptors when the h/w hits an EOL condition or
- * when the descriptor is specifically marked to generate
- * an interrupt. We periodically mark descriptors in this
- * way to insure timely replenishing of the supply needed
- * for sending frames. Defering interrupts reduces system
- * load and potentially allows more concurrent work to be
- * done but if done to aggressively can cause senders to
- * backup.
- *
- * NB: use >= to deal with sc_txintrperiod changing
- * dynamically through sysctl.
- */
- spin_lock_bh(&txq->axq_lock);
- if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) {
- txctl->flags |= ATH9K_TXDESC_INTREQ;
- txq->axq_intrcnt = 0;
- }
- spin_unlock_bh(&txq->axq_lock);
+ return flags;
+}
+
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
+{
+ struct ath_buf *bf = NULL;
- if (is_multicast_ether_addr(hdr->addr1)) {
- antenna = sc->sc_mcastantenna + 1;
- sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
+ spin_lock_bh(&sc->tx.txbuflock);
+
+ if (unlikely(list_empty(&sc->tx.txbuf))) {
+ spin_unlock_bh(&sc->tx.txbuflock);
+ return NULL;
}
- return 0;
+ bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+ list_del(&bf->list);
+
+ spin_unlock_bh(&sc->tx.txbuflock);
+
+ return bf;
}
/* To complete a chain of buffers associated a frame */
@@ -396,6 +330,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_xmit_status tx_status;
+ unsigned long flags;
/*
* Set retry information.
@@ -414,20 +349,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
if (bf_isxretried(bf))
tx_status.flags |= ATH_TX_XRETRY;
}
+
/* Unmap this frame */
pci_unmap_single(sc->pdev,
bf->bf_dmacontext,
skb->len,
PCI_DMA_TODEVICE);
/* complete this frame */
- ath_tx_complete(sc, skb, &tx_status, bf->bf_node);
+ ath_tx_complete(sc, skb, &tx_status);
/*
* Return the list of ath_buf of this mpdu to free queue
*/
- spin_lock_bh(&sc->sc_txbuflock);
- list_splice_tail_init(bf_q, &sc->sc_txbuf);
- spin_unlock_bh(&sc->sc_txbuflock);
+ spin_lock_irqsave(&sc->tx.txbuflock, flags);
+ list_splice_tail_init(bf_q, &sc->tx.txbuf);
+ spin_unlock_irqrestore(&sc->tx.txbuflock, flags);
}
/*
@@ -468,7 +404,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
- struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+ struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
spin_lock_bh(&txq->axq_lock);
@@ -481,7 +417,7 @@ static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
- struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+ struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
ASSERT(tid->paused > 0);
spin_lock_bh(&txq->axq_lock);
@@ -505,11 +441,9 @@ unlock:
/* Compute the number of bad frames */
-static int ath_tx_num_badfrms(struct ath_softc *sc,
- struct ath_buf *bf, int txok)
+static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
+ int txok)
{
- struct ath_node *an = bf->bf_node;
- int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
struct ath_buf *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc;
u16 seq_st = 0;
@@ -518,7 +452,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc,
int nbad = 0;
int isaggr = 0;
- if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+ if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
return 0;
isaggr = bf_isaggr(bf);
@@ -553,8 +487,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
/* Update block ack window */
-static void ath_tx_update_baw(struct ath_softc *sc,
- struct ath_atx_tid *tid, int seqno)
+static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+ int seqno)
{
int index, cindex;
@@ -577,34 +511,23 @@ static void ath_tx_update_baw(struct ath_softc *sc,
* width - 0 for 20 MHz, 1 for 40 MHz
* half_gi - to use 4us v/s 3.6 us for symbol time
*/
-
-static u32 ath_pkt_duration(struct ath_softc *sc,
- u8 rix,
- struct ath_buf *bf,
- int width,
- int half_gi,
- bool shortPreamble)
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
+ int width, int half_gi, bool shortPreamble)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rate_table = sc->cur_rate_table;
u32 nbits, nsymbits, duration, nsymbols;
u8 rc;
int streams, pktlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
- rc = rt->info[rix].rateCode;
+ rc = rate_table->info[rix].ratecode;
- /*
- * for legacy rates, use old function to compute packet duration
- */
+ /* for legacy rates, use old function to compute packet duration */
if (!IS_HT_RATE(rc))
- return ath9k_hw_computetxtime(sc->sc_ah,
- rt,
- pktlen,
- rix,
- shortPreamble);
- /*
- * find number of symbols: PLCP + data
- */
+ return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
+ rix, shortPreamble);
+
+ /* find number of symbols: PLCP + data */
nbits = (pktlen << 3) + OFDM_PLCP_BITS;
nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
nsymbols = (nbits + nsymbits - 1) / nsymbits;
@@ -614,11 +537,10 @@ static u32 ath_pkt_duration(struct ath_softc *sc,
else
duration = SYMBOL_TIME_HALFGI(nsymbols);
- /*
- * addup duration for legacy/ht training and signal fields
- */
+ /* addup duration for legacy/ht training and signal fields */
streams = HT_RC_2_STREAMS(rc);
duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+
return duration;
}
@@ -627,207 +549,127 @@ static u32 ath_pkt_duration(struct ath_softc *sc,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
- const struct ath9k_rate_table *rt;
+ struct ath_rate_table *rt;
struct ath_desc *ds = bf->bf_desc;
struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
struct ath9k_11n_rate_series series[4];
- int i, flags, rtsctsena = 0, dynamic_mimops = 0;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rates;
+ struct ieee80211_hdr *hdr;
+ int i, flags, rtsctsena = 0;
u32 ctsduration = 0;
u8 rix = 0, cix, ctsrate = 0;
- u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit;
- struct ath_node *an = (struct ath_node *) bf->bf_node;
+ __le16 fc;
- /*
- * get the cix for the lowest valid rix.
- */
- rt = sc->sc_currates;
- for (i = 4; i--;) {
- if (bf->bf_rcs[i].tries) {
- rix = bf->bf_rcs[i].rix;
+ memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ tx_info = IEEE80211_SKB_CB(skb);
+ rates = tx_info->control.rates;
+
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
+ rates[1].count = rates[2].count = rates[3].count = 0;
+ rates[1].idx = rates[2].idx = rates[3].idx = 0;
+ rates[0].count = ATH_TXMAXTRY;
+ }
+
+ /* get the cix for the lowest valid rix */
+ rt = sc->cur_rate_table;
+ for (i = 3; i >= 0; i--) {
+ if (rates[i].count && (rates[i].idx >= 0)) {
+ rix = rates[i].idx;
break;
}
}
+
flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
- cix = rt->info[rix].controlRate;
+ cix = rt->info[rix].ctrl_rate;
/*
- * If 802.11g protection is enabled, determine whether
- * to use RTS/CTS or just CTS. Note that this is only
- * done for OFDM/HT unicast frames.
+ * If 802.11g protection is enabled, determine whether to use RTS/CTS or
+ * just CTS. Note that this is only done for OFDM/HT unicast frames.
*/
- if (sc->sc_protmode != PROT_M_NONE &&
- (rt->info[rix].phy == PHY_OFDM ||
- rt->info[rix].phy == PHY_HT) &&
- (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+ if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
+ && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
+ WLAN_RC_PHY_HT(rt->info[rix].phy))) {
if (sc->sc_protmode == PROT_M_RTSCTS)
flags = ATH9K_TXDESC_RTSENA;
else if (sc->sc_protmode == PROT_M_CTSONLY)
flags = ATH9K_TXDESC_CTSENA;
- cix = rt->info[sc->sc_protrix].controlRate;
+ cix = rt->info[sc->sc_protrix].ctrl_rate;
rtsctsena = 1;
}
- /* For 11n, the default behavior is to enable RTS for
- * hw retried frames. We enable the global flag here and
- * let rate series flags determine which rates will actually
- * use RTS.
+ /* For 11n, the default behavior is to enable RTS for hw retried frames.
+ * We enable the global flag here and let rate series flags determine
+ * which rates will actually use RTS.
*/
if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
- BUG_ON(!an);
- /*
- * 802.11g protection not needed, use our default behavior
- */
+ /* 802.11g protection not needed, use our default behavior */
if (!rtsctsena)
flags = ATH9K_TXDESC_RTSENA;
- /*
- * For dynamic MIMO PS, RTS needs to precede the first aggregate
- * and the second aggregate should have any protection at all.
- */
- if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
- if (!bf_isaggrburst(bf)) {
- flags = ATH9K_TXDESC_RTSENA;
- dynamic_mimops = 1;
- } else {
- flags = 0;
- }
- }
}
- /*
- * Set protection if aggregate protection on
- */
+ /* Set protection if aggregate protection on */
if (sc->sc_config.ath_aggr_prot &&
(!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
flags = ATH9K_TXDESC_RTSENA;
- cix = rt->info[sc->sc_protrix].controlRate;
+ cix = rt->info[sc->sc_protrix].ctrl_rate;
rtsctsena = 1;
}
- /*
- * For AR5416 - RTS cannot be followed by a frame larger than 8K.
- */
- if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) {
- /*
- * Ensure that in the case of SM Dynamic power save
- * while we are bursting the second aggregate the
- * RTS is cleared.
- */
+ /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+ if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit))
flags &= ~(ATH9K_TXDESC_RTSENA);
- }
/*
- * CTS transmit rate is derived from the transmit rate
- * by looking in the h/w rate table. We must also factor
- * in whether or not a short preamble is to be used.
+ * CTS transmit rate is derived from the transmit rate by looking in the
+ * h/w rate table. We must also factor in whether or not a short
+ * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
*/
- /* NB: cix is set above where RTS/CTS is enabled */
- BUG_ON(cix == 0xff);
- ctsrate = rt->info[cix].rateCode |
- (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
-
- /*
- * Setup HAL rate series
- */
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+ ctsrate = rt->info[cix].ratecode |
+ (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
for (i = 0; i < 4; i++) {
- if (!bf->bf_rcs[i].tries)
+ if (!rates[i].count || (rates[i].idx < 0))
continue;
- rix = bf->bf_rcs[i].rix;
+ rix = rates[i].idx;
- series[i].Rate = rt->info[rix].rateCode |
- (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0);
+ series[i].Rate = rt->info[rix].ratecode |
+ (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
- series[i].Tries = bf->bf_rcs[i].tries;
+ series[i].Tries = rates[i].count;
series[i].RateFlags = (
- (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ?
+ (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
ATH9K_RATESERIES_RTS_CTS : 0) |
- ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ?
+ ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
ATH9K_RATESERIES_2040 : 0) |
- ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
+ ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
ATH9K_RATESERIES_HALFGI : 0);
- series[i].PktDuration = ath_pkt_duration(
- sc, rix, bf,
- (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
- (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
- bf_isshpreamble(bf));
+ series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+ (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
+ (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
+ bf_isshpreamble(bf));
- if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
- (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
- /*
- * When sending to an HT node that has enabled static
- * SM/MIMO power save, send at single stream rates but
- * use maximum allowed transmit chains per user,
- * hardware, regulatory, or country limits for
- * better range.
- */
- series[i].ChSel = sc->sc_tx_chainmask;
- } else {
- if (bf_isht(bf))
- series[i].ChSel =
- ath_chainmask_sel_logic(sc, an);
- else
- series[i].ChSel = sc->sc_tx_chainmask;
- }
+ series[i].ChSel = sc->sc_tx_chainmask;
if (rtsctsena)
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
-
- /*
- * Set RTS for all rates if node is in dynamic powersave
- * mode and we are using dual stream rates.
- */
- if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG))
- series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
- }
-
- /*
- * For non-HT devices, calculate RTS/CTS duration in software
- * and disable multi-rate retry.
- */
- if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) {
- /*
- * Compute the transmit duration based on the frame
- * size and the size of an ACK frame. We call into the
- * HAL to do the computation since it depends on the
- * characteristics of the actual PHY being used.
- *
- * NB: CTS is assumed the same size as an ACK so we can
- * use the precalculated ACK durations.
- */
- if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */
- ctsduration += bf_isshpreamble(bf) ?
- rt->info[cix].spAckDuration :
- rt->info[cix].lpAckDuration;
- }
-
- ctsduration += series[0].PktDuration;
-
- if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
- ctsduration += bf_isshpreamble(bf) ?
- rt->info[rix].spAckDuration :
- rt->info[rix].lpAckDuration;
- }
-
- /*
- * Disable multi-rate retry when using RTS/CTS by clearing
- * series 1, 2 and 3.
- */
- memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3);
}
- /*
- * set dur_update_en for l-sig computation except for PS-Poll frames
- */
- ath9k_hw_set11n_ratescenario(ah, ds, lastds,
- !bf_ispspoll(bf),
- ctsrate,
- ctsduration,
+ /* set dur_update_en for l-sig computation except for PS-Poll frames */
+ ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
+ ctsrate, ctsduration,
series, 4, flags);
+
if (sc->sc_config.ath_aggr_prot && flags)
ath9k_hw_set11n_burstduration(ah, ds, 8192);
}
@@ -836,27 +678,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* Function to send a normal HT (non-AMPDU) frame
* NB: must be called with txq lock held
*/
-
static int ath_tx_send_normal(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_head)
{
struct ath_buf *bf;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
BUG_ON(list_empty(bf_head));
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */
- skb = (struct sk_buff *)bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
/* update starting sequence number for subsequent ADDBA request */
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
@@ -873,7 +706,7 @@ static int ath_tx_send_normal(struct ath_softc *sc,
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
- struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+ struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
struct ath_buf *bf;
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
@@ -906,8 +739,10 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
struct list_head *bf_q,
int txok)
{
- struct ath_node *an = bf->bf_node;
- struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ struct ath_node *an = NULL;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_atx_tid *tid = NULL;
struct ath_buf *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc;
struct ath_buf *bf_next, *bf_lastq = NULL;
@@ -915,7 +750,14 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
u16 seq_st = 0;
u32 ba[WME_BA_BMP_SIZE >> 5];
int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
- int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
+
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+
+ if (tx_info->control.sta) {
+ an = (struct ath_node *)tx_info->control.sta->drv_priv;
+ tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ }
isaggr = bf_isaggr(bf);
if (isaggr) {
@@ -939,7 +781,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
* when perform internal reset in this routine.
* Only enable reset in STA mode for now.
*/
- if (sc->sc_ah->ah_opmode == ATH9K_M_STA)
+ if (sc->sc_ah->ah_opmode ==
+ NL80211_IFTYPE_STATION)
needreset = 1;
}
} else {
@@ -961,7 +804,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
/* transmit completion */
} else {
- if (!tid->cleanup_inprogress && !isnodegone &&
+ if (!(tid->state & AGGR_CLEANUP) &&
ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
ath_tx_set_retry(sc, bf);
@@ -1038,18 +881,17 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
struct ath_buf *tbf;
/* allocate new descriptor */
- spin_lock_bh(&sc->sc_txbuflock);
- ASSERT(!list_empty((&sc->sc_txbuf)));
- tbf = list_first_entry(&sc->sc_txbuf,
+ spin_lock_bh(&sc->tx.txbuflock);
+ ASSERT(!list_empty((&sc->tx.txbuf)));
+ tbf = list_first_entry(&sc->tx.txbuf,
struct ath_buf, list);
list_del(&tbf->list);
- spin_unlock_bh(&sc->sc_txbuflock);
+ spin_unlock_bh(&sc->tx.txbuflock);
ATH_TXBUF_RESET(tbf);
/* copy descriptor content */
tbf->bf_mpdu = bf_last->bf_mpdu;
- tbf->bf_node = bf_last->bf_node;
tbf->bf_buf_addr = bf_last->bf_buf_addr;
*(tbf->bf_desc) = *(bf_last->bf_desc);
@@ -1090,25 +932,16 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
bf = bf_next;
}
- /*
- * node is already gone. no more assocication
- * with the node. the node might have been freed
- * any node acces can result in panic.note tid
- * is part of the node.
- */
- if (isnodegone)
- return;
-
- if (tid->cleanup_inprogress) {
+ if (tid->state & AGGR_CLEANUP) {
/* check to see if we're done with cleaning the h/w queue */
spin_lock_bh(&txq->axq_lock);
if (tid->baw_head == tid->baw_tail) {
- tid->addba_exchangecomplete = 0;
+ tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->addba_exchangeattempts = 0;
spin_unlock_bh(&txq->axq_lock);
- tid->cleanup_inprogress = false;
+ tid->state &= ~AGGR_CLEANUP;
/* send buffered frames as singles */
ath_tx_flush_tid(sc, tid);
@@ -1136,29 +969,45 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
return;
}
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
+{
+ struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+
+ tx_info_priv->update_rc = false;
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+
+ if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+ (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+ if (bf_isdata(bf)) {
+ memcpy(&tx_info_priv->tx, &ds->ds_txstat,
+ sizeof(tx_info_priv->tx));
+ tx_info_priv->n_frames = bf->bf_nframes;
+ tx_info_priv->n_bad_frames = nbad;
+ tx_info_priv->update_rc = true;
+ }
+ }
+}
+
/* Process completed xmit descriptors from the specified queue */
-static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head;
- struct ath_desc *ds, *tmp_ds;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
- int nacked, txok, nbad = 0, isrifs = 0;
+ struct ath_desc *ds;
+ int txok, nbad = 0;
int status;
- DPRINTF(sc, ATH_DBG_QUEUE,
- "%s: tx queue %d (%x), link %p\n", __func__,
+ DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
txq->axq_link);
- nacked = 0;
for (;;) {
spin_lock_bh(&txq->axq_lock);
- txq->axq_intrcnt = 0; /* reset periodic desc intr count */
if (list_empty(&txq->axq_q)) {
txq->axq_link = NULL;
txq->axq_linkbuf = NULL;
@@ -1229,9 +1078,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf_held) {
list_del(&bf_held->list);
- spin_lock_bh(&sc->sc_txbuflock);
- list_add_tail(&bf_held->list, &sc->sc_txbuf);
- spin_unlock_bh(&sc->sc_txbuflock);
+ spin_lock_bh(&sc->tx.txbuflock);
+ list_add_tail(&bf_held->list, &sc->tx.txbuf);
+ spin_unlock_bh(&sc->tx.txbuflock);
}
if (!bf_isampdu(bf)) {
@@ -1246,29 +1095,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
} else {
nbad = ath_tx_num_badfrms(sc, bf, txok);
}
- skb = bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info_priv = (struct ath_tx_info_priv *)
- tx_info->driver_data[0];
- if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
- tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
- (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
- if (ds->ds_txstat.ts_status == 0)
- nacked++;
-
- if (bf_isdata(bf)) {
- if (isrifs)
- tmp_ds = bf->bf_rifslast->bf_desc;
- else
- tmp_ds = ds;
- memcpy(&tx_info_priv->tx,
- &tmp_ds->ds_txstat,
- sizeof(tx_info_priv->tx));
- tx_info_priv->n_frames = bf->bf_nframes;
- tx_info_priv->n_bad_frames = nbad;
- }
- }
+
+ ath_tx_rc_status(bf, ds, nbad);
/*
* Complete this transmit unit
@@ -1299,7 +1127,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_txq_schedule(sc, txq);
spin_unlock_bh(&txq->axq_lock);
}
- return nacked;
}
static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
@@ -1307,9 +1134,9 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
struct ath_hal *ah = sc->sc_ah;
(void) ath9k_hw_stoptxdma(ah, txq->axq_qnum);
- DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n",
- __func__, txq->axq_qnum,
- ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link);
+ DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n",
+ txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum),
+ txq->axq_link);
}
/* Drain only the data queues */
@@ -1317,40 +1144,33 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hal *ah = sc->sc_ah;
- int i;
- int npend = 0;
+ int i, status, npend = 0;
- /* XXX return value */
if (!(sc->sc_flags & SC_OP_INVALID)) {
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
- ath_tx_stopdma(sc, &sc->sc_txq[i]);
-
+ ath_tx_stopdma(sc, &sc->tx.txq[i]);
/* The TxDMA may not really be stopped.
* Double check the hal tx pending count */
npend += ath9k_hw_numtxpending(ah,
- sc->sc_txq[i].axq_qnum);
+ sc->tx.txq[i].axq_qnum);
}
}
}
if (npend) {
- int status;
-
/* TxDMA not stopped, reset the hal */
- DPRINTF(sc, ATH_DBG_XMIT,
- "%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
+ DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
spin_lock_bh(&sc->sc_resetlock);
if (!ath9k_hw_reset(ah,
sc->sc_ah->ah_curchan,
- sc->sc_ht_info.tx_chan_width,
+ sc->tx_chan_width,
sc->sc_tx_chainmask, sc->sc_rx_chainmask,
sc->sc_ht_extprotspacing, true, &status)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to reset hardware; hal status %u\n",
- __func__,
+ "Unable to reset hardware; hal status %u\n",
status);
}
spin_unlock_bh(&sc->sc_resetlock);
@@ -1358,7 +1178,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i))
- ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx);
+ ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx);
}
}
@@ -1390,24 +1210,17 @@ static void ath_tx_addto_baw(struct ath_softc *sc,
* Function to send an A-MPDU
* NB: must be called with txq lock held
*/
-
static int ath_tx_send_ampdu(struct ath_softc *sc,
- struct ath_txq *txq,
struct ath_atx_tid *tid,
struct list_head *bf_head,
struct ath_tx_control *txctl)
{
struct ath_buf *bf;
- struct sk_buff *skb;
- struct ieee80211_tx_info *tx_info;
- struct ath_tx_info_priv *tx_info_priv;
BUG_ON(list_empty(bf_head));
bf = list_first_entry(bf_head, struct ath_buf, list);
bf->bf_state.bf_type |= BUF_AMPDU;
- bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
- bf->bf_tidno = txctl->tidno;
/*
* Do not queue to h/w when any of the following conditions is true:
@@ -1418,21 +1231,16 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
*/
if (!list_empty(&tid->buf_q) || tid->paused ||
!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
- txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
+ txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
/*
* Add this frame to software queue for scheduling later
* for aggregation.
*/
list_splice_tail_init(bf_head, &tid->buf_q);
- ath_tx_queue_tid(txq, tid);
+ ath_tx_queue_tid(txctl->txq, tid);
return 0;
}
- skb = (struct sk_buff *)bf->bf_mpdu;
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
-
/* Add sub-frame to BAW */
ath_tx_addto_baw(sc, tid, bf);
@@ -1440,7 +1248,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
bf->bf_nframes = 1;
bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */
ath_buf_set_rate(sc, bf);
- ath_tx_txqaddbuf(sc, txq, bf_head);
+ ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
+
return 0;
}
@@ -1448,25 +1257,24 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
* looks up the rate
* returns aggr limit based on lowest of the rates
*/
-
static u32 ath_lookup_rate(struct ath_softc *sc,
- struct ath_buf *bf)
+ struct ath_buf *bf,
+ struct ath_atx_tid *tid)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rate_table = sc->cur_rate_table;
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rates;
struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frame_length;
u16 aggr_limit, legacy = 0, maxampdu;
int i;
-
skb = (struct sk_buff *)bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
- tx_info_priv = (struct ath_tx_info_priv *)
- tx_info->driver_data[0];
- memcpy(bf->bf_rcs,
- tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+ rates = tx_info->control.rates;
+ tx_info_priv =
+ (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
/*
* Find the lowest frame length among the rate series that will have a
@@ -1476,14 +1284,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
for (i = 0; i < 4; i++) {
- if (bf->bf_rcs[i].tries) {
- frame_length = bf->bf_rcs[i].max_4ms_framelen;
-
- if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
+ if (rates[i].count) {
+ if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
legacy = 1;
break;
}
+ frame_length =
+ rate_table->info[rates[i].idx].max_4ms_framelen;
max_4ms_framelen = min(max_4ms_framelen, frame_length);
}
}
@@ -1504,7 +1312,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
* The IE, however can hold upto 65536, which shows up here
* as zero. Ignore 65536 since we are constrained by hw.
*/
- maxampdu = sc->sc_ht_info.maxampdu;
+ maxampdu = tid->an->maxampdu;
if (maxampdu)
aggr_limit = min(aggr_limit, maxampdu);
@@ -1516,12 +1324,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
* meet the minimum required mpdudensity.
* caller should make sure that the rate is HT rate .
*/
-
static int ath_compute_num_delims(struct ath_softc *sc,
+ struct ath_atx_tid *tid,
struct ath_buf *bf,
u16 frmlen)
{
- const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct ath_rate_table *rt = sc->cur_rate_table;
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols, mpdudensity;
u16 minlen;
u8 rc, flags, rix;
@@ -1545,7 +1355,7 @@ static int ath_compute_num_delims(struct ath_softc *sc,
* required minimum length for subframe. Take into account
* whether high rate is 20 or 40Mhz and half or full GI.
*/
- mpdudensity = sc->sc_ht_info.mpdudensity;
+ mpdudensity = tid->an->mpdudensity;
/*
* If there is no mpdu density restriction, no further calculation
@@ -1554,11 +1364,11 @@ static int ath_compute_num_delims(struct ath_softc *sc,
if (mpdudensity == 0)
return ndelim;
- rix = bf->bf_rcs[0].rix;
- flags = bf->bf_rcs[0].flags;
- rc = rt->info[rix].rateCode;
- width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0;
- half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0;
+ rix = tx_info->control.rates[0].idx;
+ flags = tx_info->control.rates[0].flags;
+ rc = rt->info[rix].ratecode;
+ width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
+ half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
if (half_gi)
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
@@ -1585,7 +1395,6 @@ static int ath_compute_num_delims(struct ath_softc *sc,
* For aggregation from software buffer queue.
* NB: must be called with txq lock held
*/
-
static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
struct ath_atx_tid *tid,
struct list_head *bf_q,
@@ -1600,7 +1409,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
u16 aggr_limit = 0, al = 0, bpad = 0,
al_delta, h_baw = tid->baw_size / 2;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
- int prev_al = 0, is_ds_rate = 0;
+ int prev_al = 0;
INIT_LIST_HEAD(&bf_head);
BUG_ON(list_empty(&tid->buf_q));
@@ -1619,13 +1428,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
}
if (!rl) {
- aggr_limit = ath_lookup_rate(sc, bf);
+ aggr_limit = ath_lookup_rate(sc, bf, tid);
rl = 1;
- /*
- * Is rate dual stream
- */
- is_ds_rate =
- (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0;
}
/*
@@ -1657,7 +1461,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
* Get the delimiters needed to meet the MPDU
* density for this node.
*/
- ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen);
+ ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
bpad = PADBYTES(al_delta) + (ndelim << 2);
@@ -1713,7 +1517,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
* process pending frames possibly doing a-mpdu aggregation
* NB: must be called with txq lock held
*/
-
static void ath_tx_sched_aggr(struct ath_softc *sc,
struct ath_txq *txq, struct ath_atx_tid *tid)
{
@@ -1799,8 +1602,8 @@ static void ath_tx_sched_aggr(struct ath_softc *sc,
static void ath_tid_drain(struct ath_softc *sc,
struct ath_txq *txq,
- struct ath_atx_tid *tid,
- bool bh_flag)
+ struct ath_atx_tid *tid)
+
{
struct ath_buf *bf;
struct list_head bf_head;
@@ -1821,18 +1624,12 @@ static void ath_tid_drain(struct ath_softc *sc,
* do not indicate packets while holding txq spinlock.
* unlock is intentional here
*/
- if (likely(bh_flag))
- spin_unlock_bh(&txq->axq_lock);
- else
- spin_unlock(&txq->axq_lock);
+ spin_unlock(&txq->axq_lock);
/* complete this sub-frame */
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
- if (likely(bh_flag))
- spin_lock_bh(&txq->axq_lock);
- else
- spin_lock(&txq->axq_lock);
+ spin_lock(&txq->axq_lock);
}
/*
@@ -1849,10 +1646,8 @@ static void ath_tid_drain(struct ath_softc *sc,
* Drain all pending buffers
* NB: must be called with txq lock held
*/
-
static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
- struct ath_txq *txq,
- bool bh_flag)
+ struct ath_txq *txq)
{
struct ath_atx_ac *ac, *ac_tmp;
struct ath_atx_tid *tid, *tid_tmp;
@@ -1863,51 +1658,33 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
list_del(&tid->list);
tid->sched = false;
- ath_tid_drain(sc, txq, tid, bh_flag);
+ ath_tid_drain(sc, txq, tid);
}
}
}
-static int ath_tx_start_dma(struct ath_softc *sc,
- struct sk_buff *skb,
- struct scatterlist *sg,
- u32 n_sg,
- struct ath_tx_control *txctl)
+static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+ struct sk_buff *skb,
+ struct ath_tx_control *txctl)
{
- struct ath_node *an = txctl->an;
- struct ath_buf *bf = NULL;
- struct list_head bf_head;
- struct ath_desc *ds;
- struct ath_hal *ah = sc->sc_ah;
- struct ath_txq *txq;
- struct ath_tx_info_priv *tx_info_priv;
- struct ath_rc_series *rcs;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- __le16 fc = hdr->frame_control;
-
- if (unlikely(txctl->flags & ATH9K_TXDESC_CAB))
- txq = sc->sc_cabq;
- else
- txq = &sc->sc_txq[txctl->qnum];
+ struct ath_tx_info_priv *tx_info_priv;
+ int hdrlen;
+ __le16 fc;
- /* For each sglist entry, allocate an ath_buf for DMA */
- INIT_LIST_HEAD(&bf_head);
- spin_lock_bh(&sc->sc_txbuflock);
- if (unlikely(list_empty(&sc->sc_txbuf))) {
- spin_unlock_bh(&sc->sc_txbuflock);
+ tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+ if (unlikely(!tx_info_priv))
return -ENOMEM;
- }
+ tx_info->rate_driver_data[0] = tx_info_priv;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
- bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list);
- list_del(&bf->list);
- spin_unlock_bh(&sc->sc_txbuflock);
+ ATH_TXBUF_RESET(bf);
- list_add_tail(&bf->list, &bf_head);
+ /* Frame type */
- /* set up this buffer */
- ATH_TXBUF_RESET(bf);
- bf->bf_frmlen = txctl->frmlen;
+ bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
ieee80211_is_data(fc) ?
(bf->bf_state.bf_type |= BUF_DATA) :
@@ -1921,120 +1698,158 @@ static int ath_tx_start_dma(struct ath_softc *sc,
(sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
(bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
(bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
+ (sc->hw->conf.ht.enabled && !is_pae(skb) &&
+ (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ?
+ (bf->bf_state.bf_type |= BUF_HT) :
+ (bf->bf_state.bf_type &= ~BUF_HT);
+
+ bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
+
+ /* Crypto */
+
+ bf->bf_keytype = get_hw_crypto_keytype(skb);
+
+ if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
+ bf->bf_frmlen += tx_info->control.hw_key->icv_len;
+ bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
+ } else {
+ bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
+ }
+
+ /* Assign seqno, tidno */
+
+ if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
+ assign_aggr_tid_seqno(skb, bf);
+
+ /* DMA setup */
- bf->bf_flags = txctl->flags;
- bf->bf_keytype = txctl->keytype;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
- rcs = tx_info_priv->rcs;
- bf->bf_rcs[0] = rcs[0];
- bf->bf_rcs[1] = rcs[1];
- bf->bf_rcs[2] = rcs[2];
- bf->bf_rcs[3] = rcs[3];
- bf->bf_node = an;
bf->bf_mpdu = skb;
- bf->bf_buf_addr = sg_dma_address(sg);
+
+ bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) {
+ bf->bf_mpdu = NULL;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "pci_dma_mapping_error() on TX\n");
+ return -ENOMEM;
+ }
+
+ bf->bf_buf_addr = bf->bf_dmacontext;
+ return 0;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_control *txctl)
+{
+ struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_node *an = NULL;
+ struct list_head bf_head;
+ struct ath_desc *ds;
+ struct ath_atx_tid *tid;
+ struct ath_hal *ah = sc->sc_ah;
+ int frm_type;
+
+ frm_type = get_hw_packet_type(skb);
+
+ INIT_LIST_HEAD(&bf_head);
+ list_add_tail(&bf->list, &bf_head);
/* setup descriptor */
+
ds = bf->bf_desc;
ds->ds_link = 0;
ds->ds_data = bf->bf_buf_addr;
- /*
- * Save the DMA context in the first ath_buf
- */
- bf->bf_dmacontext = txctl->dmacontext;
+ /* Formulate first tx descriptor with tx controls */
- /*
- * Formulate first tx descriptor with tx controls.
- */
- ath9k_hw_set11n_txdesc(ah,
- ds,
- bf->bf_frmlen, /* frame length */
- txctl->atype, /* Atheros packet type */
- min(txctl->txpower, (u16)60), /* txpower */
- txctl->keyix, /* key cache index */
- txctl->keytype, /* key type */
- txctl->flags); /* flags */
- ath9k_hw_filltxdesc(ah,
- ds,
- sg_dma_len(sg), /* segment length */
- true, /* first segment */
- (n_sg == 1) ? true : false, /* last segment */
- ds); /* first descriptor */
+ ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
+ bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
+
+ ath9k_hw_filltxdesc(ah, ds,
+ skb->len, /* segment length */
+ true, /* first segment */
+ true, /* last segment */
+ ds); /* first descriptor */
bf->bf_lastfrm = bf;
- (txctl->ht) ?
- (bf->bf_state.bf_type |= BUF_HT) :
- (bf->bf_state.bf_type &= ~BUF_HT);
- spin_lock_bh(&txq->axq_lock);
+ spin_lock_bh(&txctl->txq->axq_lock);
- if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
- struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
- if (ath_aggr_query(sc, an, txctl->tidno)) {
+ if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
+ tx_info->control.sta) {
+ an = (struct ath_node *)tx_info->control.sta->drv_priv;
+ tid = ATH_AN_2_TID(an, bf->bf_tidno);
+
+ if (ath_aggr_query(sc, an, bf->bf_tidno)) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
*/
- ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl);
+ ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
} else {
/*
- * Send this frame as regular when ADDBA exchange
- * is neither complete nor pending.
+ * Send this frame as regular when ADDBA
+ * exchange is neither complete nor pending.
*/
- ath_tx_send_normal(sc, txq, tid, &bf_head);
+ ath_tx_send_normal(sc, txctl->txq,
+ tid, &bf_head);
}
} else {
bf->bf_lastbf = bf;
bf->bf_nframes = 1;
- ath_buf_set_rate(sc, bf);
-
- if (ieee80211_is_back_req(fc)) {
- /* This is required for resuming tid
- * during BAR completion */
- bf->bf_tidno = txctl->tidno;
- }
- ath_tx_txqaddbuf(sc, txq, &bf_head);
+ ath_buf_set_rate(sc, bf);
+ ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
}
- spin_unlock_bh(&txq->axq_lock);
- return 0;
+
+ spin_unlock_bh(&txctl->txq->axq_lock);
}
-static void xmit_map_sg(struct ath_softc *sc,
- struct sk_buff *skb,
- struct ath_tx_control *txctl)
+/* Upon failure caller should free skb */
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_tx_control *txctl)
{
- struct ath_xmit_status tx_status;
- struct ath_atx_tid *tid;
- struct scatterlist sg;
+ struct ath_buf *bf;
+ int r;
- txctl->dmacontext = pci_map_single(sc->pdev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ /* Check if a tx buffer is available */
- /* setup S/G list */
- memset(&sg, 0, sizeof(struct scatterlist));
- sg_dma_address(&sg) = txctl->dmacontext;
- sg_dma_len(&sg) = skb->len;
+ bf = ath_tx_get_buffer(sc);
+ if (!bf) {
+ DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n");
+ return -1;
+ }
- if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
- /*
- * We have to do drop frame here.
- */
- pci_unmap_single(sc->pdev, txctl->dmacontext,
- skb->len, PCI_DMA_TODEVICE);
+ r = ath_tx_setup_buffer(sc, bf, skb, txctl);
+ if (unlikely(r)) {
+ struct ath_txq *txq = txctl->txq;
- tx_status.retries = 0;
- tx_status.flags = ATH_TX_ERROR;
+ DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
- if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
- /* Reclaim the seqno. */
- tid = ATH_AN_2_TID((struct ath_node *)
- txctl->an, txctl->tidno);
- DECR(tid->seq_next, IEEE80211_SEQ_MAX);
+ /* upon ath_tx_processq() this TX queue will be resumed, we
+ * guarantee this will happen by knowing beforehand that
+ * we will at least have to run TX completionon one buffer
+ * on the queue */
+ spin_lock_bh(&txq->axq_lock);
+ if (ath_txq_depth(sc, txq->axq_qnum) > 1) {
+ ieee80211_stop_queue(sc->hw,
+ skb_get_queue_mapping(skb));
+ txq->stopped = 1;
}
- ath_tx_complete(sc, skb, &tx_status, txctl->an);
+ spin_unlock_bh(&txq->axq_lock);
+
+ spin_lock_bh(&sc->tx.txbuflock);
+ list_add_tail(&bf->list, &sc->tx.txbuf);
+ spin_unlock_bh(&sc->tx.txbuflock);
+
+ return r;
}
+
+ ath_tx_start_dma(sc, bf, txctl);
+
+ return 0;
}
/* Initialize TX queue and h/w */
@@ -2044,26 +1859,25 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
int error = 0;
do {
- spin_lock_init(&sc->sc_txbuflock);
+ spin_lock_init(&sc->tx.txbuflock);
/* Setup tx descriptors */
- error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+ error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
"tx", nbufs, 1);
if (error != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: failed to allocate tx descriptors: %d\n",
- __func__, error);
+ "Failed to allocate tx descriptors: %d\n",
+ error);
break;
}
/* XXX allocate beacon state together with vap */
- error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+ error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
"beacon", ATH_BCBUF, 1);
if (error != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: failed to allocate "
- "beacon descripotrs: %d\n",
- __func__, error);
+ "Failed to allocate beacon descriptors: %d\n",
+ error);
break;
}
@@ -2080,12 +1894,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
int ath_tx_cleanup(struct ath_softc *sc)
{
/* cleanup beacon descriptors */
- if (sc->sc_bdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
+ if (sc->beacon.bdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf);
/* cleanup tx descriptors */
- if (sc->sc_txdma.dd_desc_len != 0)
- ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+ if (sc->tx.txdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
return 0;
}
@@ -2133,15 +1947,15 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
*/
return NULL;
}
- if (qnum >= ARRAY_SIZE(sc->sc_txq)) {
+ if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: hal qnum %u out of range, max %u!\n",
- __func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq));
+ "qnum %u out of range, max %u!\n",
+ qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
ath9k_hw_releasetxqueue(ah, qnum);
return NULL;
}
if (!ATH_TXQ_SETUP(sc, qnum)) {
- struct ath_txq *txq = &sc->sc_txq[qnum];
+ struct ath_txq *txq = &sc->tx.txq[qnum];
txq->axq_qnum = qnum;
txq->axq_link = NULL;
@@ -2151,11 +1965,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
txq->axq_depth = 0;
txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
- txq->axq_intrcnt = 0;
txq->axq_linkbuf = NULL;
- sc->sc_txqsetup |= 1<<qnum;
+ sc->tx.txqsetup |= 1<<qnum;
}
- return &sc->sc_txq[qnum];
+ return &sc->tx.txq[qnum];
}
/* Reclaim resources for a setup queue */
@@ -2163,7 +1976,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
{
ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
- sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
+ sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
}
/*
@@ -2180,15 +1993,15 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
{
struct ath_txq *txq;
- if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+ if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: HAL AC %u out of range, max %zu!\n",
- __func__, haltype, ARRAY_SIZE(sc->sc_haltype2q));
+ "HAL AC %u out of range, max %zu!\n",
+ haltype, ARRAY_SIZE(sc->tx.hwq_map));
return 0;
}
txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
if (txq != NULL) {
- sc->sc_haltype2q[haltype] = txq->axq_qnum;
+ sc->tx.hwq_map[haltype] = txq->axq_qnum;
return 1;
} else
return 0;
@@ -2200,20 +2013,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
switch (qtype) {
case ATH9K_TX_QUEUE_DATA:
- if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+ if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: HAL AC %u out of range, max %zu!\n",
- __func__,
- haltype, ARRAY_SIZE(sc->sc_haltype2q));
+ "HAL AC %u out of range, max %zu!\n",
+ haltype, ARRAY_SIZE(sc->tx.hwq_map));
return -1;
}
- qnum = sc->sc_haltype2q[haltype];
+ qnum = sc->tx.hwq_map[haltype];
break;
case ATH9K_TX_QUEUE_BEACON:
- qnum = sc->sc_bhalq;
+ qnum = sc->beacon.beaconq;
break;
case ATH9K_TX_QUEUE_CAB:
- qnum = sc->sc_cabq->axq_qnum;
+ qnum = sc->beacon.cabq->axq_qnum;
break;
default:
qnum = -1;
@@ -2221,6 +2033,34 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
return qnum;
}
+/* Get a transmit queue, if available */
+
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
+{
+ struct ath_txq *txq = NULL;
+ int qnum;
+
+ qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ txq = &sc->tx.txq[qnum];
+
+ spin_lock_bh(&txq->axq_lock);
+
+ /* Try to avoid running out of descriptors */
+ if (txq->axq_depth >= (ATH_TXBUF - 20)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "TX queue: %d is full, depth: %d\n",
+ qnum, txq->axq_depth);
+ ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+ txq->stopped = 1;
+ spin_unlock_bh(&txq->axq_lock);
+ return NULL;
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+
+ return txq;
+}
+
/* Update parameters for a transmit queue */
int ath_txq_update(struct ath_softc *sc, int qnum,
@@ -2230,17 +2070,17 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
int error = 0;
struct ath9k_tx_queue_info qi;
- if (qnum == sc->sc_bhalq) {
+ if (qnum == sc->beacon.beaconq) {
/*
* XXX: for beacon queue, we just save the parameter.
* It will be picked up by ath_beaconq_config when
* it's necessary.
*/
- sc->sc_beacon_qi = *qinfo;
+ sc->beacon.beacon_qi = *qinfo;
return 0;
}
- ASSERT(sc->sc_txq[qnum].axq_qnum == qnum);
+ ASSERT(sc->tx.txq[qnum].axq_qnum == qnum);
ath9k_hw_get_txq_props(ah, qnum, &qi);
qi.tqi_aifs = qinfo->tqi_aifs;
@@ -2251,8 +2091,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
DPRINTF(sc, ATH_DBG_FATAL,
- "%s: unable to update hardware queue %u!\n",
- __func__, qnum);
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */
@@ -2264,7 +2103,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
int ath_cabq_update(struct ath_softc *sc)
{
struct ath9k_tx_queue_info qi;
- int qnum = sc->sc_cabq->axq_qnum;
+ int qnum = sc->beacon.cabq->axq_qnum;
struct ath_beacon_config conf;
ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
@@ -2284,27 +2123,6 @@ int ath_cabq_update(struct ath_softc *sc)
return 0;
}
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
-{
- struct ath_tx_control txctl;
- int error = 0;
-
- memset(&txctl, 0, sizeof(struct ath_tx_control));
- error = ath_tx_prepare(sc, skb, &txctl);
- if (error == 0)
- /*
- * Start DMA mapping.
- * ath_tx_start_dma() will be called either synchronously
- * or asynchrounsly once DMA is complete.
- */
- xmit_map_sg(sc, skb, &txctl);
- else
- ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
-
- /* failed packets will be dropped by the caller */
- return error;
-}
-
/* Deferred processing of transmit interrupt */
void ath_tx_tasklet(struct ath_softc *sc)
@@ -2319,7 +2137,7 @@ void ath_tx_tasklet(struct ath_softc *sc)
*/
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
- ath_tx_processq(sc, &sc->sc_txq[i]);
+ ath_tx_processq(sc, &sc->tx.txq[i]);
}
}
@@ -2351,9 +2169,9 @@ void ath_tx_draintxq(struct ath_softc *sc,
list_del(&bf->list);
spin_unlock_bh(&txq->axq_lock);
- spin_lock_bh(&sc->sc_txbuflock);
- list_add_tail(&bf->list, &sc->sc_txbuf);
- spin_unlock_bh(&sc->sc_txbuflock);
+ spin_lock_bh(&sc->tx.txbuflock);
+ list_add_tail(&bf->list, &sc->tx.txbuf);
+ spin_unlock_bh(&sc->tx.txbuflock);
continue;
}
@@ -2378,8 +2196,7 @@ void ath_tx_draintxq(struct ath_softc *sc,
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
spin_lock_bh(&txq->axq_lock);
- ath_txq_drain_pending_buffers(sc, txq,
- ATH9K_BH_STATUS_CHANGE);
+ ath_txq_drain_pending_buffers(sc, txq);
spin_unlock_bh(&txq->axq_lock);
}
}
@@ -2392,9 +2209,9 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx)
/* stop beacon queue. The beacon will be freed when
* we go to INIT state */
if (!(sc->sc_flags & SC_OP_INVALID)) {
- (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
- DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__,
- ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq));
+ (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
+ DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n",
+ ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq));
}
ath_drain_txdataq(sc, retry_tx);
@@ -2402,72 +2219,47 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx)
u32 ath_txq_depth(struct ath_softc *sc, int qnum)
{
- return sc->sc_txq[qnum].axq_depth;
+ return sc->tx.txq[qnum].axq_depth;
}
u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum)
{
- return sc->sc_txq[qnum].axq_aggr_depth;
+ return sc->tx.txq[qnum].axq_aggr_depth;
}
-/* Check if an ADDBA is required. A valid node must be passed. */
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
- struct ath_node *an,
- u8 tidno)
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
{
struct ath_atx_tid *txtid;
- DECLARE_MAC_BUF(mac);
if (!(sc->sc_flags & SC_OP_TXAGGR))
- return AGGR_NOT_REQUIRED;
+ return false;
- /* ADDBA exchange must be completed before sending aggregates */
txtid = ATH_AN_2_TID(an, tidno);
- if (txtid->addba_exchangecomplete)
- return AGGR_EXCHANGE_DONE;
-
- if (txtid->cleanup_inprogress)
- return AGGR_CLEANUP_PROGRESS;
-
- if (txtid->addba_exchangeinprogress)
- return AGGR_EXCHANGE_PROGRESS;
-
- if (!txtid->addba_exchangecomplete) {
- if (!txtid->addba_exchangeinprogress &&
+ if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
+ if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
(txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
txtid->addba_exchangeattempts++;
- return AGGR_REQUIRED;
+ return true;
}
}
- return AGGR_NOT_REQUIRED;
+ return false;
}
/* Start TX aggregation */
-int ath_tx_aggr_start(struct ath_softc *sc,
- const u8 *addr,
- u16 tid,
- u16 *ssn)
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+ u16 tid, u16 *ssn)
{
struct ath_atx_tid *txtid;
struct ath_node *an;
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, (u8 *) addr);
- spin_unlock_bh(&sc->node_lock);
-
- if (!an) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: Node not found to initialize "
- "TX aggregation\n", __func__);
- return -1;
- }
+ an = (struct ath_node *)sta->drv_priv;
if (sc->sc_flags & SC_OP_TXAGGR) {
txtid = ATH_AN_2_TID(an, tid);
- txtid->addba_exchangeinprogress = 1;
+ txtid->state |= AGGR_ADDBA_PROGRESS;
ath_tx_pause_tid(sc, txtid);
}
@@ -2476,24 +2268,31 @@ int ath_tx_aggr_start(struct ath_softc *sc,
/* Stop tx aggregation */
-int ath_tx_aggr_stop(struct ath_softc *sc,
- const u8 *addr,
- u16 tid)
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
+
+ ath_tx_aggr_teardown(sc, an, tid);
+ return 0;
+}
+
+/* Resume tx aggregation */
+
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+{
+ struct ath_atx_tid *txtid;
struct ath_node *an;
- spin_lock_bh(&sc->node_lock);
- an = ath_node_find(sc, (u8 *) addr);
- spin_unlock_bh(&sc->node_lock);
+ an = (struct ath_node *)sta->drv_priv;
- if (!an) {
- DPRINTF(sc, ATH_DBG_AGGR,
- "%s: TX aggr stop for non-existent node\n", __func__);
- return -1;
+ if (sc->sc_flags & SC_OP_TXAGGR) {
+ txtid = ATH_AN_2_TID(an, tid);
+ txtid->baw_size =
+ IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
+ txtid->state |= AGGR_ADDBA_COMPLETE;
+ txtid->state &= ~AGGR_ADDBA_PROGRESS;
+ ath_tx_resume_tid(sc, txtid);
}
-
- ath_tx_aggr_teardown(sc, an, tid);
- return 0;
}
/*
@@ -2503,21 +2302,18 @@ int ath_tx_aggr_stop(struct ath_softc *sc,
* - Discard all retry frames from the s/w queue.
*/
-void ath_tx_aggr_teardown(struct ath_softc *sc,
- struct ath_node *an, u8 tid)
+void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid)
{
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
- struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum];
+ struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
struct ath_buf *bf;
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
- DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__);
-
- if (txtid->cleanup_inprogress) /* cleanup is in progress */
+ if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */
return;
- if (!txtid->addba_exchangecomplete) {
+ if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->addba_exchangeattempts = 0;
return;
}
@@ -2547,9 +2343,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc,
if (txtid->baw_head != txtid->baw_tail) {
spin_unlock_bh(&txq->axq_lock);
- txtid->cleanup_inprogress = true;
+ txtid->state |= AGGR_CLEANUP;
} else {
- txtid->addba_exchangecomplete = 0;
+ txtid->state &= ~AGGR_ADDBA_COMPLETE;
txtid->addba_exchangeattempts = 0;
spin_unlock_bh(&txq->axq_lock);
ath_tx_flush_tid(sc, txtid);
@@ -2591,10 +2387,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused) /* check next tid to keep h/w busy */
continue;
- if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) ||
- ((txq->axq_depth % 2) == 0)) {
+ if ((txq->axq_depth % 2) == 0)
ath_tx_sched_aggr(sc, txq, tid);
- }
/*
* add tid to round-robin queue if more frames
@@ -2625,72 +2419,67 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
{
- if (sc->sc_flags & SC_OP_TXAGGR) {
- struct ath_atx_tid *tid;
- struct ath_atx_ac *ac;
- int tidno, acno;
-
- sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ int tidno, acno;
- /*
- * Init per tid tx state
- */
- for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
- tidno < WME_NUM_TID;
- tidno++, tid++) {
- tid->an = an;
- tid->tidno = tidno;
- tid->seq_start = tid->seq_next = 0;
- tid->baw_size = WME_MAX_BA;
- tid->baw_head = tid->baw_tail = 0;
- tid->sched = false;
- tid->paused = false;
- tid->cleanup_inprogress = false;
- INIT_LIST_HEAD(&tid->buf_q);
-
- acno = TID_TO_WME_AC(tidno);
- tid->ac = &an->an_aggr.tx.ac[acno];
-
- /* ADDBA state */
- tid->addba_exchangecomplete = 0;
- tid->addba_exchangeinprogress = 0;
- tid->addba_exchangeattempts = 0;
- }
+ /*
+ * Init per tid tx state
+ */
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID;
+ tidno++, tid++) {
+ tid->an = an;
+ tid->tidno = tidno;
+ tid->seq_start = tid->seq_next = 0;
+ tid->baw_size = WME_MAX_BA;
+ tid->baw_head = tid->baw_tail = 0;
+ tid->sched = false;
+ tid->paused = false;
+ tid->state &= ~AGGR_CLEANUP;
+ INIT_LIST_HEAD(&tid->buf_q);
+
+ acno = TID_TO_WME_AC(tidno);
+ tid->ac = &an->ac[acno];
+
+ /* ADDBA state */
+ tid->state &= ~AGGR_ADDBA_COMPLETE;
+ tid->state &= ~AGGR_ADDBA_PROGRESS;
+ tid->addba_exchangeattempts = 0;
+ }
- /*
- * Init per ac tx state
- */
- for (acno = 0, ac = &an->an_aggr.tx.ac[acno];
- acno < WME_NUM_AC; acno++, ac++) {
- ac->sched = false;
- INIT_LIST_HEAD(&ac->tid_q);
-
- switch (acno) {
- case WME_AC_BE:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
- break;
- case WME_AC_BK:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
- break;
- case WME_AC_VI:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
- break;
- case WME_AC_VO:
- ac->qnum = ath_tx_get_qnum(sc,
- ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
- break;
- }
+ /*
+ * Init per ac tx state
+ */
+ for (acno = 0, ac = &an->ac[acno];
+ acno < WME_NUM_AC; acno++, ac++) {
+ ac->sched = false;
+ INIT_LIST_HEAD(&ac->tid_q);
+
+ switch (acno) {
+ case WME_AC_BE:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ break;
+ case WME_AC_BK:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
+ break;
+ case WME_AC_VI:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
+ break;
+ case WME_AC_VO:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
+ break;
}
}
}
/* Cleanupthe pending buffers for the node. */
-void ath_tx_node_cleanup(struct ath_softc *sc,
- struct ath_node *an, bool bh_flag)
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
{
int i;
struct ath_atx_ac *ac, *ac_tmp;
@@ -2698,12 +2487,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc,
struct ath_txq *txq;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
- txq = &sc->sc_txq[i];
+ txq = &sc->tx.txq[i];
- if (likely(bh_flag))
- spin_lock_bh(&txq->axq_lock);
- else
- spin_lock(&txq->axq_lock);
+ spin_lock(&txq->axq_lock);
list_for_each_entry_safe(ac,
ac_tmp, &txq->axq_acq, list) {
@@ -2718,36 +2504,14 @@ void ath_tx_node_cleanup(struct ath_softc *sc,
tid_tmp, &ac->tid_q, list) {
list_del(&tid->list);
tid->sched = false;
- ath_tid_drain(sc, txq, tid, bh_flag);
- tid->addba_exchangecomplete = 0;
+ ath_tid_drain(sc, txq, tid);
+ tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->addba_exchangeattempts = 0;
- tid->cleanup_inprogress = false;
+ tid->state &= ~AGGR_CLEANUP;
}
}
- if (likely(bh_flag))
- spin_unlock_bh(&txq->axq_lock);
- else
- spin_unlock(&txq->axq_lock);
- }
- }
-}
-
-/* Cleanup per node transmit state */
-
-void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
- if (sc->sc_flags & SC_OP_TXAGGR) {
- struct ath_atx_tid *tid;
- int tidno, i;
-
- /* Init per tid rx state */
- for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
- tidno < WME_NUM_TID;
- tidno++, tid++) {
-
- for (i = 0; i < ATH_TID_MAX_BUFS; i++)
- ASSERT(tid->tx_buf[i] == NULL);
+ spin_unlock(&txq->axq_lock);
}
}
}
@@ -2758,6 +2522,8 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_tx_control txctl;
+ memset(&txctl, 0, sizeof(struct ath_tx_control));
+
/*
* As a temporary workaround, assign seq# here; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual
@@ -2766,9 +2532,9 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- sc->seq_no += 0x10;
+ sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}
/* Add the padding after the header if this is not already done */
@@ -2776,8 +2542,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
if (hdrlen & 3) {
padsize = hdrlen % 4;
if (skb_headroom(skb) < padsize) {
- DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding "
- "failed\n", __func__);
+ DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n");
dev_kfree_skb_any(skb);
return;
}
@@ -2785,23 +2550,16 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
memmove(skb->data, skb->data + padsize, hdrlen);
}
- DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n",
- __func__,
- skb);
+ txctl.txq = sc->beacon.cabq;
- memset(&txctl, 0, sizeof(struct ath_tx_control));
- txctl.flags = ATH9K_TXDESC_CAB;
- if (ath_tx_prepare(sc, skb, &txctl) == 0) {
- /*
- * Start DMA mapping.
- * ath_tx_start_dma() will be called either synchronously
- * or asynchrounsly once DMA is complete.
- */
- xmit_map_sg(sc, skb, &txctl);
- } else {
- ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
- DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__);
- dev_kfree_skb_any(skb);
+ DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
+
+ if (ath_tx_start(sc, skb, &txctl) != 0) {
+ DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
+ goto exit;
}
-}
+ return;
+exit:
+ dev_kfree_skb_any(skb);
+}
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index ecb02bdaab5..350157fcd08 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -67,7 +67,7 @@
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
#include "atmel.h"
#define DRIVER_MAJOR 0
@@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
static void atmel_command_irq(struct atmel_private *priv);
static int atmel_validate_channel(struct atmel_private *priv, int channel);
static void atmel_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u16 frame_len, u8 rssi);
static void atmel_management_timer(u_long a);
static void atmel_send_command(struct atmel_private *priv, int command,
@@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command,
static int atmel_send_command_wait(struct atmel_private *priv, int command,
void *cmd, int cmd_size);
static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u8 *body, int body_len);
static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -785,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
{
static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
struct atmel_private *priv = netdev_priv(dev);
- struct ieee80211_hdr_4addr header;
+ struct ieee80211_hdr header;
unsigned long flags;
u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
@@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
frame_ctl = IEEE80211_FTYPE_DATA;
header.duration_id = 0;
- header.seq_ctl = 0;
+ header.seq_ctrl = 0;
if (priv->wep_is_on)
frame_ctl |= IEEE80211_FCTL_PROTECTED;
if (priv->operating_mode == IW_MODE_ADHOC) {
@@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
if (priv->use_wpa)
memcpy(&header.addr4, SNAP_RFC1024, 6);
- header.frame_ctl = cpu_to_le16(frame_ctl);
+ header.frame_control = cpu_to_le16(frame_ctl);
/* Copy the wireless header into the card */
atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
/* Copy the packet sans its 802.3 header addresses which have been replaced */
@@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u8 *body, int body_len)
{
u16 buff;
@@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
}
static void fast_rx_path(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc)
{
/* fast path: unfragmented packet copy directly into skbuf */
@@ -914,12 +914,11 @@ static void fast_rx_path(struct atmel_private *priv,
}
memcpy(skbp, header->addr1, 6); /* destination address */
- if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
memcpy(&skbp[6], header->addr3, 6);
else
memcpy(&skbp[6], header->addr2, 6); /* source address */
- priv->dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
@@ -950,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
}
static void frag_rx_path(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
u8 frag_no, int more_frags)
{
@@ -958,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv,
u8 source[6];
struct sk_buff *skb;
- if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
memcpy(source, header->addr3, 6);
else
memcpy(source, header->addr2, 6);
@@ -1026,7 +1025,6 @@ static void frag_rx_path(struct atmel_private *priv,
memcpy(skb_put(skb, priv->frag_len + 12),
priv->rx_buf,
priv->frag_len + 12);
- priv->dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
@@ -1041,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv,
static void rx_done_irq(struct atmel_private *priv)
{
int i;
- struct ieee80211_hdr_4addr header;
+ struct ieee80211_hdr header;
for (i = 0;
atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1068,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv)
goto next;
}
- /* Get header as far as end of seq_ctl */
+ /* Get header as far as end of seq_ctrl */
atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
- frame_ctl = le16_to_cpu(header.frame_ctl);
- seq_control = le16_to_cpu(header.seq_ctl);
+ frame_ctl = le16_to_cpu(header.frame_control);
+ seq_control = le16_to_cpu(header.seq_ctrl);
/* probe for CRC use here if needed once five packets have
arrived with the same crc status, we assume we know what's
@@ -1479,7 +1477,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
struct net_device *dev;
struct atmel_private *priv;
int rc;
- DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_etherdev(sizeof(*priv));
@@ -1591,8 +1588,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
if (!ent)
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
- printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
- dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
+ printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",
+ dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr);
return dev;
@@ -1822,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev,
/* Determine and validate the key index */
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
+ if (idx < 1 || idx > 4)
return -EINVAL;
idx--;
} else
@@ -1885,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev,
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
+ if (idx < 1 || idx > 4)
return -EINVAL;
idx--;
} else
@@ -2800,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
u8 channel)
{
int rejoin = 0;
- int new = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+ int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
SHORT_PREAMBLE : LONG_PREAMBLE;
if (priv->preamble != new) {
@@ -2829,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
static void send_authentication_request(struct atmel_private *priv, u16 system,
u8 *challenge, int challenge_len)
{
- struct ieee80211_hdr_4addr header;
+ struct ieee80211_hdr header;
struct auth_body auth;
- header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+ header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
header.duration_id = cpu_to_le16(0x8000);
- header.seq_ctl = 0;
+ header.seq_ctrl = 0;
memcpy(header.addr1, priv->CurrentBSSID, 6);
memcpy(header.addr2, priv->dev->dev_addr, 6);
memcpy(header.addr3, priv->CurrentBSSID, 6);
if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
/* no WEP for authentication frames with TrSeqNo 1 */
- header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
auth.alg = cpu_to_le16(system);
@@ -2864,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
{
u8 *ssid_el_p;
int bodysize;
- struct ieee80211_hdr_4addr header;
+ struct ieee80211_hdr header;
struct ass_req_format {
__le16 capability;
__le16 listen_interval;
@@ -2877,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
u8 rates[4];
} body;
- header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
(is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
header.duration_id = cpu_to_le16(0x8000);
- header.seq_ctl = 0;
+ header.seq_ctrl = 0;
memcpy(header.addr1, priv->CurrentBSSID, 6);
memcpy(header.addr2, priv->dev->dev_addr, 6);
@@ -2890,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
if (priv->wep_is_on)
body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
if (priv->preamble == SHORT_PREAMBLE)
- body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT);
+ body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
@@ -2904,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
bodysize = 12 + priv->SSID_size;
}
- ssid_el_p[0] = MFIE_TYPE_SSID;
+ ssid_el_p[0] = WLAN_EID_SSID;
ssid_el_p[1] = priv->SSID_size;
memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
- ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES;
+ ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES;
ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */
memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
@@ -2915,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
}
static int is_frame_from_current_bss(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header)
+ struct ieee80211_hdr *header)
{
- if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+ if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
else
return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2965,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv)
}
static void store_bss_info(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header, u16 capability,
+ struct ieee80211_hdr *header, u16 capability,
u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
u8 *ssid, int is_beacon)
{
@@ -3004,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv,
else if (capability & WLAN_CAPABILITY_ESS)
priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
- priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+ priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
SHORT_PREAMBLE : LONG_PREAMBLE;
}
@@ -3040,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
}
} else if (system == WLAN_AUTH_SHARED_KEY) {
if (trans_seq_no == 0x0002 &&
- auth->el_id == MFIE_TYPE_CHALLENGE) {
+ auth->el_id == WLAN_EID_CHALLENGE) {
send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
return;
} else if (trans_seq_no == 0x0004) {
@@ -3183,7 +3180,7 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
}
}
-void atmel_join_bss(struct atmel_private *priv, int bss_index)
+static void atmel_join_bss(struct atmel_private *priv, int bss_index)
{
struct bss_info *bss = &priv->BSSinfo[bss_index];
@@ -3291,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv)
/* deals with incoming managment frames. */
static void atmel_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr_4addr *header,
+ struct ieee80211_hdr *header,
u16 frame_len, u8 rssi)
{
u16 subtype;
- subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
+ subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE;
switch (subtype) {
case IEEE80211_STYPE_BEACON:
case IEEE80211_STYPE_PROBE_RESP:
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 427b8203e3f..a53c378e748 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -718,7 +718,6 @@ struct b43_wldev {
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
- bool short_slot; /* TRUE, if short slot timing is enabled. */
bool radio_hw_enable; /* saved state of radio hardware enabled state */
bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index 06a01da8016..e04fc91f569 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
+ add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
#undef add_dyn_dbg
}
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
index 22ffd02ba55..7886cbe2d1d 100644
--- a/drivers/net/wireless/b43/debugfs.h
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
B43_DBG_PWORK_STOP,
B43_DBG_LO,
B43_DBG_FIRMWARE,
+ B43_DBG_KEYS,
__B43_NR_DYNDBG,
};
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 098f886976f..6d65a02b705 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
info = IEEE80211_SKB_CB(meta->skb);
- memset(&info->status, 0, sizeof(info->status));
-
/*
* Call back to inform the ieee80211 subsystem about
* the status of the transmission.
*/
- frame_succeed = b43_fill_txstatus_report(info, status);
+ frame_succeed = b43_fill_txstatus_report(dev, info, status);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 14c44df584d..7b31a327b24 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
static void b43_short_slot_timing_enable(struct b43_wldev *dev)
{
b43_set_slot_time(dev, 9);
- dev->short_slot = 1;
}
static void b43_short_slot_timing_disable(struct b43_wldev *dev)
{
b43_set_slot_time(dev, 20);
- dev->short_slot = 0;
}
/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -994,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev)
b43_key_clear(dev, i);
}
+static void b43_dump_keymemory(struct b43_wldev *dev)
+{
+ unsigned int i, index, offset;
+ DECLARE_MAC_BUF(macbuf);
+ u8 mac[ETH_ALEN];
+ u16 algo;
+ u32 rcmta0;
+ u16 rcmta1;
+ u64 hf;
+ struct b43_key *key;
+
+ if (!b43_debug(dev, B43_DBG_KEYS))
+ return;
+
+ hf = b43_hf_read(dev);
+ b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
+ !!(hf & B43_HF_USEDEFKEYS));
+ for (index = 0; index < dev->max_nr_keys; index++) {
+ key = &(dev->key[index]);
+ printk(KERN_DEBUG "Key slot %02u: %s",
+ index, (key->keyconf == NULL) ? " " : "*");
+ offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+ for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+ u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
+ printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
+ }
+
+ algo = b43_shm_read16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_KEYIDXBLOCK + (index * 2));
+ printk(" Algo: %04X/%02X", algo, key->algorithm);
+
+ if (index >= 4) {
+ rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
+ ((index - 4) * 2) + 0);
+ rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
+ ((index - 4) * 2) + 1);
+ *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
+ *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
+ printk(" MAC: %s",
+ print_mac(macbuf, mac));
+ } else
+ printk(" DEFAULT KEY");
+ printk("\n");
+ }
+}
+
void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
{
u32 macctl;
@@ -1339,25 +1383,6 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
return antenna_nr;
}
-static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
-{
- antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
- switch (antenna) {
- case 0: /* default/diversity */
- return B43_ANTENNA_DEFAULT;
- case 1: /* Antenna 0 */
- return B43_ANTENNA0;
- case 2: /* Antenna 1 */
- return B43_ANTENNA1;
- case 3: /* Antenna 2 */
- return B43_ANTENNA2;
- case 4: /* Antenna 3 */
- return B43_ANTENNA3;
- default:
- return B43_ANTENNA_DEFAULT;
- }
-}
-
/* Convert a b43 antenna number value to the PHY TX control value. */
static u16 b43_antenna_to_phyctl(int antenna)
{
@@ -1399,7 +1424,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
len, ram_offset, shm_size_offset, rate);
/* Write the PHY TX control parameters. */
- antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
+ antenna = B43_ANTENNA_DEFAULT;
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
@@ -1693,25 +1718,6 @@ static void b43_update_templates(struct b43_wl *wl)
queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
}
-static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
-{
- u32 tmp;
- u16 i, len;
-
- len = min((u16) ssid_len, (u16) 0x100);
- for (i = 0; i < len; i += sizeof(u32)) {
- tmp = (u32) (ssid[i + 0]);
- if (i + 1 < len)
- tmp |= (u32) (ssid[i + 1]) << 8;
- if (i + 2 < len)
- tmp |= (u32) (ssid[i + 2]) << 16;
- if (i + 3 < len)
- tmp |= (u32) (ssid[i + 3]) << 24;
- b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
- }
- b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
-}
-
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
{
b43_time_lock(dev);
@@ -3339,15 +3345,31 @@ init_failure:
return err;
}
-static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+ unsigned int short_retry,
+ unsigned int long_retry)
+{
+ /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter. */
+ short_retry = min(short_retry, (unsigned int)0xF);
+ long_retry = min(long_retry, (unsigned int)0xF);
+
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+ short_retry);
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+ long_retry);
+}
+
+static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
struct b43_phy *phy;
+ struct ieee80211_conf *conf = &hw->conf;
unsigned long flags;
int antenna;
int err = 0;
- u32 savedirqs;
mutex_lock(&wl->mutex);
@@ -3358,33 +3380,20 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
dev = wl->current_dev;
phy = &dev->phy;
- /* Disable IRQs while reconfiguring the device.
- * This makes it possible to drop the spinlock throughout
- * the reconfiguration process. */
- spin_lock_irqsave(&wl->irq_lock, flags);
- if (b43_status(dev) < B43_STAT_STARTED) {
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- goto out_unlock_mutex;
- }
- savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- b43_synchronize_irq(dev);
+ b43_mac_suspend(dev);
+
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);
+ changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
+ if (!changed)
+ goto out_mac_enable;
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
if (conf->channel->hw_value != phy->channel)
b43_switch_channel(dev, conf->channel->hw_value);
- /* Enable/Disable ShortSlot timing. */
- if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
- dev->short_slot) {
- B43_WARN_ON(phy->type != B43_PHYTYPE_G);
- if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
- b43_short_slot_timing_enable(dev);
- else
- b43_short_slot_timing_disable(dev);
- }
-
dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
/* Adjust the desired TX power level. */
@@ -3399,9 +3408,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
}
/* Antennas for RX and management frame TX. */
- antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+ antenna = B43_ANTENNA_DEFAULT;
b43_mgmtframe_txantenna(dev, antenna);
- antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+ antenna = B43_ANTENNA_DEFAULT;
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, antenna);
@@ -3425,16 +3434,91 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
}
}
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_interrupt_enable(dev, savedirqs);
- mmiowb();
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- out_unlock_mutex:
+out_mac_enable:
+ b43_mac_enable(dev);
+out_unlock_mutex:
mutex_unlock(&wl->mutex);
return err;
}
+static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+{
+ struct ieee80211_supported_band *sband =
+ dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
+ struct ieee80211_rate *rate;
+ int i;
+ u16 basic, direct, offset, basic_offset, rateptr;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = &sband->bitrates[i];
+
+ if (b43_is_cck_rate(rate->hw_value)) {
+ direct = B43_SHM_SH_CCKDIRECT;
+ basic = B43_SHM_SH_CCKBASIC;
+ offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+ offset &= 0xF;
+ } else {
+ direct = B43_SHM_SH_OFDMDIRECT;
+ basic = B43_SHM_SH_OFDMBASIC;
+ offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+ offset &= 0xF;
+ }
+
+ rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+ if (b43_is_cck_rate(rate->hw_value)) {
+ basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+ basic_offset &= 0xF;
+ } else {
+ basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+ basic_offset &= 0xF;
+ }
+
+ /*
+ * Get the pointer that we need to point to
+ * from the direct map
+ */
+ rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
+ direct + 2 * basic_offset);
+ /* and write it to the basic map */
+ b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
+ rateptr);
+ }
+}
+
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *conf,
+ u32 changed)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+
+ dev = wl->current_dev;
+ if (!dev || b43_status(dev) < B43_STAT_STARTED)
+ goto out_unlock_mutex;
+ b43_mac_suspend(dev);
+
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ b43_update_basic_rates(dev, conf->basic_rates);
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ if (conf->use_short_slot)
+ b43_short_slot_timing_enable(dev);
+ else
+ b43_short_slot_timing_disable(dev);
+ }
+
+ b43_mac_enable(dev);
+out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return;
+}
+
static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_addr, const u8 *addr,
struct ieee80211_key_conf *key)
@@ -3445,7 +3529,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
u8 algorithm;
u8 index;
int err;
- DECLARE_MAC_BUF(mac);
if (modparam_nohwcrypt)
return -ENOSPC; /* User disabled HW-crypto */
@@ -3528,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
default:
B43_WARN_ON(1);
}
+
out_unlock:
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- mutex_unlock(&wl->mutex);
if (!err) {
b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
- "mac: %s\n",
+ "mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
- print_mac(mac, addr));
+ addr);
+ b43_dump_keymemory(dev);
}
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+
return err;
}
@@ -3598,8 +3684,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
B43_WARN_ON(vif->type != wl->if_type);
- if (conf->changed & IEEE80211_IFCC_SSID)
- b43_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->changed & IEEE80211_IFCC_BEACON)
b43_update_templates(wl);
} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -3878,22 +3962,6 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
#endif /* CONFIG_SSB_DRIVER_PCICORE */
}
-/* Write the short and long frame retry limit values. */
-static void b43_set_retry_limits(struct b43_wldev *dev,
- unsigned int short_retry,
- unsigned int long_retry)
-{
- /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
- * the chip-internal counter. */
- short_retry = min(short_retry, (unsigned int)0xF);
- long_retry = min(long_retry, (unsigned int)0xF);
-
- b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
- short_retry);
- b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
- long_retry);
-}
-
static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
{
u16 pu_delay;
@@ -4214,26 +4282,6 @@ static void b43_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&(wl->txpower_adjust_work));
}
-static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry_limit, u32 long_retry_limit)
-{
- struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev;
- int err = 0;
-
- mutex_lock(&wl->mutex);
- dev = wl->current_dev;
- if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
- err = -ENODEV;
- goto out_unlock;
- }
- b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
-out_unlock:
- mutex_unlock(&wl->mutex);
-
- return err;
-}
-
static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, bool set)
{
@@ -4263,6 +4311,7 @@ static const struct ieee80211_ops b43_hw_ops = {
.add_interface = b43_op_add_interface,
.remove_interface = b43_op_remove_interface,
.config = b43_op_config,
+ .bss_info_changed = b43_op_bss_info_changed,
.config_interface = b43_op_config_interface,
.configure_filter = b43_op_configure_filter,
.set_key = b43_op_set_key,
@@ -4270,7 +4319,6 @@ static const struct ieee80211_ops b43_hw_ops = {
.get_tx_stats = b43_op_get_tx_stats,
.start = b43_op_start,
.stop = b43_op_stop,
- .set_retry_limit = b43_op_set_retry_limit,
.set_tim = b43_op_beacon_set_tim,
.sta_notify = b43_op_sta_notify,
};
@@ -4588,7 +4636,7 @@ static int b43_wireless_init(struct ssb_device *dev)
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = b43_modparam_qos ? 4 : 1;
- hw->max_altrates = 1;
+ hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 0f1a84c9de6..7fe9d170162 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -77,7 +77,7 @@ static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
}
#endif
-void b43_radio_set_tx_iq(struct b43_wldev *dev)
+static void b43_radio_set_tx_iq(struct b43_wldev *dev)
{
static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
@@ -147,7 +147,7 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
//FIXME b43_phy_xmitpower(dev);
}
-void b43_radio_init2060(struct b43_wldev *dev)
+static void b43_radio_init2060(struct b43_wldev *dev)
{
b43_radio_write16(dev, 0x0004, 0x00C0);
b43_radio_write16(dev, 0x0005, 0x0008);
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index af37abccccb..026b61c03fb 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev)
b43_power_saving_ctl_bits(dev, 0);
}
+static inline void assert_mac_suspended(struct b43_wldev *dev)
+{
+ if (!B43_DEBUG)
+ return;
+ if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
+ (dev->mac_suspended <= 0)) {
+ b43dbg(dev->wl, "PHY/RADIO register access with "
+ "enabled MAC.\n");
+ dump_stack();
+ }
+}
+
u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{
+ assert_mac_suspended(dev);
return dev->phy.ops->radio_read(dev, reg);
}
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{
+ assert_mac_suspended(dev);
dev->phy.ops->radio_write(dev, reg, value);
}
@@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
+ assert_mac_suspended(dev);
return dev->phy.ops->phy_read(dev, reg);
}
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{
+ assert_mac_suspended(dev);
dev->phy.ops->phy_write(dev, reg, value);
}
@@ -280,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
state = RFKILL_STATE_SOFT_BLOCKED;
}
+ b43_mac_suspend(dev);
phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
+ b43_mac_enable(dev);
}
/**
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 232181f6333..caac4a45f0b 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -54,7 +54,7 @@ static const s8 b43_tssi2dbm_g_table[] = {
-20, -20, -20, -20,
};
-const u8 b43_radio_channel_codes_bg[] = {
+static const u8 b43_radio_channel_codes_bg[] = {
12, 17, 22, 27,
32, 37, 42, 47,
52, 57, 62, 67,
@@ -215,9 +215,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
}
/* Adjust the transmission power output (G-PHY) */
-void b43_set_txpower_g(struct b43_wldev *dev,
- const struct b43_bbatt *bbatt,
- const struct b43_rfatt *rfatt, u8 tx_control)
+static void b43_set_txpower_g(struct b43_wldev *dev,
+ const struct b43_bbatt *bbatt,
+ const struct b43_rfatt *rfatt, u8 tx_control)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
@@ -383,14 +383,14 @@ static void b43_set_original_gains(struct b43_wldev *dev)
}
/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
{
b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
}
/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
{
u16 val;
@@ -401,7 +401,7 @@ s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
}
/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
{
u16 i;
s16 tmp;
@@ -415,7 +415,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
}
/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
-void b43_nrssi_mem_update(struct b43_wldev *dev)
+static void b43_nrssi_mem_update(struct b43_wldev *dev)
{
struct b43_phy_g *gphy = dev->phy.g;
s16 i, delta;
@@ -589,7 +589,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev)
b43_phy_write(dev, 0x0811, backup[1]);
}
-void b43_calc_nrssi_slope(struct b43_wldev *dev)
+static void b43_calc_nrssi_slope(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
@@ -1354,7 +1354,7 @@ struct init2050_saved_values {
u16 phy_syncctl;
};
-u16 b43_radio_init2050(struct b43_wldev *dev)
+static u16 b43_radio_init2050(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct init2050_saved_values sav;
@@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
int rfatt, bbatt;
u8 tx_control;
+ b43_mac_suspend(dev);
+
spin_lock_irq(&dev->wl->irq_lock);
/* Calculate the new attenuation values. */
@@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
gphy->tx_control);
b43_radio_unlock(dev);
b43_phy_unlock(dev);
+
+ b43_mac_enable(dev);
}
static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
@@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
+ b43_mac_suspend(dev);
//TODO: update_aci_moving_average
if (gphy->aci_enable && gphy->aci_wlan_automatic) {
- b43_mac_suspend(dev);
if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
if (0 /*TODO: bunch of conditions */ ) {
phy->ops->interf_mitigation(dev,
@@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
}
- b43_mac_enable(dev);
} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
phy->rev == 1) {
//TODO: implement rev1 workaround
}
b43_lo_g_maintanance_work(dev);
+ b43_mac_enable(dev);
}
static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 40159126759..1036bef8c4c 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
spin_lock(&q->lock); /* IRQs are already disabled. */
info = IEEE80211_SKB_CB(pack->skb);
- memset(&info->status, 0, sizeof(info->status));
- b43_fill_txstatus_report(info, status);
+ b43_fill_txstatus_report(dev, info, status);
total_len = pack->skb->len + b43_txhdr_size(dev);
total_len = roundup(total_len, 4);
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 2fabcf8f047..eae9b805265 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -46,7 +46,6 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp)
case 0x6E:
return 3;
}
- B43_WARN_ON(1);
return -1;
}
@@ -73,7 +72,6 @@ static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy)
case 0xC:
return base + 7;
}
- B43_WARN_ON(1);
return -1;
}
@@ -185,7 +183,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_info *info,
+ struct ieee80211_tx_info *info,
u16 cookie)
{
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
@@ -202,6 +200,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u16 phy_ctl = 0;
u8 extra_ft = 0;
struct ieee80211_rate *txrate;
+ struct ieee80211_tx_rate *rates;
memset(txhdr, 0, sizeof(*txhdr));
@@ -291,7 +290,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
@@ -314,6 +313,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
B43_WARN_ON(1);
}
+ rates = info->control.rates;
/* MAC control */
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK;
@@ -324,12 +324,22 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TXH_MAC_5GHZ;
- if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+ /* Overwrite rates[0].count to make the retry calculation
+ * in the tx status easier. need the actual retry limit to
+ * detect whether the fallback rate was used.
+ */
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+ rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
mac_ctl |= B43_TXH_MAC_LONGFRAME;
+ } else {
+ rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+ }
/* Generate the RTS or CTS-to-self frame */
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
@@ -344,7 +354,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
- if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) {
@@ -596,6 +606,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
phytype == B43_PHYTYPE_A);
else
status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
+ if (unlikely(status.rate_idx == -1))
+ goto drop;
status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
/*
@@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev,
/* Fill out the mac80211 TXstatus report based on the b43-specific
* txstatus report data. This returns a boolean whether the frame was
* successfully transmitted. */
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+ struct ieee80211_tx_info *report,
const struct b43_txstatus *status)
{
bool frame_success = 1;
+ int retry_limit;
+
+ /* preserve the confiured retry limit before clearing the status
+ * The xmit function has overwritten the rc's value with the actual
+ * retry limit done by the hardware */
+ retry_limit = report->status.rates[0].count;
+ ieee80211_tx_info_clear_status(report);
if (status->acked) {
/* The frame was ACKed. */
@@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ...but we expected an ACK. */
frame_success = 0;
- report->status.excessive_retries = 1;
}
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
- report->status.retry_count = 0;
- } else
- report->status.retry_count = status->frame_count - 1;
+ report->status.rates[0].count = 0;
+ } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+ /*
+ * If the short retries (RTS, not data frame) have exceeded
+ * the limit, the hw will not have tried the selected rate,
+ * but will have used the fallback rate instead.
+ * Don't let the rate control count attempts for the selected
+ * rate in this case, otherwise the statistics will be off.
+ */
+ report->status.rates[0].count = 0;
+ report->status.rates[1].count = status->frame_count;
+ } else {
+ if (status->frame_count > retry_limit) {
+ report->status.rates[0].count = retry_limit;
+ report->status.rates[1].count = status->frame_count -
+ retry_limit;
+
+ } else {
+ report->status.rates[0].count = status->frame_count;
+ report->status.rates[1].idx = -1;
+ }
+ }
return frame_success;
}
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 0215faf4754..4fb2a190f7a 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_info *txctl, u16 cookie);
+ struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */
struct b43_txstatus {
@@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+ struct ieee80211_tx_info *report,
const struct b43_txstatus *status);
void b43_tx_suspend(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index c40078e1fff..97b0e06dfe2 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -145,6 +145,10 @@
#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
/* SHM_SHARED rate tables */
+#define B43legacy_SHM_SH_OFDMDIRECT 0x0480 /* Pointer to OFDM direct map */
+#define B43legacy_SHM_SH_OFDMBASIC 0x04A0 /* Pointer to OFDM basic rate map */
+#define B43legacy_SHM_SH_CCKDIRECT 0x04C0 /* Pointer to CCK direct map */
+#define B43legacy_SHM_SH_CCKBASIC 0x04E0 /* Pointer to CCK basic rate map */
/* SHM_SHARED microcode soft registers */
#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
@@ -663,7 +667,6 @@ struct b43legacy_wldev {
bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM). */
bool short_preamble; /* TRUE if using short preamble. */
- bool short_slot; /* TRUE if using short slot timing. */
bool radio_hw_enable; /* State of radio hardware enable bit. */
/* PHY/Radio device. */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
index 03ce0821a60..1f85ac569fe 100644
--- a/drivers/net/wireless/b43legacy/debugfs.c
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -211,7 +211,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
struct b43legacy_dfs_file *dfile;
ssize_t uninitialized_var(ret);
char *buf;
- const size_t bufsize = 1024 * 128;
+ const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
const size_t buforder = get_order(bufsize);
int err = 0;
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index fb6819e40f3..3649fc36709 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = ssb_dma_map_single(dev->dev,
+ dma_test = ssb_dma_map_single(dev->dev,
ring->txhdr_cache,
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
@@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
struct b43legacy_dmaring *ring;
struct b43legacy_dmadesc_generic *desc;
struct b43legacy_dmadesc_meta *meta;
+ int retry_limit;
int slot;
ring = parse_cookie(dev, status->cookie, &slot);
@@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
struct ieee80211_tx_info *info;
BUG_ON(!meta->skb);
info = IEEE80211_SKB_CB(meta->skb);
- /* Call back to inform the ieee80211 subsystem about the
- * status of the transmission.
- * Some fields of txstat are already filled in dma_tx().
- */
- memset(&info->status, 0, sizeof(info->status));
+ /* preserve the confiured retry limit before clearing the status
+ * The xmit function has overwritten the rc's value with the actual
+ * retry limit done by the hardware */
+ retry_limit = info->status.rates[0].count;
+ ieee80211_tx_info_clear_status(info);
- if (status->acked) {
+ if (status->acked)
info->flags |= IEEE80211_TX_STAT_ACK;
+
+ if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+ /*
+ * If the short retries (RTS, not data frame) have exceeded
+ * the limit, the hw will not have tried the selected rate,
+ * but will have used the fallback rate instead.
+ * Don't let the rate control count attempts for the selected
+ * rate in this case, otherwise the statistics will be off.
+ */
+ info->status.rates[0].count = 0;
+ info->status.rates[1].count = status->frame_count;
} else {
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
- info->status.excessive_retries = 1;
+ if (status->frame_count > retry_limit) {
+ info->status.rates[0].count = retry_limit;
+ info->status.rates[1].count = status->frame_count -
+ retry_limit;
+
+ } else {
+ info->status.rates[0].count = status->frame_count;
+ info->status.rates[1].idx = -1;
+ }
}
- if (status->frame_count == 0) {
- /* The frame was not transmitted at all. */
- info->status.retry_count = 0;
- } else
- info->status.retry_count = status->frame_count
- - 1;
+
+ /* Call back to inform the ieee80211 subsystem about the
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
/* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c66d57560e7..c1324e31d2f 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -576,13 +576,11 @@ static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
{
b43legacy_set_slot_time(dev, 9);
- dev->short_slot = 1;
}
static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
{
b43legacy_set_slot_time(dev, 20);
- dev->short_slot = 0;
}
/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -1160,29 +1158,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
wl->beacon1_uploaded = 0;
}
-static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
- const u8 *ssid, u8 ssid_len)
-{
- u32 tmp;
- u16 i;
- u16 len;
-
- len = min((u16)ssid_len, (u16)0x100);
- for (i = 0; i < len; i += sizeof(u32)) {
- tmp = (u32)(ssid[i + 0]);
- if (i + 1 < len)
- tmp |= (u32)(ssid[i + 1]) << 8;
- if (i + 2 < len)
- tmp |= (u32)(ssid[i + 2]) << 16;
- if (i + 3 < len)
- tmp |= (u32)(ssid[i + 3]) << 24;
- b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
- 0x380 + i, tmp);
- }
- b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
- 0x48, len);
-}
-
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
u16 beacon_int)
{
@@ -2556,26 +2531,27 @@ init_failure:
return err;
}
-static int b43legacy_antenna_from_ieee80211(u8 antenna)
+/* Write the short and long frame retry limit values. */
+static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
+ unsigned int short_retry,
+ unsigned int long_retry)
{
- switch (antenna) {
- case 0: /* default/diversity */
- return B43legacy_ANTENNA_DEFAULT;
- case 1: /* Antenna 0 */
- return B43legacy_ANTENNA0;
- case 2: /* Antenna 1 */
- return B43legacy_ANTENNA1;
- default:
- return B43legacy_ANTENNA_DEFAULT;
- }
+ /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter. */
+ short_retry = min(short_retry, (unsigned int)0xF);
+ long_retry = min(long_retry, (unsigned int)0xF);
+
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
}
static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf)
+ u32 changed)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev;
struct b43legacy_phy *phy;
+ struct ieee80211_conf *conf = &hw->conf;
unsigned long flags;
unsigned int new_phymode = 0xFFFF;
int antenna_tx;
@@ -2583,13 +2559,21 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
int err = 0;
u32 savedirqs;
- antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
- antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+ antenna_tx = B43legacy_ANTENNA_DEFAULT;
+ antenna_rx = B43legacy_ANTENNA_DEFAULT;
mutex_lock(&wl->mutex);
dev = wl->current_dev;
phy = &dev->phy;
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ b43legacy_set_retry_limits(dev,
+ conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);
+ changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
+ if (!changed)
+ goto out_unlock_mutex;
+
/* Switch the PHY mode (if necessary). */
switch (conf->channel->band) {
case IEEE80211_BAND_2GHZ:
@@ -2622,16 +2606,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
if (conf->channel->hw_value != phy->channel)
b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
- /* Enable/Disable ShortSlot timing. */
- if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
- != dev->short_slot) {
- B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
- if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
- b43legacy_short_slot_timing_enable(dev);
- else
- b43legacy_short_slot_timing_disable(dev);
- }
-
dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
/* Adjust the desired TX power level. */
@@ -2676,6 +2650,104 @@ out_unlock_mutex:
return err;
}
+static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates)
+{
+ struct ieee80211_supported_band *sband =
+ dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+ struct ieee80211_rate *rate;
+ int i;
+ u16 basic, direct, offset, basic_offset, rateptr;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = &sband->bitrates[i];
+
+ if (b43legacy_is_cck_rate(rate->hw_value)) {
+ direct = B43legacy_SHM_SH_CCKDIRECT;
+ basic = B43legacy_SHM_SH_CCKBASIC;
+ offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+ offset &= 0xF;
+ } else {
+ direct = B43legacy_SHM_SH_OFDMDIRECT;
+ basic = B43legacy_SHM_SH_OFDMBASIC;
+ offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+ offset &= 0xF;
+ }
+
+ rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+ if (b43legacy_is_cck_rate(rate->hw_value)) {
+ basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value);
+ basic_offset &= 0xF;
+ } else {
+ basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value);
+ basic_offset &= 0xF;
+ }
+
+ /*
+ * Get the pointer that we need to point to
+ * from the direct map
+ */
+ rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ direct + 2 * basic_offset);
+ /* and write it to the basic map */
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ basic + 2 * offset, rateptr);
+ }
+}
+
+static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *conf,
+ u32 changed)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev;
+ struct b43legacy_phy *phy;
+ unsigned long flags;
+ u32 savedirqs;
+
+ mutex_lock(&wl->mutex);
+
+ dev = wl->current_dev;
+ phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+ * the reconfiguration process. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ goto out_unlock_mutex;
+ }
+ savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ b43legacy_mac_suspend(dev);
+
+ if (changed & BSS_CHANGED_BASIC_RATES)
+ b43legacy_update_basic_rates(dev, conf->basic_rates);
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ if (conf->use_short_slot)
+ b43legacy_short_slot_timing_enable(dev);
+ else
+ b43legacy_short_slot_timing_disable(dev);
+ }
+
+ b43legacy_mac_enable(dev);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_interrupt_enable(dev, savedirqs);
+ /* XXX: why? */
+ mmiowb();
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return;
+}
+
static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *fflags,
@@ -2735,7 +2807,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
- b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->changed & IEEE80211_IFCC_BEACON)
b43legacy_update_templates(wl);
} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -3002,20 +3073,6 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
#endif /* CONFIG_SSB_DRIVER_PCICORE */
}
-/* Write the short and long frame retry limit values. */
-static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
- unsigned int short_retry,
- unsigned int long_retry)
-{
- /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
- * the chip-internal counter. */
- short_retry = min(short_retry, (unsigned int)0xF);
- long_retry = min(long_retry, (unsigned int)0xF);
-
- b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
- b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
-}
-
static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
bool idle) {
u16 pu_delay = 1050;
@@ -3380,28 +3437,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
mutex_unlock(&wl->mutex);
}
-static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry_limit,
- u32 long_retry_limit)
-{
- struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
- struct b43legacy_wldev *dev;
- int err = 0;
-
- mutex_lock(&wl->mutex);
- dev = wl->current_dev;
- if (unlikely(!dev ||
- (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) {
- err = -ENODEV;
- goto out_unlock;
- }
- b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit);
-out_unlock:
- mutex_unlock(&wl->mutex);
-
- return err;
-}
-
static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, bool set)
{
@@ -3421,13 +3456,13 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
.add_interface = b43legacy_op_add_interface,
.remove_interface = b43legacy_op_remove_interface,
.config = b43legacy_op_dev_config,
+ .bss_info_changed = b43legacy_op_bss_info_changed,
.config_interface = b43legacy_op_config_interface,
.configure_filter = b43legacy_op_configure_filter,
.get_stats = b43legacy_op_get_stats,
.get_tx_stats = b43legacy_op_get_tx_stats,
.start = b43legacy_op_start,
.stop = b43legacy_op_stop,
- .set_retry_limit = b43legacy_op_set_retry_limit,
.set_tim = b43legacy_op_beacon_set_tim,
};
@@ -3710,7 +3745,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 1; /* FIXME: hardware has more queues */
- hw->max_altrates = 1;
+ hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 4c9442b16f3..11319ec2d64 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -1296,12 +1296,10 @@ void b43legacy_lo_write(struct b43legacy_wldev *dev,
/* Sanity check. */
if (pair->low < -8 || pair->low > 8 ||
pair->high < -8 || pair->high > 8) {
- struct b43legacy_phy *phy = &dev->phy;
b43legacydbg(dev->wl,
"WARNING: Writing invalid LOpair "
- "(low: %d, high: %d, index: %lu)\n",
- pair->low, pair->high,
- (unsigned long)(pair - phy->_lo_pairs));
+ "(low: %d, high: %d)\n",
+ pair->low, pair->high);
dump_stack();
}
#endif
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index a86c7647fa2..746d5361bba 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
struct b43legacy_pioqueue *queue;
struct b43legacy_pio_txpacket *packet;
struct ieee80211_tx_info *info;
+ int retry_limit;
queue = parse_cookie(dev, status->cookie, &packet);
B43legacy_WARN_ON(!queue);
@@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
sizeof(struct b43legacy_txhdr_fw3));
info = IEEE80211_SKB_CB(packet->skb);
- memset(&info->status, 0, sizeof(info->status));
+
+ /* preserve the confiured retry limit before clearing the status
+ * The xmit function has overwritten the rc's value with the actual
+ * retry limit done by the hardware */
+ retry_limit = info->status.rates[0].count;
+ ieee80211_tx_info_clear_status(info);
if (status->acked)
info->flags |= IEEE80211_TX_STAT_ACK;
- info->status.retry_count = status->frame_count - 1;
+
+ if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+ /*
+ * If the short retries (RTS, not data frame) have exceeded
+ * the limit, the hw will not have tried the selected rate,
+ * but will have used the fallback rate instead.
+ * Don't let the rate control count attempts for the selected
+ * rate in this case, otherwise the statistics will be off.
+ */
+ info->status.rates[0].count = 0;
+ info->status.rates[1].count = status->frame_count;
+ } else {
+ if (status->frame_count > retry_limit) {
+ info->status.rates[0].count = retry_limit;
+ info->status.rates[1].count = status->frame_count -
+ retry_limit;
+
+ } else {
+ info->status.rates[0].count = status->frame_count;
+ info->status.rates[1].idx = -1;
+ }
+ }
ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
packet->skb = NULL;
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index 65e83378160..12fca99f757 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
struct b43legacy_txhdr_fw3 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_info *info,
+ struct ieee80211_tx_info *info,
u16 cookie)
{
const struct ieee80211_hdr *wlhdr;
@@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
u32 mac_ctl = 0;
u16 phy_ctl = 0;
struct ieee80211_rate *tx_rate;
+ struct ieee80211_tx_rate *rates;
wlhdr = (const struct ieee80211_hdr *)fragment_data;
@@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
/* PHY TX Control word */
if (rate_ofdm)
phy_ctl |= B43legacy_TX4_PHY_OFDM;
- if (dev->short_preamble)
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
switch (info->antenna_sel_tx) {
case 0:
@@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
}
/* MAC control */
+ rates = info->control.rates;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43legacy_TX4_MAC_ACK;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
if (rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
- if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+ /* Overwrite rates[0].count to make the retry calculation
+ * in the tx status easier. need the actual retry limit to
+ * detect whether the fallback rate was used.
+ */
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+ rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+ } else {
+ rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+ }
/* Generate the RTS or CTS-to-self frame */
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate;
@@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
if (rts_rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
- if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
ieee80211_ctstoself_get(dev->wl->hw,
info->control.vif,
fragment_data,
@@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_info *info,
+ struct ieee80211_tx_info *info,
u16 cookie)
{
return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index e56777e0fea..62e09d02788 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_info *info,
+ struct ieee80211_tx_info *info,
u16 cookie);
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
index 1fef33169fd..932d207bce2 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -2,8 +2,17 @@ config HOSTAP
tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
depends on WLAN_80211
select WIRELESS_EXT
- select IEEE80211
- select IEEE80211_CRYPT_WEP
+ select CRYPTO
+ select CRYPTO_ARC4
+ select CRYPTO_ECB
+ select CRYPTO_AES
+ select CRYPTO_MICHAEL_MIC
+ select CRYPTO_ECB
+ select CRC32
+ select LIB80211
+ select LIB80211_CRYPT_WEP
+ select LIB80211_CRYPT_TKIP
+ select LIB80211_CRYPT_CCMP
---help---
Shared driver code for IEEE 802.11b wireless cards based on
Intersil Prism2/2.5/3 chipset. This driver supports so called
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index 3a386a636cc..2453deaa3e0 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -63,7 +63,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);
void ap_control_kickall(struct ap_data *ap);
void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct ieee80211_crypt_data ***crypt);
+ struct lib80211_crypt_data ***crypt);
int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
struct iw_quality qual[], int buf_size,
int aplist);
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 3694b1eba52..3a9474d9a90 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -2,7 +2,7 @@
#define HOSTAP_80211_H
#include <linux/types.h>
-#include <net/ieee80211_crypt.h>
+#include <net/ieee80211.h>
struct hostap_ieee80211_mgmt {
__le16 frame_control;
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index f106bc1585a..19b1bf0478b 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -1,5 +1,5 @@
#include <linux/etherdevice.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
#include "hostap_80211.h"
#include "hostap.h"
@@ -19,7 +19,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
- DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -45,11 +44,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
- printk(" A2=%s", print_mac(mac, hdr->addr2));
- printk(" A3=%s", print_mac(mac, hdr->addr3));
+ printk(KERN_DEBUG " A1=%pM", hdr->addr1);
+ printk(" A2=%pM", hdr->addr2);
+ printk(" A3=%pM", hdr->addr3);
if (skb->len >= 30)
- printk(" A4=%s", print_mac(mac, hdr->addr4));
+ printk(" A4=%pM", hdr->addr4);
printk("\n");
}
@@ -68,7 +67,6 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
iface = netdev_priv(dev);
local = iface->local;
- dev->last_rx = jiffies;
if (dev->type == ARPHRD_IEEE80211_PRISM) {
if (local->monitor_type == PRISM2_MONITOR_PRISM) {
@@ -557,7 +555,6 @@ static int
hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
u16 fc, struct net_device **wds)
{
- DECLARE_MAC_BUF(mac);
/* FIX: is this really supposed to accept WDS frames only in Master
* mode? What about Repeater or Managed with WDS frames? */
if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
@@ -573,10 +570,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
/* RA (or BSSID) is not ours - drop */
PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
- "not own or broadcast %s=%s\n",
+ "not own or broadcast %s=%pM\n",
local->dev->name,
fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
- print_mac(mac, hdr->addr1));
+ hdr->addr1);
return -1;
}
@@ -589,8 +586,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
/* require that WDS link has been registered with TA or the
* frame is from current AP when using 'AP client mode' */
PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
- "from unknown TA=%s\n",
- local->dev->name, print_mac(mac, hdr->addr2));
+ "from unknown TA=%pM\n",
+ local->dev->name, hdr->addr2);
if (local->ap && local->ap->autom_ap_wds)
hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
return -1;
@@ -652,7 +649,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
/* Called only as a tasklet (software IRQ) */
static int
hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
- struct ieee80211_crypt_data *crypt)
+ struct lib80211_crypt_data *crypt)
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
@@ -667,10 +664,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MAC_FMT "\n",
- local->dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "received packet from %pM\n",
+ local->dev->name, hdr->addr2);
}
return -1;
}
@@ -679,12 +674,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
- printk(KERN_DEBUG "%s: decryption failed (SA=" MAC_FMT
- ") res=%d\n",
- local->dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
- res);
+ printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n",
+ local->dev->name, hdr->addr2, res);
local->comm_tallies.rx_discards_wep_undecryptable++;
return -1;
}
@@ -696,11 +687,10 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
/* Called only as a tasklet (software IRQ) */
static int
hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
- int keyidx, struct ieee80211_crypt_data *crypt)
+ int keyidx, struct lib80211_crypt_data *crypt)
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
- DECLARE_MAC_BUF(mac);
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
return 0;
@@ -713,8 +703,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%s keyidx=%d)\n",
- local->dev->name, print_mac(mac, hdr->addr2), keyidx);
+ " (SA=%pM keyidx=%d)\n",
+ local->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -743,7 +733,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
int from_assoc_ap = 0;
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN];
- struct ieee80211_crypt_data *crypt = NULL;
+ struct lib80211_crypt_data *crypt = NULL;
void *sta = NULL;
int keyidx = 0;
@@ -795,7 +785,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
int idx = 0;
if (skb->len >= hdrlen + 3)
idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt[idx];
+ crypt = local->crypt_info.crypt[idx];
sta = NULL;
/* Use station specific key to override default keys if the
@@ -822,10 +812,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
- " (SA=" MAC_FMT ")\n",
- local->dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ " (SA=%pM)\n",
+ local->dev->name, hdr->addr2);
#endif
local->comm_tallies.rx_discards_wep_undecryptable++;
goto rx_dropped;
@@ -839,9 +827,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
(keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
{
printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from " MAC_FMT "\n", dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "from %pM\n", dev->name, hdr->addr2);
/* TODO: could inform hostapd about this so that it
* could send auth failure report */
goto rx_dropped;
@@ -896,8 +882,6 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
from_assoc_ap = 1;
}
- dev->last_rx = jiffies;
-
if ((local->iw_mode == IW_MODE_MASTER ||
local->iw_mode == IW_MODE_REPEAT) &&
!from_assoc_ap) {
@@ -1009,10 +993,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
"unencrypted EAPOL frame\n", local->dev->name);
} else {
printk(KERN_DEBUG "%s: encryption configured, but RX "
- "frame not encrypted (SA=" MAC_FMT ")\n",
- local->dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "frame not encrypted (SA=%pM)\n",
+ local->dev->name, hdr->addr2);
goto rx_dropped;
}
}
@@ -1021,10 +1003,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
!hostap_is_eapol_frame(local, skb)) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: dropped unencrypted RX data "
- "frame from " MAC_FMT " (drop_unencrypted=1)\n",
- dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "frame from %pM (drop_unencrypted=1)\n",
+ dev->name, hdr->addr2);
}
goto rx_dropped;
}
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 921c984416f..078a010f39a 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -17,7 +17,6 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
- DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -41,11 +40,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
- printk(" A2=%s", print_mac(mac, hdr->addr2));
- printk(" A3=%s", print_mac(mac, hdr->addr3));
+ printk(KERN_DEBUG " A1=%pM", hdr->addr1);
+ printk(" A2=%pM", hdr->addr2);
+ printk(" A3=%pM", hdr->addr3);
if (skb->len >= 30)
- printk(" A4=%s", print_mac(mac, hdr->addr4));
+ printk(" A4=%pM", hdr->addr4);
printk("\n");
}
@@ -307,7 +306,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Called only from software IRQ */
static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
- struct ieee80211_crypt_data *crypt)
+ struct lib80211_crypt_data *crypt)
{
struct hostap_interface *iface;
local_info_t *local;
@@ -328,10 +327,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MAC_FMT "\n",
- local->dev->name,
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ "TX packet to %pM\n",
+ local->dev->name, hdr->addr1);
}
kfree_skb(skb);
return NULL;
@@ -408,7 +405,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (local->host_encrypt) {
/* Set crypt to default algorithm and key; will be replaced in
* AP code if STA has own alg/key */
- tx.crypt = local->crypt[local->tx_keyidx];
+ tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
tx.host_encrypt = 1;
} else {
tx.crypt = NULL;
@@ -490,7 +487,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
tx.crypt = NULL;
- else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) {
+ else if ((tx.crypt ||
+ local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
+ !no_encrypt) {
/* Add ISWEP flag both for firmware and host based encryption
*/
fc |= IEEE80211_FCTL_PROTECTED;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index af3d4ef2a80..0903db786d5 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -94,7 +94,6 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
{
struct sta_info *s;
- DECLARE_MAC_BUF(mac);
s = ap->sta_hash[STA_HASH(sta->addr)];
if (s == NULL) return;
@@ -109,20 +108,18 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
- printk("AP: could not remove STA %s"
- " from hash table\n",
- print_mac(mac, sta->addr));
+ printk("AP: could not remove STA %pM from hash table\n",
+ sta->addr);
}
static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
{
- DECLARE_MAC_BUF(mac);
if (sta->ap && sta->local)
hostap_event_expired_sta(sta->local->dev, sta);
if (ap->proc != NULL) {
char name[20];
- sprintf(name, "%s", print_mac(mac, sta->addr));
+ sprintf(name, "%pM", sta->addr);
remove_proc_entry(name, ap->proc);
}
@@ -185,7 +182,6 @@ static void ap_handle_timer(unsigned long data)
struct ap_data *ap;
unsigned long next_time = 0;
int was_assoc;
- DECLARE_MAC_BUF(mac);
if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
@@ -242,8 +238,8 @@ static void ap_handle_timer(unsigned long data)
if (sta->ap) {
if (ap->autom_ap_wds) {
PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
- "connection to AP %s\n",
- local->dev->name, print_mac(mac, sta->addr));
+ "connection to AP %pM\n",
+ local->dev->name, sta->addr);
hostap_wds_link_oper(local, sta->addr, WDS_DEL);
}
} else if (sta->timeout_next == STA_NULLFUNC) {
@@ -259,11 +255,11 @@ static void ap_handle_timer(unsigned long data)
} else {
int deauth = sta->timeout_next == STA_DEAUTH;
__le16 resp;
- PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
+ PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM"
"(last=%lu, jiffies=%lu)\n",
local->dev->name,
deauth ? "deauthentication" : "disassociation",
- print_mac(mac, sta->addr), sta->last_rx, jiffies);
+ sta->addr, sta->last_rx, jiffies);
resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
@@ -275,10 +271,10 @@ static void ap_handle_timer(unsigned long data)
if (sta->timeout_next == STA_DEAUTH) {
if (sta->flags & WLAN_STA_PERM) {
- PDEBUG(DEBUG_AP, "%s: STA %s"
+ PDEBUG(DEBUG_AP, "%s: STA %pM"
" would have been removed, "
"but it has 'perm' flag\n",
- local->dev->name, print_mac(mac, sta->addr));
+ local->dev->name, sta->addr);
} else
ap_free_sta(ap, sta);
return;
@@ -332,7 +328,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
char *policy_txt;
struct mac_entry *entry;
- DECLARE_MAC_BUF(mac);
if (off != 0) {
*eof = 1;
@@ -363,7 +358,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
break;
}
- p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
+ p += sprintf(p, "%pM\n", entry->addr);
}
spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -520,7 +515,6 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
struct sta_info *sta;
int i;
- DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -533,8 +527,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
if (!sta->ap)
continue;
- p += sprintf(p, "%s %d %d %d %d '",
- print_mac(mac, sta->addr),
+ p += sprintf(p, "%pM %d %d %d %d '",
+ sta->addr,
sta->u.ap.channel, sta->last_rx_signal,
sta->last_rx_silence, sta->last_rx_rate);
for (i = 0; i < sta->u.ap.ssid_len; i++)
@@ -683,11 +677,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d "
+ PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d "
"trans#=%d status=%d - %s\n",
- dev->name,
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
+ dev->name, hdr->addr1,
auth_alg, auth_transaction, status, txt);
}
dev_kfree_skb(skb);
@@ -754,11 +746,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n",
- dev->name,
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
- txt);
+ PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n",
+ dev->name, hdr->addr1, txt);
}
dev_kfree_skb(skb);
}
@@ -781,11 +770,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
sta->flags &= ~WLAN_STA_PENDING_POLL;
spin_unlock(&ap->sta_table_lock);
} else {
- PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
- " did not ACK activity poll frame\n",
- ap->local->dev->name,
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ PDEBUG(DEBUG_AP,
+ "%s: STA %pM did not ACK activity poll frame\n",
+ ap->local->dev->name, hdr->addr1);
}
fail:
@@ -1002,7 +989,6 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
char *p = page;
struct sta_info *sta = (struct sta_info *) data;
int i;
- DECLARE_MAC_BUF(mac);
/* FIX: possible race condition.. the STA data could have just expired,
* but proc entry was still here so that the read could have started;
@@ -1013,11 +999,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
return 0;
}
- p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
+ p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n"
"flags=0x%04x%s%s%s%s%s%s%s\n"
"capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
sta->ap ? "AP" : "STA",
- print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
+ sta->addr, atomic_read(&sta->users), sta->aid,
sta->flags,
sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
@@ -1078,7 +1064,6 @@ static void handle_add_proc_queue(struct work_struct *work)
struct sta_info *sta;
char name[20];
struct add_sta_proc_data *entry, *prev;
- DECLARE_MAC_BUF(mac);
entry = ap->add_sta_proc_entries;
ap->add_sta_proc_entries = NULL;
@@ -1091,7 +1076,7 @@ static void handle_add_proc_queue(struct work_struct *work)
spin_unlock_bh(&ap->sta_table_lock);
if (sta) {
- sprintf(name, "%s", print_mac(mac, sta->addr));
+ sprintf(name, "%pM", sta->addr);
sta->proc = create_proc_read_entry(
name, 0, ap->proc,
prism2_sta_proc_read, sta);
@@ -1221,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta)
static void ap_crypt_init(struct ap_data *ap)
{
- ap->crypt = ieee80211_get_crypto_ops("WEP");
+ ap->crypt = lib80211_get_crypto_ops("WEP");
if (ap->crypt) {
if (ap->crypt->init) {
@@ -1239,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap)
if (ap->crypt == NULL) {
printk(KERN_WARNING "AP could not initialize WEP: load module "
- "ieee80211_crypt_wep.ko\n");
+ "lib80211_crypt_wep.ko\n");
}
}
@@ -1308,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
__le16 *pos;
u16 resp = WLAN_STATUS_SUCCESS, fc;
struct sta_info *sta = NULL;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
char *txt = "";
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1318,9 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (len < 6) {
PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
- "(len=%d) from " MAC_FMT "\n", dev->name, len,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "(len=%d) from %pM\n", dev->name, len, hdr->addr2);
return;
}
@@ -1336,7 +1319,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
int idx = 0;
if (skb->len >= hdrlen + 3)
idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt[idx];
+ crypt = local->crypt_info.crypt[idx];
}
pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
@@ -1385,10 +1368,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (time_after(jiffies, sta->u.ap.last_beacon +
(10 * sta->listen_interval * HZ) / 1024)) {
PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
- " assuming AP " MAC_FMT " is now STA\n",
- dev->name,
- sta->addr[0], sta->addr[1], sta->addr[2],
- sta->addr[3], sta->addr[4], sta->addr[5]);
+ " assuming AP %pM is now STA\n",
+ dev->name, sta->addr);
sta->ap = 0;
sta->flags = 0;
sta->u.sta.challenge = NULL;
@@ -1503,11 +1484,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
}
if (resp) {
- PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d "
+ PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d "
"trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
- dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+ dev->name, hdr->addr2,
auth_alg, auth_transaction, status_code, len,
fc, resp, txt);
}
@@ -1533,10 +1512,8 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
if (len < (reassoc ? 10 : 4)) {
PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
- "(len=%d, reassoc=%d) from " MAC_FMT "\n",
- dev->name, len, reassoc,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
+ "(len=%d, reassoc=%d) from %pM\n",
+ dev->name, len, reassoc, hdr->addr2);
return;
}
@@ -1613,12 +1590,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
if (left > 0) {
- PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT
+ PDEBUG(DEBUG_AP, "%s: assoc from %pM"
" with extra data (%d bytes) [",
- dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
- left);
+ dev->name, hdr->addr2, left);
while (left > 0) {
PDEBUG2(DEBUG_AP, "<%02x>", *u);
u++; left--;
@@ -1717,14 +1691,12 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
#if 0
- PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d "
- "prev_ap=" MAC_FMT") => %d(%d) (%s)\n",
+ PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d "
+ "prev_ap=%pM) => %d(%d) (%s)\n",
dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+ hdr->addr2,
reassoc ? "re" : "", len,
- prev_ap[0], prev_ap[1], prev_ap[2],
- prev_ap[3], prev_ap[4], prev_ap[5],
+ prev_ap,
resp, send_deauth, txt);
#endif
}
@@ -1741,7 +1713,6 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
u16 reason_code;
__le16 *pos;
struct sta_info *sta = NULL;
- DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1753,10 +1724,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
pos = (__le16 *) body;
reason_code = le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, "
- "reason_code=%d\n", dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+ PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, "
+ "reason_code=%d\n", dev->name, hdr->addr2,
len, reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1768,11 +1737,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: deauthentication from " MAC_FMT ", "
+ printk("%s: deauthentication from %pM, "
"reason_code=%d, but STA not authenticated\n", dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
- reason_code);
+ hdr->addr2, reason_code);
}
}
@@ -1799,10 +1766,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
pos = (__le16 *) body;
reason_code = le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, "
- "reason_code=%d\n", dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+ PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, "
+ "reason_code=%d\n", dev->name, hdr->addr2,
len, reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1814,12 +1779,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: disassociation from " MAC_FMT ", "
+ printk("%s: disassociation from %pM, "
"reason_code=%d, but STA not authenticated\n",
- dev->name,
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
- reason_code);
+ dev->name, hdr->addr2, reason_code);
}
}
@@ -1909,19 +1871,14 @@ static void handle_pspoll(local_info_t *local,
u16 aid;
struct sk_buff *skb;
- PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT
- ", TA=" MAC_FMT " PWRMGT=%d\n",
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
- hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
- hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
+ PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n",
+ hdr->addr1, hdr->addr2,
!!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT
- " not own MAC\n",
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ PDEBUG(DEBUG_AP,
+ "handle_pspoll - addr1(BSSID)=%pM not own MAC\n",
+ hdr->addr1);
return;
}
@@ -2007,11 +1964,10 @@ static void handle_wds_oper_queue(struct work_struct *work)
while (entry) {
PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
- "to AP " MAC_FMT "\n",
+ "to AP %pM\n",
local->dev->name,
entry->type == WDS_ADD ? "adding" : "removing",
- entry->addr[0], entry->addr[1], entry->addr[2],
- entry->addr[3], entry->addr[4], entry->addr[5]);
+ entry->addr);
if (entry->type == WDS_ADD)
prism2_wds_add(local, entry->addr, 0);
else if (entry->type == WDS_DEL)
@@ -2215,10 +2171,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
}
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
- MAC_FMT " not own MAC\n",
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM"
+ " not own MAC\n", hdr->addr1);
goto done;
}
@@ -2254,18 +2208,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
}
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT
- " not own MAC\n",
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM"
+ " not own MAC\n", hdr->addr1);
goto done;
}
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT
- " not own MAC\n",
- hdr->addr3[0], hdr->addr3[1], hdr->addr3[2],
- hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]);
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM"
+ " not own MAC\n", hdr->addr3);
goto done;
}
@@ -2366,10 +2316,9 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
memcpy(hdr->addr2, sta->addr, ETH_ALEN);
hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
- PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
- MAC_FMT "\n", local->dev->name,
- sta->addr[0], sta->addr[1], sta->addr[2],
- sta->addr[3], sta->addr[4], sta->addr[5]);
+ PDEBUG(DEBUG_PS2,
+ "%s: Scheduling buffered packet delivery for STA %pM\n",
+ local->dev->name, sta->addr);
skb->dev = local->dev;
@@ -2723,12 +2672,8 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
- " TX rate raised to %d\n",
- dev->name,
- sta->addr[0], sta->addr[1], sta->addr[2],
- sta->addr[3], sta->addr[4], sta->addr[5],
- sta->tx_rate);
+ PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n",
+ dev->name, sta->addr, sta->tx_rate);
}
sta->tx_since_last_failure = 0;
}
@@ -2781,9 +2726,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
* print out any errors here. */
if (net_ratelimit()) {
printk(KERN_DEBUG "AP: drop packet to non-associated "
- "STA " MAC_FMT "\n",
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
+ "STA %pM\n", hdr->addr1);
}
#endif
local->ap->tx_drop_nonassoc++;
@@ -2821,11 +2764,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
}
if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
- PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT
- ")'s PS mode buffer\n",
- local->dev->name,
- sta->addr[0], sta->addr[1], sta->addr[2],
- sta->addr[3], sta->addr[4], sta->addr[5]);
+ PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s"
+ "PS mode buffer\n",
+ local->dev->name, sta->addr);
/* Make sure that TIM is set for the station (it might not be
* after AP wlan hw reset). */
/* FIX: should fix hw reset to restore bits based on STA
@@ -2897,12 +2838,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
sta = ap_get_sta(local->ap, hdr->addr1);
if (!sta) {
spin_unlock(&local->ap->sta_table_lock);
- PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT
+ PDEBUG(DEBUG_AP, "%s: Could not find STA %pM"
" for this TX error (@%lu)\n",
- local->dev->name,
- hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
- hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
- jiffies);
+ local->dev->name, hdr->addr1, jiffies);
return;
}
@@ -2929,12 +2867,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
- " TX rate lowered to %d\n",
- local->dev->name,
- sta->addr[0], sta->addr[1], sta->addr[2],
- sta->addr[3], sta->addr[4], sta->addr[5],
- sta->tx_rate);
+ PDEBUG(DEBUG_AP,
+ "%s: STA %pM TX rate lowered to %d\n",
+ local->dev->name, sta->addr, sta->tx_rate);
}
sta->tx_consecutive_exc = 0;
}
@@ -2945,17 +2880,16 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
int pwrmgt, int type, int stype)
{
- DECLARE_MAC_BUF(mac);
if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
sta->flags |= WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
+ PDEBUG(DEBUG_PS2, "STA %pM changed to use PS "
"mode (type=0x%02X, stype=0x%02X)\n",
- print_mac(mac, sta->addr), type >> 2, stype >> 4);
+ sta->addr, type >> 2, stype >> 4);
} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
sta->flags &= ~WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %s changed to not use "
+ PDEBUG(DEBUG_PS2, "STA %pM changed to not use "
"PS mode (type=0x%02X, stype=0x%02X)\n",
- print_mac(mac, sta->addr), type >> 2, stype >> 4);
+ sta->addr, type >> 2, stype >> 4);
if (type != IEEE80211_FTYPE_CTL ||
stype != IEEE80211_STYPE_PSPOLL)
schedule_packet_send(local, sta);
@@ -3029,13 +2963,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
} else {
printk(KERN_DEBUG "%s: dropped received packet"
- " from non-associated STA "
- MAC_FMT
+ " from non-associated STA %pM"
" (type=0x%02x, subtype=0x%02x)\n",
- dev->name,
- hdr->addr2[0], hdr->addr2[1],
- hdr->addr2[2], hdr->addr2[3],
- hdr->addr2[4], hdr->addr2[5],
+ dev->name, hdr->addr2,
type >> 2, stype >> 4);
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -3068,13 +2998,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* after being unavailable for some time. Speed up
* re-association by informing the station about it not
* being associated. */
- printk(KERN_DEBUG "%s: rejected received nullfunc "
- "frame without ToDS from not associated STA "
- MAC_FMT "\n",
- dev->name,
- hdr->addr2[0], hdr->addr2[1],
- hdr->addr2[2], hdr->addr2[3],
- hdr->addr2[4], hdr->addr2[5]);
+ printk(KERN_DEBUG "%s: rejected received nullfunc frame"
+ " without ToDS from not associated STA %pM\n",
+ dev->name, hdr->addr2);
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
}
@@ -3090,13 +3016,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* broadcast frame from an IBSS network. Drop it silently.
* If BSSID is own, report the dropping of this frame. */
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
- printk(KERN_DEBUG "%s: dropped received packet from "
- MAC_FMT " with no ToDS flag "
+ printk(KERN_DEBUG "%s: dropped received packet from %pM"
+ " with no ToDS flag "
"(type=0x%02x, subtype=0x%02x)\n", dev->name,
- hdr->addr2[0], hdr->addr2[1],
- hdr->addr2[2], hdr->addr2[3],
- hdr->addr2[4], hdr->addr2[5],
- type >> 2, stype >> 4);
+ hdr->addr2, type >> 2, stype >> 4);
hostap_dump_rx_80211(dev->name, skb, rx_stats);
}
ret = AP_RX_DROP;
@@ -3142,7 +3065,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
/* Called only as a tasklet (software IRQ) */
int hostap_handle_sta_crypto(local_info_t *local,
struct ieee80211_hdr_4addr *hdr,
- struct ieee80211_crypt_data **crypt,
+ struct lib80211_crypt_data **crypt,
void **sta_ptr)
{
struct sta_info *sta;
@@ -3290,7 +3213,7 @@ void hostap_update_rates(local_info_t *local)
void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct ieee80211_crypt_data ***crypt)
+ struct lib80211_crypt_data ***crypt)
{
struct sta_info *sta;
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h
index 2fa2452b6b0..d36e4b17533 100644
--- a/drivers/net/wireless/hostap/hostap_ap.h
+++ b/drivers/net/wireless/hostap/hostap_ap.h
@@ -74,7 +74,7 @@ struct sta_info {
u32 tx_since_last_failure;
u32 tx_consecutive_exc;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
int ap; /* whether this station is an AP */
@@ -209,7 +209,7 @@ struct ap_data {
/* WEP operations for generating challenges to be used with shared key
* authentication */
- struct ieee80211_crypto_ops *crypt;
+ struct lib80211_crypto_ops *crypt;
void *crypt_priv;
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
};
@@ -229,7 +229,7 @@ typedef enum {
struct hostap_tx_data {
struct sk_buff *skb;
int host_encrypt;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
void *sta_ptr;
};
ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
@@ -244,7 +244,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
struct hostap_80211_rx_status *rx_stats,
int wds);
int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
- struct ieee80211_crypt_data **crypt,
+ struct lib80211_crypt_data **crypt,
void **sta_ptr);
int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index b470c743c2d..90b64b09200 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -6,19 +6,6 @@
/* IEEE 802.11 defines */
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#define WLAN_EID_TIM 5
-#define WLAN_EID_IBSS_PARAMS 6
-#define WLAN_EID_CHALLENGE 16
-#define WLAN_EID_RSN 48
-#define WLAN_EID_GENERIC 221
-
-
/* HFA384X Configuration RIDs */
#define HFA384X_RID_CNFPORTTYPE 0xFC00
#define HFA384X_RID_CNFOWNMACADDR 0xFC01
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 3153fe9d7ce..0f27059bbe8 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -47,7 +47,7 @@
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
#include <asm/irq.h>
#include "hostap_80211.h"
@@ -2335,10 +2335,6 @@ static void prism2_txexc(local_info_t *local)
int show_dump, res;
char *payload = NULL;
struct hfa384x_tx_frame txdesc;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
- DECLARE_MAC_BUF(mac4);
show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
local->stats.tx_errors++;
@@ -2404,9 +2400,9 @@ static void prism2_txexc(local_info_t *local)
WLAN_FC_GET_STYPE(fc) >> 4,
fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
- PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n",
- print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2),
- print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4));
+ PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n",
+ txdesc.addr1, txdesc.addr2,
+ txdesc.addr3, txdesc.addr4);
}
@@ -2792,45 +2788,6 @@ static void prism2_check_sta_fw_version(local_info_t *local)
}
-static void prism2_crypt_deinit_entries(local_info_t *local, int force)
-{
- struct list_head *ptr, *n;
- struct ieee80211_crypt_data *entry;
-
- for (ptr = local->crypt_deinit_list.next, n = ptr->next;
- ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) {
- entry = list_entry(ptr, struct ieee80211_crypt_data, list);
-
- if (atomic_read(&entry->refcnt) != 0 && !force)
- continue;
-
- list_del(ptr);
-
- if (entry->ops)
- entry->ops->deinit(entry->priv);
- kfree(entry);
- }
-}
-
-
-static void prism2_crypt_deinit_handler(unsigned long data)
-{
- local_info_t *local = (local_info_t *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_crypt_deinit_entries(local, 0);
- if (!list_empty(&local->crypt_deinit_list)) {
- printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
- "deletion list\n", local->dev->name);
- local->crypt_deinit_timer.expires = jiffies + HZ;
- add_timer(&local->crypt_deinit_timer);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-
-}
-
-
static void hostap_passive_scan(unsigned long data)
{
local_info_t *local = (local_info_t *) data;
@@ -3254,10 +3211,8 @@ while (0)
INIT_LIST_HEAD(&local->cmd_queue);
init_waitqueue_head(&local->hostscan_wq);
- INIT_LIST_HEAD(&local->crypt_deinit_list);
- init_timer(&local->crypt_deinit_timer);
- local->crypt_deinit_timer.data = (unsigned long) local;
- local->crypt_deinit_timer.function = prism2_crypt_deinit_handler;
+
+ lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock);
init_timer(&local->passive_scan_timer);
local->passive_scan_timer.data = (unsigned long) local;
@@ -3358,9 +3313,7 @@ static void prism2_free_local_data(struct net_device *dev)
flush_scheduled_work();
- if (timer_pending(&local->crypt_deinit_timer))
- del_timer(&local->crypt_deinit_timer);
- prism2_crypt_deinit_entries(local, 1);
+ lib80211_crypt_info_free(&local->crypt_info);
if (timer_pending(&local->passive_scan_timer))
del_timer(&local->passive_scan_timer);
@@ -3377,16 +3330,6 @@ static void prism2_free_local_data(struct net_device *dev)
if (local->dev_enabled)
prism2_callback(local, PRISM2_CALLBACK_DISABLE);
- for (i = 0; i < WEP_KEYS; i++) {
- struct ieee80211_crypt_data *crypt = local->crypt[i];
- if (crypt) {
- if (crypt->ops)
- crypt->ops->deinit(crypt->priv);
- kfree(crypt);
- local->crypt[i] = NULL;
- }
- }
-
if (local->ap != NULL)
hostap_free_data(local->ap);
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index 7cd3fb79230..99b4cf41edf 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -166,7 +166,6 @@ static void prism2_host_roaming(local_info_t *local)
struct hfa384x_hostscan_result *selected, *entry;
int i;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
if (local->last_join_time &&
time_before(jiffies, local->last_join_time + 10 * HZ)) {
@@ -199,9 +198,8 @@ static void prism2_host_roaming(local_info_t *local)
local->preferred_ap[2] || local->preferred_ap[3] ||
local->preferred_ap[4] || local->preferred_ap[5]) {
/* Try to find preferred AP */
- PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID "
- "%s\n",
- dev->name, print_mac(mac, local->preferred_ap));
+ PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
+ dev->name, local->preferred_ap);
for (i = 0; i < local->last_scan_results_count; i++) {
entry = &local->last_scan_results[i];
if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
@@ -218,9 +216,9 @@ static void prism2_host_roaming(local_info_t *local)
req.channel = selected->chid;
spin_unlock_irqrestore(&local->lock, flags);
- PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s"
+ PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
" channel=%d\n",
- dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel));
+ dev->name, req.bssid, le16_to_cpu(req.channel));
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
@@ -413,7 +411,6 @@ static void handle_info_queue_linkstatus(local_info_t *local)
int val = local->prev_link_status;
int connected;
union iwreq_data wrqu;
- DECLARE_MAC_BUF(mac);
connected =
val == HFA384X_LINKSTATUS_CONNECTED ||
@@ -425,10 +422,9 @@ static void handle_info_queue_linkstatus(local_info_t *local)
printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
"LinkStatus event\n", local->dev->name);
} else {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID="
- "%s\n",
+ PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
local->dev->name,
- print_mac(mac, (unsigned char *) local->bssid));
+ (unsigned char *) local->bssid);
if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
hostap_add_sta(local->ap, local->bssid);
}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 3f8b1d7036e..c40fdf4c79d 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -2,7 +2,7 @@
#include <linux/types.h>
#include <linux/ethtool.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
#include "hostap_wlan.h"
#include "hostap.h"
@@ -116,32 +116,6 @@ static int prism2_get_name(struct net_device *dev,
}
-static void prism2_crypt_delayed_deinit(local_info_t *local,
- struct ieee80211_crypt_data **crypt)
-{
- struct ieee80211_crypt_data *tmp;
- unsigned long flags;
-
- tmp = *crypt;
- *crypt = NULL;
-
- if (tmp == NULL)
- return;
-
- /* must not run ops->deinit() while there may be pending encrypt or
- * decrypt operations. Use a list of delayed deinits to avoid needing
- * locking. */
-
- spin_lock_irqsave(&local->lock, flags);
- list_add(&tmp->list, &local->crypt_deinit_list);
- if (!timer_pending(&local->crypt_deinit_timer)) {
- local->crypt_deinit_timer.expires = jiffies + HZ;
- add_timer(&local->crypt_deinit_timer);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-
static int prism2_ioctl_siwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *keybuf)
@@ -149,47 +123,47 @@ static int prism2_ioctl_siwencode(struct net_device *dev,
struct hostap_interface *iface;
local_info_t *local;
int i;
- struct ieee80211_crypt_data **crypt;
+ struct lib80211_crypt_data **crypt;
iface = netdev_priv(dev);
local = iface->local;
i = erq->flags & IW_ENCODE_INDEX;
if (i < 1 || i > 4)
- i = local->tx_keyidx;
+ i = local->crypt_info.tx_keyidx;
else
i--;
if (i < 0 || i >= WEP_KEYS)
return -EINVAL;
- crypt = &local->crypt[i];
+ crypt = &local->crypt_info.crypt[i];
if (erq->flags & IW_ENCODE_DISABLED) {
if (*crypt)
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
goto done;
}
if (*crypt != NULL && (*crypt)->ops != NULL &&
strcmp((*crypt)->ops->name, "WEP") != 0) {
/* changing to use WEP; deinit previously used algorithm */
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
}
if (*crypt == NULL) {
- struct ieee80211_crypt_data *new_crypt;
+ struct lib80211_crypt_data *new_crypt;
/* take WEP into use */
- new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+ new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL)
return -ENOMEM;
- new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ new_crypt->ops = lib80211_get_crypto_ops("WEP");
if (!new_crypt->ops) {
- request_module("ieee80211_crypt_wep");
- new_crypt->ops = ieee80211_get_crypto_ops("WEP");
+ request_module("lib80211_crypt_wep");
+ new_crypt->ops = lib80211_get_crypto_ops("WEP");
}
- if (new_crypt->ops)
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(i);
if (!new_crypt->ops || !new_crypt->priv) {
kfree(new_crypt);
@@ -210,16 +184,16 @@ static int prism2_ioctl_siwencode(struct net_device *dev,
memset(keybuf + erq->length, 0, len - erq->length);
(*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt[j]) {
+ if (j != i && local->crypt_info.crypt[j]) {
first = 0;
break;
}
}
if (first)
- local->tx_keyidx = i;
+ local->crypt_info.tx_keyidx = i;
} else {
/* No key data - just set the default TX key index */
- local->tx_keyidx = i;
+ local->crypt_info.tx_keyidx = i;
}
done:
@@ -252,20 +226,20 @@ static int prism2_ioctl_giwencode(struct net_device *dev,
local_info_t *local;
int i, len;
u16 val;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
iface = netdev_priv(dev);
local = iface->local;
i = erq->flags & IW_ENCODE_INDEX;
if (i < 1 || i > 4)
- i = local->tx_keyidx;
+ i = local->crypt_info.tx_keyidx;
else
i--;
if (i < 0 || i >= WEP_KEYS)
return -EINVAL;
- crypt = local->crypt[i];
+ crypt = local->crypt_info.crypt[i];
erq->flags = i + 1;
if (crypt == NULL || crypt->ops == NULL) {
@@ -664,7 +638,6 @@ static int hostap_join_ap(struct net_device *dev)
unsigned long flags;
int i;
struct hfa384x_hostscan_result *entry;
- DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -686,14 +659,13 @@ static int hostap_join_ap(struct net_device *dev)
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest %s"
- " failed\n",
- dev->name, print_mac(mac, local->preferred_ap));
+ printk(KERN_DEBUG "%s: JoinRequest %pM failed\n",
+ dev->name, local->preferred_ap);
return -1;
}
- printk(KERN_DEBUG "%s: Trying to join BSSID %s\n",
- dev->name, print_mac(mac, local->preferred_ap));
+ printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n",
+ dev->name, local->preferred_ap);
return 0;
}
@@ -3229,8 +3201,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
local_info_t *local = iface->local;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
int i, ret = 0;
- struct ieee80211_crypto_ops *ops;
- struct ieee80211_crypt_data **crypt;
+ struct lib80211_crypto_ops *ops;
+ struct lib80211_crypt_data **crypt;
void *sta_ptr;
u8 *addr;
const char *alg, *module;
@@ -3239,7 +3211,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
if (i > WEP_KEYS)
return -EINVAL;
if (i < 1 || i > WEP_KEYS)
- i = local->tx_keyidx;
+ i = local->crypt_info.tx_keyidx;
else
i--;
if (i < 0 || i >= WEP_KEYS)
@@ -3249,7 +3221,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
sta_ptr = NULL;
- crypt = &local->crypt[i];
+ crypt = &local->crypt_info.crypt[i];
} else {
if (i != 0)
return -EINVAL;
@@ -3262,7 +3234,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
* is emulated by using default key idx 0.
*/
i = 0;
- crypt = &local->crypt[i];
+ crypt = &local->crypt_info.crypt[i];
} else
return -EINVAL;
}
@@ -3271,22 +3243,22 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
if ((erq->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) {
if (*crypt)
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
goto done;
}
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
alg = "WEP";
- module = "ieee80211_crypt_wep";
+ module = "lib80211_crypt_wep";
break;
case IW_ENCODE_ALG_TKIP:
alg = "TKIP";
- module = "ieee80211_crypt_tkip";
+ module = "lib80211_crypt_tkip";
break;
case IW_ENCODE_ALG_CCMP:
alg = "CCMP";
- module = "ieee80211_crypt_ccmp";
+ module = "lib80211_crypt_ccmp";
break;
default:
printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
@@ -3295,10 +3267,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
goto done;
}
- ops = ieee80211_get_crypto_ops(alg);
+ ops = lib80211_get_crypto_ops(alg);
if (ops == NULL) {
request_module(module);
- ops = ieee80211_get_crypto_ops(alg);
+ ops = lib80211_get_crypto_ops(alg);
}
if (ops == NULL) {
printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
@@ -3317,18 +3289,19 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
}
if (*crypt == NULL || (*crypt)->ops != ops) {
- struct ieee80211_crypt_data *new_crypt;
+ struct lib80211_crypt_data *new_crypt;
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+ new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL) {
ret = -ENOMEM;
goto done;
}
new_crypt->ops = ops;
- new_crypt->priv = new_crypt->ops->init(i);
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv = new_crypt->ops->init(i);
if (new_crypt->priv == NULL) {
kfree(new_crypt);
ret = -EINVAL;
@@ -3356,20 +3329,20 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
if (!sta_ptr)
- local->tx_keyidx = i;
+ local->crypt_info.tx_keyidx = i;
}
if (sta_ptr == NULL && ext->key_len > 0) {
int first = 1, j;
for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt[j]) {
+ if (j != i && local->crypt_info.crypt[j]) {
first = 0;
break;
}
}
if (first)
- local->tx_keyidx = i;
+ local->crypt_info.tx_keyidx = i;
}
done:
@@ -3401,7 +3374,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
{
struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
- struct ieee80211_crypt_data **crypt;
+ struct lib80211_crypt_data **crypt;
void *sta_ptr;
int max_key_len, i;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
@@ -3413,7 +3386,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
i = erq->flags & IW_ENCODE_INDEX;
if (i < 1 || i > WEP_KEYS)
- i = local->tx_keyidx;
+ i = local->crypt_info.tx_keyidx;
else
i--;
@@ -3421,7 +3394,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
sta_ptr = NULL;
- crypt = &local->crypt[i];
+ crypt = &local->crypt_info.crypt[i];
} else {
i = 0;
sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
@@ -3470,8 +3443,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
int param_len)
{
int ret = 0;
- struct ieee80211_crypto_ops *ops;
- struct ieee80211_crypt_data **crypt;
+ struct lib80211_crypto_ops *ops;
+ struct lib80211_crypt_data **crypt;
void *sta_ptr;
param->u.crypt.err = 0;
@@ -3488,7 +3461,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
if (param->u.crypt.idx >= WEP_KEYS)
return -EINVAL;
sta_ptr = NULL;
- crypt = &local->crypt[param->u.crypt.idx];
+ crypt = &local->crypt_info.crypt[param->u.crypt.idx];
} else {
if (param->u.crypt.idx)
return -EINVAL;
@@ -3505,20 +3478,20 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
if (strcmp(param->u.crypt.alg, "none") == 0) {
if (crypt)
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
goto done;
}
- ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ ops = lib80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
- request_module("ieee80211_crypt_wep");
- ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ request_module("lib80211_crypt_wep");
+ ops = lib80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
- request_module("ieee80211_crypt_tkip");
- ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ request_module("lib80211_crypt_tkip");
+ ops = lib80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
- request_module("ieee80211_crypt_ccmp");
- ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
+ request_module("lib80211_crypt_ccmp");
+ ops = lib80211_get_crypto_ops(param->u.crypt.alg);
}
if (ops == NULL) {
printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
@@ -3533,11 +3506,11 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
local->host_decrypt = local->host_encrypt = 1;
if (*crypt == NULL || (*crypt)->ops != ops) {
- struct ieee80211_crypt_data *new_crypt;
+ struct lib80211_crypt_data *new_crypt;
- prism2_crypt_delayed_deinit(local, crypt);
+ lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
+ new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL) {
ret = -ENOMEM;
@@ -3570,7 +3543,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local,
if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
if (!sta_ptr)
- local->tx_keyidx = param->u.crypt.idx;
+ local->crypt_info.tx_keyidx = param->u.crypt.idx;
else if (param->u.crypt.idx) {
printk(KERN_DEBUG "%s: TX key idx setting failed\n",
local->dev->name);
@@ -3606,7 +3579,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local,
struct prism2_hostapd_param *param,
int param_len)
{
- struct ieee80211_crypt_data **crypt;
+ struct lib80211_crypt_data **crypt;
void *sta_ptr;
int max_key_len;
@@ -3622,8 +3595,8 @@ static int prism2_ioctl_get_encryption(local_info_t *local,
param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
sta_ptr = NULL;
if (param->u.crypt.idx >= WEP_KEYS)
- param->u.crypt.idx = local->tx_keyidx;
- crypt = &local->crypt[param->u.crypt.idx];
+ param->u.crypt.idx = local->crypt_info.tx_keyidx;
+ crypt = &local->crypt_info.crypt[param->u.crypt.idx];
} else {
param->u.crypt.idx = 0;
sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
@@ -3701,10 +3674,8 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
struct prism2_hostapd_param *param,
int param_len)
{
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%ssta: associated as client with AP "
- "%s\n",
- local->dev->name, print_mac(mac, param->sta_addr));
+ printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n",
+ local->dev->name, param->sta_addr);
memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
return 0;
}
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 756ab56c1f4..02a312ca860 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -27,7 +27,7 @@
#include <net/net_namespace.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
#include <asm/uaccess.h>
#include "hostap_wlan.h"
@@ -343,10 +343,11 @@ int hostap_set_encryption(local_info_t *local)
char keybuf[WEP_KEY_LEN + 1];
enum { NONE, WEP, OTHER } encrypt_type;
- idx = local->tx_keyidx;
- if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL)
+ idx = local->crypt_info.tx_keyidx;
+ if (local->crypt_info.crypt[idx] == NULL ||
+ local->crypt_info.crypt[idx]->ops == NULL)
encrypt_type = NONE;
- else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0)
+ else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0)
encrypt_type = WEP;
else
encrypt_type = OTHER;
@@ -394,17 +395,17 @@ int hostap_set_encryption(local_info_t *local)
/* 104-bit support seems to require that all the keys are set to the
* same keylen */
keylen = 6; /* first 5 octets */
- len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf),
- NULL, local->crypt[idx]->priv);
+ len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL,
+ local->crypt_info.crypt[idx]->priv);
if (idx >= 0 && idx < WEP_KEYS && len > 5)
keylen = WEP_KEY_LEN + 1; /* first 13 octets */
for (i = 0; i < WEP_KEYS; i++) {
memset(keybuf, 0, sizeof(keybuf));
- if (local->crypt[i]) {
- (void) local->crypt[i]->ops->get_key(
+ if (local->crypt_info.crypt[i]) {
+ (void) local->crypt_info.crypt[i]->ops->get_key(
keybuf, sizeof(keybuf),
- NULL, local->crypt[i]->priv);
+ NULL, local->crypt_info.crypt[i]->priv);
}
if (local->func->set_rid(local->dev,
HFA384X_RID_CNFDEFAULTKEY0 + i,
@@ -530,10 +531,6 @@ int hostap_set_auth_algs(local_info_t *local)
void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
{
u16 status, fc;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
- DECLARE_MAC_BUF(mac4);
status = __le16_to_cpu(rx->status);
@@ -552,12 +549,11 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
- print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2),
- print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4));
+ printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
+ rx->addr1, rx->addr2, rx->addr3, rx->addr4);
- printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
- print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr),
+ printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
+ rx->dst_addr, rx->src_addr,
__be16_to_cpu(rx->len));
}
@@ -565,10 +561,6 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
{
u16 fc;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
- DECLARE_MAC_BUF(mac4);
printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
"tx_control=0x%04x; jiffies=%ld\n",
@@ -584,12 +576,11 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
- print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2),
- print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4));
+ printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
+ tx->addr1, tx->addr2, tx->addr3, tx->addr4);
- printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
- print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr),
+ printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
+ tx->dst_addr, tx->src_addr,
__be16_to_cpu(tx->len));
}
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 3a874fc621d..8fdd41f4b4f 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -312,7 +312,7 @@ static int prism2_pci_probe(struct pci_dev *pdev,
goto err_out_disable;
}
- mem = ioremap(phymem, pci_resource_len(pdev, 0));
+ mem = pci_ioremap_bar(pdev, 0);
if (mem == NULL) {
printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
goto fail;
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index b03536008ad..005ff25a405 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -2,7 +2,7 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <net/ieee80211_crypt.h>
+#include <net/lib80211.h>
#include "hostap_wlan.h"
#include "hostap.h"
@@ -36,9 +36,10 @@ static int prism2_debug_proc_read(char *page, char **start, off_t off,
p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled);
p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt[i] && local->crypt[i]->ops) {
- p += sprintf(p, "crypt[%d]=%s\n",
- i, local->crypt[i]->ops->name);
+ if (local->crypt_info.crypt[i] &&
+ local->crypt_info.crypt[i]->ops) {
+ p += sprintf(p, "crypt[%d]=%s\n", i,
+ local->crypt_info.crypt[i]->ops->name);
}
}
p += sprintf(p, "pri_only=%d\n", local->pri_only);
@@ -106,7 +107,6 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
local_info_t *local = (local_info_t *) data;
struct list_head *ptr;
struct hostap_interface *iface;
- DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -118,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
iface = list_entry(ptr, struct hostap_interface, list);
if (iface->type != HOSTAP_INTERFACE_WDS)
continue;
- p += sprintf(p, "%s\t%s\n",
+ p += sprintf(p, "%s\t%pM\n",
iface->dev->name,
- print_mac(mac, iface->u.wds.remote_addr));
+ iface->u.wds.remote_addr);
if ((p - page) > PROC_LIMIT) {
printk(KERN_DEBUG "%s: wds proc did not fit\n",
local->dev->name);
@@ -148,7 +148,6 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
struct list_head *ptr;
struct hostap_bss_info *bss;
int i;
- DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -160,8 +159,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
spin_lock_bh(&local->lock);
list_for_each(ptr, &local->bss_list) {
bss = list_entry(ptr, struct hostap_bss_info, list);
- p += sprintf(p, "%s\t%lu\t%u\t0x%x\t",
- print_mac(mac, bss->bssid), bss->last_update,
+ p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t",
+ bss->bssid, bss->last_update,
bss->count, bss->capab_info);
for (i = 0; i < bss->ssid_len; i++) {
p += sprintf(p, "%c",
@@ -208,12 +207,13 @@ static int prism2_crypt_proc_read(char *page, char **start, off_t off,
return 0;
}
- p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx);
+ p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt[i] && local->crypt[i]->ops &&
- local->crypt[i]->ops->print_stats) {
- p = local->crypt[i]->ops->print_stats(
- p, local->crypt[i]->priv);
+ if (local->crypt_info.crypt[i] &&
+ local->crypt_info.crypt[i]->ops &&
+ local->crypt_info.crypt[i]->ops->print_stats) {
+ p = local->crypt_info.crypt[i]->ops->print_stats(
+ p, local->crypt_info.crypt[i]->priv);
}
}
@@ -314,7 +314,6 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
int entry, i, len, total = 0;
struct hfa384x_hostscan_result *scanres;
u8 *pos;
- DECLARE_MAC_BUF(mac);
p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
"SSID\n");
@@ -332,14 +331,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
if ((p - page) > (PAGE_SIZE - 200))
break;
- p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ",
+ p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ",
le16_to_cpu(scanres->chid),
(s16) le16_to_cpu(scanres->anl),
(s16) le16_to_cpu(scanres->sl),
le16_to_cpu(scanres->beacon_interval),
le16_to_cpu(scanres->capability),
le16_to_cpu(scanres->rate),
- print_mac(mac, scanres->bssid),
+ scanres->bssid,
le16_to_cpu(scanres->atim));
pos = scanres->sup_rates;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index a68f97c3935..4d8d51a353c 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -6,6 +6,7 @@
#include <linux/mutex.h>
#include <net/iw_handler.h>
#include <net/ieee80211_radiotap.h>
+#include <net/lib80211.h>
#include "hostap_config.h"
#include "hostap_common.h"
@@ -763,10 +764,7 @@ struct local_info {
#define WEP_KEYS 4
#define WEP_KEY_LEN 13
- struct ieee80211_crypt_data *crypt[WEP_KEYS];
- int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
- struct timer_list crypt_deinit_timer;
- struct list_head crypt_deinit_list;
+ struct lib80211_crypt_info crypt_info;
int open_wep; /* allow unencrypted frames */
int host_encrypt;
@@ -822,7 +820,7 @@ struct local_info {
int last_scan_results_count;
enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
struct work_struct info_queue;
- long pending_info; /* bit field of pending info_queue items */
+ unsigned long pending_info; /* bit field of pending info_queue items */
#define PRISM2_INFO_PENDING_LINKSTATUS 0
#define PRISM2_INFO_PENDING_SCANRESULTS 1
int prev_link_status; /* previous received LinkStatus info */
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
new file mode 100644
index 00000000000..3d5cc4463d4
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -0,0 +1,191 @@
+#
+# Intel Centrino wireless drivers
+#
+
+config IPW2100
+ tristate "Intel PRO/Wireless 2100 Network Connection"
+ depends on PCI && WLAN_80211
+ select WIRELESS_EXT
+ select FW_LOADER
+ select LIB80211
+ select LIBIPW
+ ---help---
+ A driver for the Intel PRO/Wireless 2100 Network
+ Connection 802.11b wireless network adapter.
+
+ See <file:Documentation/networking/README.ipw2100> for information on
+ the capabilities currently enabled in this driver and for tips
+ for debugging issues and problems.
+
+ In order to use this driver, you will need a firmware image for it.
+ You can obtain the firmware from
+ <http://ipw2100.sf.net/>. Once you have the firmware image, you
+ will need to place it in /lib/firmware.
+
+ You will also very likely need the Wireless Tools in order to
+ configure your card:
+
+ <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+ It is recommended that you compile this driver as a module (M)
+ rather than built-in (Y). This driver requires firmware at device
+ initialization time, and when built-in this typically happens
+ before the filesystem is accessible (hence firmware will be
+ unavailable and initialization will fail). If you do choose to build
+ this driver into your kernel image, you can avoid this problem by
+ including the firmware and a firmware loader in an initramfs.
+
+config IPW2100_MONITOR
+ bool "Enable promiscuous mode"
+ depends on IPW2100
+ ---help---
+ Enables promiscuous/monitor mode support for the ipw2100 driver.
+ With this feature compiled into the driver, you can switch to
+ promiscuous mode via the Wireless Tool's Monitor mode. While in this
+ mode, no packets can be sent.
+
+config IPW2100_DEBUG
+ bool "Enable full debugging output in IPW2100 module."
+ depends on IPW2100
+ ---help---
+ This option will enable debug tracing output for the IPW2100.
+
+ This will result in the kernel module being ~60k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/bus/pci/drivers/ipw2100/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ If you are not trying to debug or develop the IPW2100 driver, you
+ most likely want to say N here.
+
+config IPW2200
+ tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
+ depends on PCI && WLAN_80211
+ select WIRELESS_EXT
+ select FW_LOADER
+ select LIB80211
+ select LIBIPW
+ ---help---
+ A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
+ Connection adapters.
+
+ See <file:Documentation/networking/README.ipw2200> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging issues and problems.
+
+ In order to use this driver, you will need a firmware image for it.
+ You can obtain the firmware from
+ <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
+ for information on where to install the firmware images.
+
+ You will also very likely need the Wireless Tools in order to
+ configure your card:
+
+ <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+
+ It is recommended that you compile this driver as a module (M)
+ rather than built-in (Y). This driver requires firmware at device
+ initialization time, and when built-in this typically happens
+ before the filesystem is accessible (hence firmware will be
+ unavailable and initialization will fail). If you do choose to build
+ this driver into your kernel image, you can avoid this problem by
+ including the firmware and a firmware loader in an initramfs.
+
+config IPW2200_MONITOR
+ bool "Enable promiscuous mode"
+ depends on IPW2200
+ ---help---
+ Enables promiscuous/monitor mode support for the ipw2200 driver.
+ With this feature compiled into the driver, you can switch to
+ promiscuous mode via the Wireless Tool's Monitor mode. While in this
+ mode, no packets can be sent.
+
+config IPW2200_RADIOTAP
+ bool "Enable radiotap format 802.11 raw packet support"
+ depends on IPW2200_MONITOR
+
+config IPW2200_PROMISCUOUS
+ bool "Enable creation of a RF radiotap promiscuous interface"
+ depends on IPW2200_MONITOR
+ select IPW2200_RADIOTAP
+ ---help---
+ Enables the creation of a second interface prefixed 'rtap'.
+ This second interface will provide every received in radiotap
+ format.
+
+ This is useful for performing wireless network analysis while
+ maintaining an active association.
+
+ Example usage:
+
+ % modprobe ipw2200 rtap_iface=1
+ % ifconfig rtap0 up
+ % tethereal -i rtap0
+
+ If you do not specify 'rtap_iface=1' as a module parameter then
+ the rtap interface will not be created and you will need to turn
+ it on via sysfs:
+
+ % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
+
+config IPW2200_QOS
+ bool "Enable QoS support"
+ depends on IPW2200 && EXPERIMENTAL
+
+config IPW2200_DEBUG
+ bool "Enable full debugging output in IPW2200 module."
+ depends on IPW2200
+ ---help---
+ This option will enable low level debug tracing output for IPW2200.
+
+ Note, normal debug code is already compiled in. This low level
+ debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
+ will result in the kernel module being ~70 larger. Most users
+ will typically not need this high verbosity debug information.
+
+ If you are not sure, say N here.
+
+config LIBIPW
+ tristate
+ select WIRELESS_EXT
+ select CRYPTO
+ select CRYPTO_ARC4
+ select CRYPTO_ECB
+ select CRYPTO_AES
+ select CRYPTO_MICHAEL_MIC
+ select CRYPTO_ECB
+ select CRC32
+ select LIB80211
+ select LIB80211_CRYPT_WEP
+ select LIB80211_CRYPT_TKIP
+ select LIB80211_CRYPT_CCMP
+ ---help---
+ This option enables the hardware independent IEEE 802.11
+ networking stack. This component is deprecated in favor of the
+ mac80211 component.
+
+config LIBIPW_DEBUG
+ bool "Full debugging output for the LIBIPW component"
+ depends on LIBIPW
+ ---help---
+ This option will enable debug tracing output for the
+ libipw component.
+
+ This will result in the kernel module being ~70k larger. You
+ can control which debug output is sent to the kernel log by
+ setting the value in
+
+ /proc/net/ieee80211/debug_level
+
+ For example:
+
+ % echo 0x00000FFO > /proc/net/ieee80211/debug_level
+
+ For a list of values you can assign to debug_level, you
+ can look at the bit mask values in <net/ieee80211.h>
+
+ If you are not trying to debug or develop the libipw
+ component, you most likely want to say N here.
diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile
new file mode 100644
index 00000000000..aecd2cff462
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Intel Centrino wireless drivers
+#
+
+obj-$(CONFIG_IPW2100) += ipw2100.o
+obj-$(CONFIG_IPW2200) += ipw2200.o
+
+obj-$(CONFIG_LIBIPW) += libipw.o
+libipw-objs := \
+ libipw_module.o \
+ libipw_tx.o \
+ libipw_rx.o \
+ libipw_wx.o \
+ libipw_geo.o
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index bca74811bc7..1667065b86a 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -163,6 +163,8 @@ that only one external action is invoked at a time.
#include <linux/ctype.h>
#include <linux/pm_qos_params.h>
+#include <net/lib80211.h>
+
#include "ipw2100.h"
#define IPW2100_VERSION "git-1.2.2"
@@ -185,7 +187,7 @@ MODULE_LICENSE("GPL");
static int debug = 0;
static int mode = 0;
static int channel = 0;
-static int associate = 1;
+static int associate = 0;
static int disable = 0;
#ifdef CONFIG_PM
static struct ipw2100_fw ipw2100_firmware;
@@ -201,7 +203,7 @@ module_param(disable, int, 0444);
MODULE_PARM_DESC(debug, "debug level");
MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
MODULE_PARM_DESC(channel, "channel");
-MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
static u32 ipw2100_debug_level = IPW_DL_NONE;
@@ -1914,7 +1916,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
u32 chan;
char *txratename;
u8 bssid[ETH_ALEN];
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
/*
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1975,10 +1977,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
break;
}
- IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
- "%s)\n",
- priv->net_dev->name, escape_essid(essid, essid_len),
- txratename, chan, print_mac(mac, bssid));
+ IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
+ priv->net_dev->name, print_ssid(ssid, essid, essid_len),
+ txratename, chan, bssid);
/* now we copy read ssid into dev */
if (!(priv->config & CFG_STATIC_ESSID)) {
@@ -2004,8 +2005,9 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
.host_command_length = ssid_len
};
int err;
+ DECLARE_SSID_BUF(ssid);
- IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
+ IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
if (ssid_len)
memcpy(cmd.host_command_parameters, essid, ssid_len);
@@ -2046,12 +2048,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
{
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%s' %s \n",
- escape_essid(priv->essid, priv->essid_len),
- print_mac(mac, priv->bssid));
+ "disassociated: '%s' %pM \n",
+ print_ssid(ssid, priv->essid, priv->essid_len),
+ priv->bssid);
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
@@ -4008,7 +4010,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr,
else
len += sprintf(buf + len, "not connected\n");
- DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p");
+ DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
DUMP_VAR(status, "08lx");
DUMP_VAR(config, "08lx");
DUMP_VAR(capability, "08lx");
@@ -4058,7 +4060,6 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
char *out = buf;
int length;
int ret;
- DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_RF_KILL_MASK)
return 0;
@@ -4086,7 +4087,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
__LINE__);
out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid));
+ out += sprintf(out, "BSSID: %pM\n", bssid);
out += sprintf(out, "Channel: %d\n", chan);
return out - buf;
@@ -4662,7 +4663,6 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
{
u32 length = ETH_ALEN;
u8 addr[ETH_ALEN];
- DECLARE_MAC_BUF(mac);
int err;
@@ -4673,8 +4673,7 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
}
memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
- IPW_DEBUG_INFO("card MAC is %s\n",
- print_mac(mac, priv->net_dev->dev_addr));
+ IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
return 0;
}
@@ -5053,10 +5052,8 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
int err;
#ifdef CONFIG_IPW2100_DEBUG
- DECLARE_MAC_BUF(mac);
if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
- print_mac(mac, bssid));
+ IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
else
IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
#endif
@@ -5271,21 +5268,21 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
return 0;
}
-void ipw2100_queues_initialize(struct ipw2100_priv *priv)
+static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
{
ipw2100_tx_initialize(priv);
ipw2100_rx_initialize(priv);
ipw2100_msg_initialize(priv);
}
-void ipw2100_queues_free(struct ipw2100_priv *priv)
+static void ipw2100_queues_free(struct ipw2100_priv *priv)
{
ipw2100_tx_free(priv);
ipw2100_rx_free(priv);
ipw2100_msg_free(priv);
}
-int ipw2100_queues_allocate(struct ipw2100_priv *priv)
+static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
{
if (ipw2100_tx_allocate(priv) ||
ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
@@ -5517,7 +5514,7 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
}
}
- ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1);
+ ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
}
/* Always enable privacy so the Host can filter WEP packets if
@@ -6905,7 +6902,6 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
static const unsigned char off[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
- DECLARE_MAC_BUF(mac);
// sanity checks
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
@@ -6931,8 +6927,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
- IPW_DEBUG_WX("SET BSSID -> %s\n",
- print_mac(mac, wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
done:
mutex_unlock(&priv->action_mutex);
@@ -6948,7 +6943,6 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
- DECLARE_MAC_BUF(mac);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -6958,8 +6952,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
- print_mac(mac, wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
return 0;
}
@@ -6971,6 +6964,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
char *essid = ""; /* ANY */
int length = 0;
int err = 0;
+ DECLARE_SSID_BUF(ssid);
mutex_lock(&priv->action_mutex);
if (!(priv->status & STATUS_INITIALIZED)) {
@@ -7000,8 +6994,8 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
goto done;
}
- IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
- length);
+ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
+ print_ssid(ssid, essid, length), length);
priv->essid_len = length;
memcpy(priv->essid, essid, priv->essid_len);
@@ -7022,12 +7016,13 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
+ DECLARE_SSID_BUF(ssid);
/* If we are associated, trying to associate, or have a statically
* configured ESSID then return that; otherwise return ANY */
if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
IPW_DEBUG_WX("Getting essid: '%s'\n",
- escape_essid(priv->essid, priv->essid_len));
+ print_ssid(ssid, priv->essid, priv->essid_len));
memcpy(extra, priv->essid, priv->essid_len);
wrqu->essid.length = priv->essid_len;
wrqu->essid.flags = 1; /* active */
@@ -7625,7 +7620,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
unsigned long flags;
int ret = 0;
@@ -7640,7 +7635,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
break;
@@ -7717,7 +7712,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
int ret = 0;
@@ -7733,7 +7728,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
if (!crypt || !crypt->ops->get_flags) {
IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
"crypt not set!\n");
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index bbf1ddcafba..bbf1ddcafba 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index dcce3542d5a..625f2cf99fa 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -87,7 +87,7 @@ static int channel = 0;
static int mode = 0;
static u32 ipw_debug_level;
-static int associate = 1;
+static int associate;
static int auto_create = 1;
static int led = 0;
static int disable = 0;
@@ -2265,8 +2265,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
return -1;
}
- IPW_DEBUG_INFO("%s: Setting MAC to %s\n",
- priv->net_dev->name, print_mac(mac, mac));
+ IPW_DEBUG_INFO("%s: Setting MAC to %pM\n",
+ priv->net_dev->name, mac);
return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
}
@@ -3812,7 +3812,6 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
{
struct ipw_station_entry entry;
int i;
- DECLARE_MAC_BUF(mac);
for (i = 0; i < priv->num_stations; i++) {
if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
@@ -3829,7 +3828,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
if (i == MAX_STATIONS)
return IPW_INVALID_STATION;
- IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid));
+ IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid);
entry.reserved = 0;
entry.support_mode = 0;
@@ -3856,7 +3855,6 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
{
int err;
- DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_ASSOCIATING) {
IPW_DEBUG_ASSOC("Disassociating while associating.\n");
@@ -3869,9 +3867,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
return;
}
- IPW_DEBUG_ASSOC("Disassocation attempt from %s "
+ IPW_DEBUG_ASSOC("Disassocation attempt from %pM "
"on channel %d.\n",
- print_mac(mac, priv->assoc_request.bssid),
+ priv->assoc_request.bssid,
priv->assoc_request.channel);
priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
@@ -3897,6 +3895,7 @@ static int ipw_disassociate(void *data)
if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
return 0;
ipw_send_disassociate(data, 0);
+ netif_carrier_off(priv->net_dev);
return 1;
}
@@ -4346,7 +4345,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
return;
}
- if (priv->status & STATUS_SCANNING) {
+ if (priv->status & STATUS_SCANNING &&
+ missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
/* Stop scan to keep fw from getting
* stuck (only if we aren't roaming --
* otherwise we'll never scan more than 2 or 3
@@ -4397,7 +4397,7 @@ static void handle_scan_event(struct ipw_priv *priv)
static void ipw_rx_notification(struct ipw_priv *priv,
struct ipw_rx_notification *notif)
{
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
u16 size = le16_to_cpu(notif->size);
notif->size = le16_to_cpu(notif->size);
@@ -4411,11 +4411,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
case CMAS_ASSOCIATED:{
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "associated: '%s' %s"
- " \n",
- escape_essid(priv->essid,
- priv->essid_len),
- print_mac(mac, priv->bssid));
+ "associated: '%s' %pM \n",
+ print_ssid(ssid, priv->essid,
+ priv->essid_len),
+ priv->bssid);
switch (priv->ieee->iw_mode) {
case IW_MODE_INFRA:
@@ -4449,7 +4448,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
#ifdef CONFIG_IPW2200_QOS
#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
- le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl))
+ le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
if ((priv->status & STATUS_AUTH) &&
(IPW_GET_PACKET_STYPE(&notif->u.raw)
== IEEE80211_STYPE_ASSOC_RESP)) {
@@ -4492,13 +4491,14 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DL_STATE |
IPW_DL_ASSOC,
"deauthenticated: '%s' "
- "%s"
+ "%pM"
": (0x%04X) - %s \n",
- escape_essid(priv->
- essid,
- priv->
- essid_len),
- print_mac(mac, priv->bssid),
+ print_ssid(ssid,
+ priv->
+ essid,
+ priv->
+ essid_len),
+ priv->bssid,
le16_to_cpu(auth->status),
ipw_get_status_code
(le16_to_cpu
@@ -4515,11 +4515,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "authenticated: '%s' %s"
- "\n",
- escape_essid(priv->essid,
- priv->essid_len),
- print_mac(mac, priv->bssid));
+ "authenticated: '%s' %pM\n",
+ print_ssid(ssid, priv->essid,
+ priv->essid_len),
+ priv->bssid);
break;
}
@@ -4544,11 +4543,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "disassociated: '%s' %s"
- " \n",
- escape_essid(priv->essid,
- priv->essid_len),
- print_mac(mac, priv->bssid));
+ "disassociated: '%s' %pM \n",
+ print_ssid(ssid, priv->essid,
+ priv->essid_len),
+ priv->bssid);
priv->status &=
~(STATUS_DISASSOCIATING |
@@ -4583,10 +4581,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
switch (auth->state) {
case CMAS_AUTHENTICATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%s' %s \n",
- escape_essid(priv->essid,
- priv->essid_len),
- print_mac(mac, priv->bssid));
+ "authenticated: '%s' %pM \n",
+ print_ssid(ssid, priv->essid,
+ priv->essid_len),
+ priv->bssid);
priv->status |= STATUS_AUTH;
break;
@@ -4602,10 +4600,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "deauthenticated: '%s' %s\n",
- escape_essid(priv->essid,
- priv->essid_len),
- print_mac(mac, priv->bssid));
+ "deauthenticated: '%s' %pM\n",
+ print_ssid(ssid, priv->essid,
+ priv->essid_len),
+ priv->bssid);
priv->status &= ~(STATUS_ASSOCIATING |
STATUS_AUTH |
@@ -5429,27 +5427,17 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
int roaming)
{
struct ipw_supported_rates rates;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
+ DECLARE_SSID_BUF(ssid);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to "
"capability mismatch.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
- return 0;
- }
-
- /* If we do not have an ESSID for this AP, we can not associate with
- * it */
- if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
- "because of hidden ESSID.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
@@ -5459,11 +5447,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of non-network ESSID.\n",
- escape_essid(network->ssid,
- network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
} else {
@@ -5476,13 +5464,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
strncpy(escaped,
- escape_essid(network->ssid, network->ssid_len),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, print_mac(mac, network->bssid),
- escape_essid(priv->essid,
- priv->essid_len));
+ escaped, network->bssid,
+ print_ssid(ssid, priv->essid,
+ priv->essid_len));
return 0;
}
}
@@ -5493,24 +5482,25 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if (network->time_stamp[0] < match->network->time_stamp[0]) {
IPW_DEBUG_MERGE("Network '%s excluded because newer than "
"current network.\n",
- escape_essid(match->network->ssid,
- match->network->ssid_len));
+ print_ssid(ssid, match->network->ssid,
+ match->network->ssid_len));
return 0;
} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
IPW_DEBUG_MERGE("Network '%s excluded because newer than "
"current network.\n",
- escape_essid(match->network->ssid,
- match->network->ssid_len));
+ print_ssid(ssid, match->network->ssid,
+ match->network->ssid_len));
return 0;
}
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of age: %ums.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5518,10 +5508,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of channel mismatch: %d != %d.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
network->channel, priv->channel);
return 0;
}
@@ -5529,10 +5520,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of privacy mismatch: %s != %s.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
priv->
capability & CAP_PRIVACY_ON ? "on" : "off",
network->
@@ -5542,41 +5534,44 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
}
if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
- "because of the same BSSID match: %s"
- ".\n", escape_essid(network->ssid,
- network->ssid_len),
- print_mac(mac, network->bssid),
- print_mac(mac2, priv->bssid));
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
+ "because of the same BSSID match: %pM"
+ ".\n", print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
+ priv->bssid);
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of invalid frequency/mode "
"combination.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
"because of no compatible rates.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
@@ -5587,15 +5582,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Set up 'new' AP to this network */
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n",
+ print_ssid(ssid, network->ssid, network->ssid_len),
+ network->bssid);
return 1;
}
static void ipw_merge_adhoc_network(struct work_struct *work)
{
+ DECLARE_SSID_BUF(ssid);
struct ipw_priv *priv =
container_of(work, struct ipw_priv, merge_networks);
struct ieee80211_network *network = NULL;
@@ -5626,8 +5622,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work)
mutex_lock(&priv->mutex);
if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
IPW_DEBUG_MERGE("remove network %s\n",
- escape_essid(priv->essid,
- priv->essid_len));
+ print_ssid(ssid, priv->essid,
+ priv->essid_len));
ipw_remove_current_network(priv);
}
@@ -5643,7 +5639,7 @@ static int ipw_best_network(struct ipw_priv *priv,
struct ieee80211_network *network, int roaming)
{
struct ipw_supported_rates rates;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
@@ -5651,20 +5647,11 @@ static int ipw_best_network(struct ipw_priv *priv,
!(network->capability & WLAN_CAPABILITY_ESS)) ||
(priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to "
"capability mismatch.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
- return 0;
- }
-
- /* If we do not have an ESSID for this AP, we can not associate with
- * it */
- if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
- "because of hidden ESSID.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
@@ -5674,11 +5661,11 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of non-network ESSID.\n",
- escape_essid(network->ssid,
- network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
} else {
@@ -5690,13 +5677,14 @@ static int ipw_best_network(struct ipw_priv *priv,
min(network->ssid_len, priv->essid_len)))) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
strncpy(escaped,
- escape_essid(network->ssid, network->ssid_len),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, print_mac(mac, network->bssid),
- escape_essid(priv->essid,
- priv->essid_len));
+ escaped, network->bssid,
+ print_ssid(ssid, priv->essid,
+ priv->essid_len));
return 0;
}
}
@@ -5706,14 +5694,14 @@ static int ipw_best_network(struct ipw_priv *priv,
if (match->network && match->network->stats.rssi > network->stats.rssi) {
char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
strncpy(escaped,
- escape_essid(network->ssid, network->ssid_len),
+ print_ssid(ssid, network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because "
- "'%s (%s)' has a stronger signal.\n",
- escaped, print_mac(mac, network->bssid),
- escape_essid(match->network->ssid,
- match->network->ssid_len),
- print_mac(mac, match->network->bssid));
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
+ "'%s (%pM)' has a stronger signal.\n",
+ escaped, network->bssid,
+ print_ssid(ssid, match->network->ssid,
+ match->network->ssid_len),
+ match->network->bssid);
return 0;
}
@@ -5721,11 +5709,12 @@ static int ipw_best_network(struct ipw_priv *priv,
* last 3 seconds, do not try and associate again... */
if (network->last_associate &&
time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of storming (%ums since last "
"assoc attempt).\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
jiffies_to_msecs(jiffies -
network->last_associate));
return 0;
@@ -5734,10 +5723,11 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of age: %ums.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5745,10 +5735,11 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of channel mismatch: %d != %d.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
network->channel, priv->channel);
return 0;
}
@@ -5756,10 +5747,11 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of privacy mismatch: %s != %s.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid),
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
priv->capability & CAP_PRIVACY_ON ? "on" :
"off",
network->capability &
@@ -5769,48 +5761,53 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_BSSID) &&
memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
- "because of BSSID mismatch: %s.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid), print_mac(mac, priv->bssid));
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
+ "because of BSSID mismatch: %pM.\n",
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid, priv->bssid);
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of invalid frequency/mode "
"combination.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
/* Filter out invalid channel in current GEO */
if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of invalid channel in current GEO\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
"because of no compatible rates.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
return 0;
}
@@ -5822,9 +5819,9 @@ static int ipw_best_network(struct ipw_priv *priv,
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n",
- escape_essid(network->ssid, network->ssid_len),
- print_mac(mac, network->bssid));
+ IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n",
+ print_ssid(ssid, network->ssid, network->ssid_len),
+ network->bssid);
return 1;
}
@@ -6066,7 +6063,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work)
static void ipw_debug_config(struct ipw_priv *priv)
{
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
"[CFG 0x%08X]\n", priv->config);
if (priv->config & CFG_STATIC_CHANNEL)
@@ -6075,12 +6072,11 @@ static void ipw_debug_config(struct ipw_priv *priv)
IPW_DEBUG_INFO("Channel unlocked.\n");
if (priv->config & CFG_STATIC_ESSID)
IPW_DEBUG_INFO("ESSID locked to '%s'\n",
- escape_essid(priv->essid, priv->essid_len));
+ print_ssid(ssid, priv->essid, priv->essid_len));
else
IPW_DEBUG_INFO("ESSID unlocked.\n");
if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to %s\n",
- print_mac(mac, priv->bssid));
+ IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid);
else
IPW_DEBUG_INFO("BSSID unlocked.\n");
if (priv->capability & CAP_PRIVACY_ON)
@@ -6276,6 +6272,20 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
}
}
+static int ipw_passive_dwell_time(struct ipw_priv *priv)
+{
+ /* staying on passive channels longer than the DTIM interval during a
+ * scan, while associated, causes the firmware to cancel the scan
+ * without notification. Hence, don't stay on passive channels longer
+ * than the beacon interval.
+ */
+ if (priv->status & STATUS_ASSOCIATED
+ && priv->assoc_network->beacon_interval > 10)
+ return priv->assoc_network->beacon_interval - 10;
+ else
+ return 120;
+}
+
static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
{
struct ipw_scan_request_ext scan;
@@ -6319,16 +6329,16 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
if (type == IW_SCAN_TYPE_PASSIVE) {
- IPW_DEBUG_WX("use passive scanning\n");
- scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
+ IPW_DEBUG_WX("use passive scanning\n");
+ scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(120);
+ cpu_to_le16(ipw_passive_dwell_time(priv));
ipw_add_scan_channels(priv, &scan, scan_type);
goto send_request;
}
/* Use active scan by default. */
- if (priv->config & CFG_SPEED_SCAN)
+ if (priv->config & CFG_SPEED_SCAN)
scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
cpu_to_le16(30);
else
@@ -6338,7 +6348,8 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
cpu_to_le16(20);
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+ cpu_to_le16(ipw_passive_dwell_time(priv));
scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
#ifdef CONFIG_IPW2200_MONITOR
@@ -6606,7 +6617,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
unsigned long flags;
int ret = 0;
@@ -6628,7 +6639,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
break;
@@ -6705,7 +6716,7 @@ static int ipw_wx_get_auth(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
- struct ieee80211_crypt_data *crypt;
+ struct lib80211_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
int ret = 0;
@@ -6721,7 +6732,7 @@ static int ipw_wx_get_auth(struct net_device *dev,
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
if (!crypt || !crypt->ops->get_flags)
break;
@@ -6892,8 +6903,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
if ((priv->status & STATUS_ASSOCIATED) &&
(priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
if (memcmp(network->bssid, priv->bssid, ETH_ALEN))
- if ((network->capability & WLAN_CAPABILITY_IBSS) &&
- !(network->flags & NETWORK_EMPTY_ESSID))
+ if (network->capability & WLAN_CAPABILITY_IBSS)
if ((network->ssid_len ==
priv->assoc_network->ssid_len) &&
!memcmp(network->ssid,
@@ -7295,7 +7305,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
struct ipw_supported_rates *rates, int roaming)
{
int err;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
if (priv->config & CFG_FIXED_RATE)
ipw_set_fixed_rate(priv, network->mode);
@@ -7364,7 +7374,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
roaming ? "Rea" : "A",
- escape_essid(priv->essid, priv->essid_len),
+ print_ssid(ssid, priv->essid, priv->essid_len),
network->channel,
ipw_modes[priv->assoc_request.ieee_mode],
rates->num_rates,
@@ -7463,9 +7473,9 @@ static int ipw_associate_network(struct ipw_priv *priv,
return err;
}
- IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n",
- escape_essid(priv->essid, priv->essid_len),
- print_mac(mac, priv->bssid));
+ IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n",
+ print_ssid(ssid, priv->essid, priv->essid_len),
+ priv->bssid);
return 0;
}
@@ -7555,6 +7565,7 @@ static int ipw_associate(void *data)
struct ipw_supported_rates *rates;
struct list_head *element;
unsigned long flags;
+ DECLARE_SSID_BUF(ssid);
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
@@ -7581,8 +7592,7 @@ static int ipw_associate(void *data)
}
if (!(priv->config & CFG_ASSOCIATE) &&
- !(priv->config & (CFG_STATIC_ESSID |
- CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
+ !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) {
IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
return 0;
}
@@ -7604,7 +7614,6 @@ static int ipw_associate(void *data)
if (list_empty(&priv->ieee->network_free_list)) {
struct ieee80211_network *oldest = NULL;
struct ieee80211_network *target;
- DECLARE_MAC_BUF(mac);
list_for_each_entry(target, &priv->ieee->network_list, list) {
if ((oldest == NULL) ||
@@ -7615,11 +7624,11 @@ static int ipw_associate(void *data)
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- IPW_DEBUG_ASSOC("Expired '%s' (%s) from "
+ IPW_DEBUG_ASSOC("Expired '%s' (%pM) from "
"network list.\n",
- escape_essid(target->ssid,
- target->ssid_len),
- print_mac(mac, target->bssid));
+ print_ssid(ssid, target->ssid,
+ target->ssid_len),
+ target->bssid);
list_add_tail(&target->list,
&priv->ieee->network_free_list);
}
@@ -7672,12 +7681,12 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
u16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
+ fc = le16_to_cpu(hdr->frame_control);
if (!(fc & IEEE80211_FCTL_PROTECTED))
return;
fc &= ~IEEE80211_FCTL_PROTECTED;
- hdr->frame_ctl = cpu_to_le16(fc);
+ hdr->frame_control = cpu_to_le16(fc);
switch (priv->ieee->sec.level) {
case SEC_LEVEL_3:
/* Remove CCMP HDR */
@@ -7805,15 +7814,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
rxb->skb->data + IPW_RX_FRAME_SIZE, len);
- /* Zero the radiotap static buffer ... We only need to zero the bytes NOT
- * part of our real header, saves a little time.
- *
- * No longer necessary since we fill in all our data. Purge before merging
- * patch officially.
- * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
- * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
- */
-
ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
@@ -7989,17 +7989,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
}
hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+ if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -8017,19 +8017,10 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
ipw_rt = (void *)skb->data;
if (hdr_only)
- len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
memcpy(ipw_rt->payload, hdr, len);
- /* Zero the radiotap static buffer ... We only need to zero the bytes
- * NOT part of our real header, saves a little time.
- *
- * No longer necessary since we fill in all our data. Purge before
- * merging patch officially.
- * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
- * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
- */
-
ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */
@@ -8237,7 +8228,7 @@ static int is_duplicate_packet(struct ipw_priv *priv,
/* Comment this line now since we observed the card receives
* duplicate packets but the FCTL_RETRY bit is not set in the
* IBSS mode with fragmentation enabled.
- BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */
+ BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */
return 1;
}
@@ -8301,9 +8292,6 @@ static void ipw_rx(struct ipw_priv *priv)
u32 r, w, i;
u8 network_packet;
u8 fill_rx = 0;
- DECLARE_MAC_BUF(mac);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
r = ipw_read32(priv, IPW_RX_READ_INDEX);
w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
@@ -8433,18 +8421,12 @@ static void ipw_rx(struct ipw_priv *priv)
header)))
{
IPW_DEBUG_DROP("Dropping: "
- "%s, "
- "%s, "
- "%s\n",
- print_mac(mac,
- header->
- addr1),
- print_mac(mac2,
- header->
- addr2),
- print_mac(mac3,
- header->
- addr3));
+ "%pM, "
+ "%pM, "
+ "%pM\n",
+ header->addr1,
+ header->addr2,
+ header->addr3);
break;
}
@@ -8983,7 +8965,6 @@ static int ipw_wx_set_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- DECLARE_MAC_BUF(mac);
static const unsigned char any[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -9014,8 +8995,8 @@ static int ipw_wx_set_wap(struct net_device *dev,
return 0;
}
- IPW_DEBUG_WX("Setting mandatory BSSID to %s\n",
- print_mac(mac, wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n",
+ wrqu->ap_addr.sa_data);
memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
@@ -9033,7 +9014,6 @@ static int ipw_wx_get_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- DECLARE_MAC_BUF(mac);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -9045,8 +9025,8 @@ static int ipw_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
- print_mac(mac, wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %pM\n",
+ wrqu->ap_addr.sa_data);
mutex_unlock(&priv->mutex);
return 0;
}
@@ -9057,6 +9037,7 @@ static int ipw_wx_set_essid(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
int length;
+ DECLARE_SSID_BUF(ssid);
mutex_lock(&priv->mutex);
@@ -9081,8 +9062,8 @@ static int ipw_wx_set_essid(struct net_device *dev,
return 0;
}
- IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length),
- length);
+ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
+ print_ssid(ssid, extra, length), length);
priv->essid_len = length;
memcpy(priv->essid, extra, priv->essid_len);
@@ -9101,6 +9082,7 @@ static int ipw_wx_get_essid(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ DECLARE_SSID_BUF(ssid);
/* If we are associated, trying to associate, or have a statically
* configured ESSID then return that; otherwise return ANY */
@@ -9108,7 +9090,7 @@ static int ipw_wx_get_essid(struct net_device *dev,
if (priv->config & CFG_STATIC_ESSID ||
priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
IPW_DEBUG_WX("Getting essid: '%s'\n",
- escape_essid(priv->essid, priv->essid_len));
+ print_ssid(ssid, priv->essid, priv->essid_len));
memcpy(extra, priv->essid, priv->essid_len);
wrqu->essid.length = priv->essid_len;
wrqu->essid.flags = 1; /* active */
@@ -10190,6 +10172,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
u16 remaining_bytes;
int fc;
+ if (!(priv->status & STATUS_ASSOCIATED))
+ goto drop;
+
hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
@@ -10199,10 +10184,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
id = ipw_add_station(priv, hdr->addr1);
if (id == IPW_INVALID_STATION) {
IPW_WARNING("Attempt to send data to "
- "invalid cell: " MAC_FMT "\n",
- hdr->addr1[0], hdr->addr1[1],
- hdr->addr1[2], hdr->addr1[3],
- hdr->addr1[4], hdr->addr1[5]);
+ "invalid cell: %pM\n",
+ hdr->addr1);
goto drop;
}
}
@@ -10270,8 +10253,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
case SEC_LEVEL_1:
tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.key_index = priv->ieee->tx_keyidx;
- if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
+ tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx;
+ if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <=
40)
tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
else
@@ -10399,17 +10382,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
/* Filtering of fragment chains is done agains the first fragment */
hdr = (void *)txb->fragments[0]->data;
- if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
+ if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
+ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
+ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -10424,13 +10407,13 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
if (hdr_only) {
hdr = (void *)src->data;
- len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
} else
len = src->len;
- dst = alloc_skb(
- len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC);
- if (!dst) continue;
+ dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC);
+ if (!dst)
+ continue;
rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr));
@@ -10505,15 +10488,14 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct sockaddr *addr = p;
- DECLARE_MAC_BUF(mac);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
mutex_lock(&priv->mutex);
priv->config |= CFG_CUSTOM_MAC;
memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to %s\n",
- priv->net_dev->name, print_mac(mac, priv->mac_addr));
+ printk(KERN_INFO "%s: Setting MAC to %pM\n",
+ priv->net_dev->name, priv->mac_addr);
queue_work(priv->workqueue, &priv->adapter_restart);
mutex_unlock(&priv->mutex);
return 0;
@@ -11648,7 +11630,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
length = pci_resource_len(pdev, 0);
priv->hw_len = length;
- base = ioremap_nocache(pci_resource_start(pdev, 0), length);
+ base = pci_ioremap_bar(pdev, 0);
if (!base) {
err = -ENODEV;
goto out_pci_release_regions;
@@ -11940,7 +11922,7 @@ module_param(disable, int, 0444);
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param(associate, int, 0444);
-MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
+MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
module_param(auto_create, int, 0444);
MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
index 0bad1ec3e7e..277b274d4be 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -48,6 +48,7 @@
#include <linux/jiffies.h>
#include <asm/io.h>
+#include <net/lib80211.h>
#include <net/ieee80211.h>
#include <net/ieee80211_radiotap.h>
@@ -244,6 +245,7 @@ enum connection_manager_assoc_states {
#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31
#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1
+#define IPW_MB_SCAN_CANCEL_THRESHOLD 3
#define IPW_MB_ROAMING_THRESHOLD_MIN 1
#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8
#define IPW_MB_ROAMING_THRESHOLD_MAX 30
diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c
new file mode 100644
index 00000000000..960ad13f5e9
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/libipw_geo.c
@@ -0,0 +1,195 @@
+/******************************************************************************
+
+ Copyright(c) 2005 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., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+
+#include <net/ieee80211.h>
+
+int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+ return 0;
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ /* NOTE: If G mode is currently supported but
+ * this is a B only channel, we don't see it
+ * as valid. */
+ if ((ieee->geo.bg[i].channel == channel) &&
+ !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) &&
+ (!(ieee->mode & IEEE_G) ||
+ !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
+ return IEEE80211_24GHZ_BAND;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if ((ieee->geo.a[i].channel == channel) &&
+ !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID))
+ return IEEE80211_52GHZ_BAND;
+
+ return 0;
+}
+
+int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+ return -1;
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ if (ieee->geo.bg[i].channel == channel)
+ return i;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if (ieee->geo.a[i].channel == channel)
+ return i;
+
+ return -1;
+}
+
+u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+{
+ const struct ieee80211_channel * ch;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+ return 0;
+
+ ch = ieee80211_get_channel(ieee, channel);
+ if (!ch->channel)
+ return 0;
+ return ch->freq;
+}
+
+u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+ return 0;
+
+ freq /= 100000;
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ if (ieee->geo.bg[i].freq == freq)
+ return ieee->geo.bg[i].channel;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if (ieee->geo.a[i].freq == freq)
+ return ieee->geo.a[i].channel;
+
+ return 0;
+}
+
+int ieee80211_set_geo(struct ieee80211_device *ieee,
+ const struct ieee80211_geo *geo)
+{
+ memcpy(ieee->geo.name, geo->name, 3);
+ ieee->geo.name[3] = '\0';
+ ieee->geo.bg_channels = geo->bg_channels;
+ ieee->geo.a_channels = geo->a_channels;
+ memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
+ sizeof(struct ieee80211_channel));
+ memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
+ sizeof(struct ieee80211_channel));
+ return 0;
+}
+
+const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee)
+{
+ return &ieee->geo;
+}
+
+u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel)
+{
+ int index = ieee80211_channel_to_index(ieee, channel);
+
+ if (index == -1)
+ return IEEE80211_CH_INVALID;
+
+ if (channel <= IEEE80211_24GHZ_CHANNELS)
+ return ieee->geo.bg[index].flags;
+
+ return ieee->geo.a[index].flags;
+}
+
+static const struct ieee80211_channel bad_channel = {
+ .channel = 0,
+ .flags = IEEE80211_CH_INVALID,
+ .max_power = 0,
+};
+
+const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device
+ *ieee, u8 channel)
+{
+ int index = ieee80211_channel_to_index(ieee, channel);
+
+ if (index == -1)
+ return &bad_channel;
+
+ if (channel <= IEEE80211_24GHZ_CHANNELS)
+ return &ieee->geo.bg[index];
+
+ return &ieee->geo.a[index];
+}
+
+EXPORT_SYMBOL(ieee80211_get_channel);
+EXPORT_SYMBOL(ieee80211_get_channel_flags);
+EXPORT_SYMBOL(ieee80211_is_valid_channel);
+EXPORT_SYMBOL(ieee80211_freq_to_channel);
+EXPORT_SYMBOL(ieee80211_channel_to_freq);
+EXPORT_SYMBOL(ieee80211_channel_to_index);
+EXPORT_SYMBOL(ieee80211_set_geo);
+EXPORT_SYMBOL(ieee80211_get_geo);
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
new file mode 100644
index 00000000000..a2f5616d5b0
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -0,0 +1,293 @@
+/*******************************************************************************
+
+ Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
+
+ Portions of this file are based on the WEP enablement code provided by the
+ Host AP project hostap-drivers v0.1.3
+ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+
+ 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., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <net/net_namespace.h>
+#include <net/arp.h>
+
+#include <net/ieee80211.h>
+
+#define DRV_DESCRIPTION "802.11 data/management/control stack"
+#define DRV_NAME "ieee80211"
+#define DRV_VERSION IEEE80211_VERSION
+#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+{
+ if (ieee->networks)
+ return 0;
+
+ ieee->networks =
+ kzalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network),
+ GFP_KERNEL);
+ if (!ieee->networks) {
+ printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
+ ieee->dev->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ieee80211_network_reset(struct ieee80211_network *network)
+{
+ if (!network)
+ return;
+
+ if (network->ibss_dfs) {
+ kfree(network->ibss_dfs);
+ network->ibss_dfs = NULL;
+ }
+}
+
+static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
+{
+ int i;
+
+ if (!ieee->networks)
+ return;
+
+ for (i = 0; i < MAX_NETWORK_COUNT; i++)
+ if (ieee->networks[i].ibss_dfs)
+ kfree(ieee->networks[i].ibss_dfs);
+
+ kfree(ieee->networks);
+ ieee->networks = NULL;
+}
+
+static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+{
+ int i;
+
+ INIT_LIST_HEAD(&ieee->network_free_list);
+ INIT_LIST_HEAD(&ieee->network_list);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++)
+ list_add_tail(&ieee->networks[i].list,
+ &ieee->network_free_list);
+}
+
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static struct net_device_stats *ieee80211_generic_get_stats(
+ struct net_device *dev)
+{
+ struct ieee80211_device *ieee = netdev_priv(dev);
+ return &ieee->stats;
+}
+
+struct net_device *alloc_ieee80211(int sizeof_priv)
+{
+ struct ieee80211_device *ieee;
+ struct net_device *dev;
+ int err;
+
+ IEEE80211_DEBUG_INFO("Initializing...\n");
+
+ dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv);
+ if (!dev) {
+ IEEE80211_ERROR("Unable to allocate network device.\n");
+ goto failed;
+ }
+ ieee = netdev_priv(dev);
+ dev->hard_start_xmit = ieee80211_xmit;
+ dev->change_mtu = ieee80211_change_mtu;
+
+ /* Drivers are free to override this if the generic implementation
+ * does not meet their needs. */
+ dev->get_stats = ieee80211_generic_get_stats;
+
+ ieee->dev = dev;
+
+ err = ieee80211_networks_allocate(ieee);
+ if (err) {
+ IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err);
+ goto failed_free_netdev;
+ }
+ ieee80211_networks_initialize(ieee);
+
+ /* Default fragmentation threshold is maximum payload size */
+ ieee->fts = DEFAULT_FTS;
+ ieee->rts = DEFAULT_FTS;
+ ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
+ ieee->open_wep = 1;
+
+ /* Default to enabling full open WEP with host based encrypt/decrypt */
+ ieee->host_encrypt = 1;
+ ieee->host_decrypt = 1;
+ ieee->host_mc_decrypt = 1;
+
+ /* Host fragementation in Open mode. Default is enabled.
+ * Note: host fragmentation is always enabled if host encryption
+ * is enabled. For cards can do hardware encryption, they must do
+ * hardware fragmentation as well. So we don't need a variable
+ * like host_enc_frag. */
+ ieee->host_open_frag = 1;
+ ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
+
+ spin_lock_init(&ieee->lock);
+
+ lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
+
+ ieee->wpa_enabled = 0;
+ ieee->drop_unencrypted = 0;
+ ieee->privacy_invoked = 0;
+
+ return dev;
+
+failed_free_netdev:
+ free_netdev(dev);
+failed:
+ return NULL;
+}
+
+void free_ieee80211(struct net_device *dev)
+{
+ struct ieee80211_device *ieee = netdev_priv(dev);
+
+ lib80211_crypt_info_free(&ieee->crypt_info);
+
+ ieee80211_networks_free(ieee);
+ free_netdev(dev);
+}
+
+#ifdef CONFIG_IEEE80211_DEBUG
+
+static int debug = 0;
+u32 ieee80211_debug_level = 0;
+EXPORT_SYMBOL_GPL(ieee80211_debug_level);
+static struct proc_dir_entry *ieee80211_proc = NULL;
+
+static int show_debug_level(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ return snprintf(page, count, "0x%08X\n", ieee80211_debug_level);
+}
+
+static int store_debug_level(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+{
+ char buf[] = "0x00000000\n";
+ unsigned long len = min((unsigned long)sizeof(buf) - 1, count);
+ unsigned long val;
+
+ if (copy_from_user(buf, buffer, len))
+ return count;
+ buf[len] = 0;
+ if (sscanf(buf, "%li", &val) != 1)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ ieee80211_debug_level = val;
+
+ return strnlen(buf, len);
+}
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+static int __init ieee80211_init(void)
+{
+#ifdef CONFIG_IEEE80211_DEBUG
+ struct proc_dir_entry *e;
+
+ ieee80211_debug_level = debug;
+ ieee80211_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
+ if (ieee80211_proc == NULL) {
+ IEEE80211_ERROR("Unable to create " DRV_NAME
+ " proc directory\n");
+ return -EIO;
+ }
+ e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR,
+ ieee80211_proc);
+ if (!e) {
+ remove_proc_entry(DRV_NAME, init_net.proc_net);
+ ieee80211_proc = NULL;
+ return -EIO;
+ }
+ e->read_proc = show_debug_level;
+ e->write_proc = store_debug_level;
+ e->data = NULL;
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+ return 0;
+}
+
+static void __exit ieee80211_exit(void)
+{
+#ifdef CONFIG_IEEE80211_DEBUG
+ if (ieee80211_proc) {
+ remove_proc_entry("debug_level", ieee80211_proc);
+ remove_proc_entry(DRV_NAME, init_net.proc_net);
+ ieee80211_proc = NULL;
+ }
+#endif /* CONFIG_IEEE80211_DEBUG */
+}
+
+#ifdef CONFIG_IEEE80211_DEBUG
+#include <linux/moduleparam.h>
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+module_exit(ieee80211_exit);
+module_init(ieee80211_init);
+
+EXPORT_SYMBOL(alloc_ieee80211);
+EXPORT_SYMBOL(free_ieee80211);
diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c
new file mode 100644
index 00000000000..9c67dfae432
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/libipw_rx.c
@@ -0,0 +1,1799 @@
+/*
+ * Original code based Host AP (software wireless LAN access point) driver
+ * for Intersil Prism2/2.5/3 - hostap.o module, common routines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2005, Intel Corporation
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>
+
+#include <net/lib80211.h>
+#include <net/ieee80211.h>
+
+static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+ struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ skb->dev = ieee->dev;
+ skb_reset_mac_header(skb);
+ skb_pull(skb, ieee80211_get_hdrlen(fc));
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_80211_RAW);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct
+ ieee80211_device
+ *ieee,
+ unsigned int seq,
+ unsigned int frag,
+ u8 * src,
+ u8 * dst)
+{
+ struct ieee80211_frag_entry *entry;
+ int i;
+
+ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {
+ entry = &ieee->frag_cache[i];
+ if (entry->skb != NULL &&
+ time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
+ IEEE80211_DEBUG_FRAG("expiring fragment cache entry "
+ "seq=%u last_frag=%u\n",
+ entry->seq, entry->last_frag);
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+ }
+
+ if (entry->skb != NULL && entry->seq == seq &&
+ (entry->last_frag + 1 == frag || frag == -1) &&
+ !compare_ether_addr(entry->src_addr, src) &&
+ !compare_ether_addr(entry->dst_addr, dst))
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct sk_buff *skb = NULL;
+ u16 sc;
+ unsigned int frag, seq;
+ struct ieee80211_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ seq = WLAN_GET_SEQ_SEQ(sc);
+
+ if (frag == 0) {
+ /* Reserve enough space to fit maximum frame length */
+ skb = dev_alloc_skb(ieee->dev->mtu +
+ sizeof(struct ieee80211_hdr_4addr) +
+ 8 /* LLC */ +
+ 2 /* alignment */ +
+ 8 /* WEP */ + ETH_ALEN /* WDS */ );
+ if (skb == NULL)
+ return NULL;
+
+ entry = &ieee->frag_cache[ieee->frag_next_idx];
+ ieee->frag_next_idx++;
+ if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)
+ ieee->frag_next_idx = 0;
+
+ if (entry->skb != NULL)
+ dev_kfree_skb_any(entry->skb);
+
+ entry->first_frag_time = jiffies;
+ entry->seq = seq;
+ entry->last_frag = frag;
+ entry->skb = skb;
+ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
+ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
+ } else {
+ /* received a fragment of a frame for which the head fragment
+ * should have already been received */
+ entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,
+ hdr->addr1);
+ if (entry != NULL) {
+ entry->last_frag = frag;
+ skb = entry->skb;
+ }
+ }
+
+ return skb;
+}
+
+/* Called only as a tasklet (software IRQ) */
+static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ u16 sc;
+ unsigned int seq;
+ struct ieee80211_frag_entry *entry;
+
+ sc = le16_to_cpu(hdr->seq_ctl);
+ seq = WLAN_GET_SEQ_SEQ(sc);
+
+ entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,
+ hdr->addr1);
+
+ if (entry == NULL) {
+ IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "
+ "entry (seq=%u)\n", seq);
+ return -1;
+ }
+
+ entry->skb = NULL;
+ return 0;
+}
+
+#ifdef NOT_YET
+/* ieee80211_rx_frame_mgtmt
+ *
+ * Responsible for handling management control frames
+ *
+ * Called by ieee80211_rx */
+static int
+ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats, u16 type,
+ u16 stype)
+{
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
+ ieee->dev->name);
+ return 0;
+/*
+ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *)
+ skb->data);*/
+ }
+
+ if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
+ if (stype == WLAN_FC_STYPE_BEACON &&
+ ieee->iw_mode == IW_MODE_MASTER) {
+ struct sk_buff *skb2;
+ /* Process beacon frames also in kernel driver to
+ * update STA(AP) table statistics */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ hostap_rx(skb2->dev, skb2, rx_stats);
+ }
+
+ /* send management frames to the user space daemon for
+ * processing */
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
+ return 0;
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER) {
+ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
+ printk(KERN_DEBUG "%s: unknown management frame "
+ "(type=0x%02x, stype=0x%02x) dropped\n",
+ skb->dev->name, type, stype);
+ return -1;
+ }
+
+ hostap_rx(skb->dev, skb, rx_stats);
+ return 0;
+ }
+
+ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
+ "received in non-Host AP mode\n", skb->dev->name);
+ return -1;
+}
+#endif
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static unsigned char bridge_tunnel_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+/* No encapsulation header if EtherType < 0x600 (=length) */
+
+/* Called by ieee80211_rx_frame_decrypt */
+static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
+ struct sk_buff *skb)
+{
+ struct net_device *dev = ieee->dev;
+ u16 fc, ethertype;
+ struct ieee80211_hdr_3addr *hdr;
+ u8 *pos;
+
+ if (skb->len < 24)
+ return 0;
+
+ hdr = (struct ieee80211_hdr_3addr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ /* check that the frame is unicast frame to us */
+ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS &&
+ !compare_ether_addr(hdr->addr1, dev->dev_addr) &&
+ !compare_ether_addr(hdr->addr3, dev->dev_addr)) {
+ /* ToDS frame with own addr BSSID and DA */
+ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS &&
+ !compare_ether_addr(hdr->addr1, dev->dev_addr)) {
+ /* FromDS frame with own addr as DA */
+ } else
+ return 0;
+
+ if (skb->len < 24 + 8)
+ return 0;
+
+ /* check for port access entity Ethernet type */
+ pos = skb->data + 24;
+ ethertype = (pos[6] << 8) | pos[7];
+ if (ethertype == ETH_P_PAE)
+ return 1;
+
+ return 0;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static int
+ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct lib80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr_3addr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr_3addr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
+ hdr->addr2, res);
+ if (res == -2)
+ IEEE80211_DEBUG_DROP("Decryption failed ICV "
+ "mismatch (key %d)\n",
+ skb->data[hdrlen + 3] >> 6);
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ return -1;
+ }
+
+ return res;
+}
+
+/* Called only as a tasklet (software IRQ), by ieee80211_rx */
+static int
+ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
+ struct sk_buff *skb, int keyidx,
+ struct lib80211_crypt_data *crypt)
+{
+ struct ieee80211_hdr_3addr *hdr;
+ int res, hdrlen;
+
+ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
+ return 0;
+
+ hdr = (struct ieee80211_hdr_3addr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+
+ atomic_inc(&crypt->refcnt);
+ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
+ " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
+ keyidx);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* All received frames are sent to this function. @skb contains the frame in
+ * IEEE 802.11 format, i.e., in the format it was sent over air.
+ * This function is called only as a tasklet (software IRQ). */
+int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats)
+{
+ struct net_device *dev = ieee->dev;
+ struct ieee80211_hdr_4addr *hdr;
+ size_t hdrlen;
+ u16 fc, type, stype, sc;
+ struct net_device_stats *stats;
+ unsigned int frag;
+ u8 *payload;
+ u16 ethertype;
+#ifdef NOT_YET
+ struct net_device *wds = NULL;
+ struct sk_buff *skb2 = NULL;
+ struct net_device *wds = NULL;
+ int frame_authorized = 0;
+ int from_assoc_ap = 0;
+ void *sta = NULL;
+#endif
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ struct lib80211_crypt_data *crypt = NULL;
+ int keyidx = 0;
+ int can_be_decrypted = 0;
+
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ stats = &ieee->stats;
+
+ if (skb->len < 10) {
+ printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
+ goto rx_dropped;
+ }
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+ sc = le16_to_cpu(hdr->seq_ctl);
+ frag = WLAN_GET_SEQ_FRAG(sc);
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (skb->len < hdrlen) {
+ printk(KERN_INFO "%s: invalid SKB length %d\n",
+ dev->name, skb->len);
+ goto rx_dropped;
+ }
+
+ /* Put this code here so that we avoid duplicating it in all
+ * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
+#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
+ /* If spy monitoring on */
+ if (ieee->spy_data.spy_number > 0) {
+ struct iw_quality wstats;
+
+ wstats.updated = 0;
+ if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
+ wstats.level = rx_stats->signal;
+ wstats.updated |= IW_QUAL_LEVEL_UPDATED;
+ } else
+ wstats.updated |= IW_QUAL_LEVEL_INVALID;
+
+ if (rx_stats->mask & IEEE80211_STATMASK_NOISE) {
+ wstats.noise = rx_stats->noise;
+ wstats.updated |= IW_QUAL_NOISE_UPDATED;
+ } else
+ wstats.updated |= IW_QUAL_NOISE_INVALID;
+
+ if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) {
+ wstats.qual = rx_stats->signal;
+ wstats.updated |= IW_QUAL_QUAL_UPDATED;
+ } else
+ wstats.updated |= IW_QUAL_QUAL_INVALID;
+
+ /* Update spy records */
+ wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
+ }
+#endif /* IW_WIRELESS_SPY */
+#endif /* CONFIG_WIRELESS_EXT */
+
+#ifdef NOT_YET
+ hostap_update_rx_stats(local->ap, hdr, rx_stats);
+#endif
+
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ ieee80211_monitor_rx(ieee, skb, rx_stats);
+ return 1;
+ }
+
+ can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
+ is_broadcast_ether_addr(hdr->addr2)) ?
+ ieee->host_mc_decrypt : ieee->host_decrypt;
+
+ if (can_be_decrypted) {
+ if (skb->len >= hdrlen + 3) {
+ /* Top two-bits of byte 3 are the key index */
+ keyidx = skb->data[hdrlen + 3] >> 6;
+ }
+
+ /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
+ * is only allowed 2-bits of storage, no value of keyidx can
+ * be provided via above code that would result in keyidx
+ * being out of range */
+ crypt = ieee->crypt_info.crypt[keyidx];
+
+#ifdef NOT_YET
+ sta = NULL;
+
+ /* Use station specific key to override default keys if the
+ * receiver address is a unicast address ("individual RA"). If
+ * bcrx_sta_key parameter is set, station specific key is used
+ * even with broad/multicast targets (this is against IEEE
+ * 802.11, but makes it easier to use different keys with
+ * stations that do not support WEP key mapping). */
+
+ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
+ (void)hostap_handle_sta_crypto(local, hdr, &crypt,
+ &sta);
+#endif
+
+ /* allow NULL decrypt to indicate an station specific override
+ * for default encryption */
+ if (crypt && (crypt->ops == NULL ||
+ crypt->ops->decrypt_mpdu == NULL))
+ crypt = NULL;
+
+ if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
+ /* This seems to be triggered by some (multicast?)
+ * frames from other than current BSS, so just drop the
+ * frames silently instead of filling system log with
+ * these reports. */
+ IEEE80211_DEBUG_DROP("Decryption failed (not set)"
+ " (SA=%pM)\n", hdr->addr2);
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ goto rx_dropped;
+ }
+ }
+#ifdef NOT_YET
+ if (type != WLAN_FC_TYPE_DATA) {
+ if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
+ fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
+ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
+ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
+ "from %pM\n", dev->name, hdr->addr2);
+ /* TODO: could inform hostapd about this so that it
+ * could send auth failure report */
+ goto rx_dropped;
+ }
+
+ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
+ goto rx_dropped;
+ else
+ goto rx_exit;
+ }
+#endif
+ /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
+ if (sc == ieee->prev_seq_ctl)
+ goto rx_dropped;
+ else
+ ieee->prev_seq_ctl = sc;
+
+ /* Data frame - extract src/dst addresses */
+ if (skb->len < IEEE80211_3ADDR_LEN)
+ goto rx_dropped;
+
+ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ case IEEE80211_FCTL_FROMDS:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr3, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_TODS:
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
+ if (skb->len < IEEE80211_4ADDR_LEN)
+ goto rx_dropped;
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr4, ETH_ALEN);
+ break;
+ case 0:
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+ break;
+ }
+
+#ifdef NOT_YET
+ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
+ goto rx_dropped;
+ if (wds) {
+ skb->dev = dev = wds;
+ stats = hostap_get_stats(dev);
+ }
+
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
+ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_FROMDS && ieee->stadev
+ && !compare_ether_addr(hdr->addr2, ieee->assoc_ap_addr)) {
+ /* Frame from BSSID of the AP for which we are a client */
+ skb->dev = dev = ieee->stadev;
+ stats = hostap_get_stats(dev);
+ from_assoc_ap = 1;
+ }
+#endif
+
+#ifdef NOT_YET
+ if ((ieee->iw_mode == IW_MODE_MASTER ||
+ ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
+ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
+ wds != NULL)) {
+ case AP_RX_CONTINUE_NOT_AUTHORIZED:
+ frame_authorized = 0;
+ break;
+ case AP_RX_CONTINUE:
+ frame_authorized = 1;
+ break;
+ case AP_RX_DROP:
+ goto rx_dropped;
+ case AP_RX_EXIT:
+ goto rx_exit;
+ }
+ }
+#endif
+
+ /* Nullfunc frames may have PS-bit set, so they must be passed to
+ * hostap_handle_sta_rx() before being dropped here. */
+
+ stype &= ~IEEE80211_STYPE_QOS_DATA;
+
+ if (stype != IEEE80211_STYPE_DATA &&
+ stype != IEEE80211_STYPE_DATA_CFACK &&
+ stype != IEEE80211_STYPE_DATA_CFPOLL &&
+ stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
+ if (stype != IEEE80211_STYPE_NULLFUNC)
+ IEEE80211_DEBUG_DROP("RX: dropped data frame "
+ "with no data (type=0x%02x, "
+ "subtype=0x%02x, len=%d)\n",
+ type, stype, skb->len);
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
+
+ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
+ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+
+ /* skb: hdr + (possibly fragmented) plaintext payload */
+ // PR: FIXME: hostap has additional conditions in the "if" below:
+ // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+ if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
+ int flen;
+ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr);
+ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
+
+ if (!frag_skb) {
+ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG,
+ "Rx cannot get skb from fragment "
+ "cache (morefrag=%d seq=%u frag=%u)\n",
+ (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
+ WLAN_GET_SEQ_SEQ(sc), frag);
+ goto rx_dropped;
+ }
+
+ flen = skb->len;
+ if (frag != 0)
+ flen -= hdrlen;
+
+ if (frag_skb->tail + flen > frag_skb->end) {
+ printk(KERN_WARNING "%s: host decrypted and "
+ "reassembled frame did not fit skb\n",
+ dev->name);
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ goto rx_dropped;
+ }
+
+ if (frag == 0) {
+ /* copy first fragment (including full headers) into
+ * beginning of the fragment cache skb */
+ skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
+ } else {
+ /* append frame payload to the end of the fragment
+ * cache skb */
+ skb_copy_from_linear_data_offset(skb, hdrlen,
+ skb_put(frag_skb, flen), flen);
+ }
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+
+ if (fc & IEEE80211_FCTL_MOREFRAGS) {
+ /* more fragments expected - leave the skb in fragment
+ * cache for now; it will be delivered to upper layers
+ * after all fragments have been received */
+ goto rx_exit;
+ }
+
+ /* this was the last fragment and the frame will be
+ * delivered, so remove skb from fragment cache */
+ skb = frag_skb;
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ ieee80211_frag_cache_invalidate(ieee, hdr);
+ }
+
+ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
+ * encrypted/authenticated */
+ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
+ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
+ goto rx_dropped;
+
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
+ if ( /*ieee->ieee802_1x && */
+ ieee80211_is_eapol_frame(ieee, skb)) {
+ /* pass unencrypted EAPOL frames even if encryption is
+ * configured */
+ } else {
+ IEEE80211_DEBUG_DROP("encryption configured, but RX "
+ "frame not encrypted (SA=%pM)\n",
+ hdr->addr2);
+ goto rx_dropped;
+ }
+ }
+
+ if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
+ !ieee80211_is_eapol_frame(ieee, skb)) {
+ IEEE80211_DEBUG_DROP("dropped unencrypted RX data "
+ "frame from %pM (drop_unencrypted=1)\n",
+ hdr->addr2);
+ goto rx_dropped;
+ }
+
+ /* If the frame was decrypted in hardware, we may need to strip off
+ * any security data (IV, ICV, etc) that was left behind */
+ if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
+ ieee->host_strip_iv_icv) {
+ int trimlen = 0;
+
+ /* Top two-bits of byte 3 are the key index */
+ if (skb->len >= hdrlen + 3)
+ keyidx = skb->data[hdrlen + 3] >> 6;
+
+ /* To strip off any security data which appears before the
+ * payload, we simply increase hdrlen (as the header gets
+ * chopped off immediately below). For the security data which
+ * appears after the payload, we use skb_trim. */
+
+ switch (ieee->sec.encode_alg[keyidx]) {
+ case SEC_ALG_WEP:
+ /* 4 byte IV */
+ hdrlen += 4;
+ /* 4 byte ICV */
+ trimlen = 4;
+ break;
+ case SEC_ALG_TKIP:
+ /* 4 byte IV, 4 byte ExtIV */
+ hdrlen += 8;
+ /* 8 byte MIC, 4 byte ICV */
+ trimlen = 12;
+ break;
+ case SEC_ALG_CCMP:
+ /* 8 byte CCMP header */
+ hdrlen += 8;
+ /* 8 byte MIC */
+ trimlen = 8;
+ break;
+ }
+
+ if (skb->len < trimlen)
+ goto rx_dropped;
+
+ __skb_trim(skb, skb->len - trimlen);
+
+ if (skb->len < hdrlen)
+ goto rx_dropped;
+ }
+
+ /* skb: hdr + (possible reassembled) full plaintext payload */
+
+ payload = skb->data + hdrlen;
+ ethertype = (payload[6] << 8) | payload[7];
+
+#ifdef NOT_YET
+ /* If IEEE 802.1X is used, check whether the port is authorized to send
+ * the received frame. */
+ if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
+ if (ethertype == ETH_P_PAE) {
+ printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
+ dev->name);
+ if (ieee->hostapd && ieee->apdev) {
+ /* Send IEEE 802.1X frames to the user
+ * space daemon for processing */
+ prism2_rx_80211(ieee->apdev, skb, rx_stats,
+ PRISM2_RX_MGMT);
+ ieee->apdevstats.rx_packets++;
+ ieee->apdevstats.rx_bytes += skb->len;
+ goto rx_exit;
+ }
+ } else if (!frame_authorized) {
+ printk(KERN_DEBUG "%s: dropped frame from "
+ "unauthorized port (IEEE 802.1X): "
+ "ethertype=0x%04x\n", dev->name, ethertype);
+ goto rx_dropped;
+ }
+ }
+#endif
+
+ /* convert hdr + possible LLC headers into Ethernet header */
+ if (skb->len - hdrlen >= 8 &&
+ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + SNAP_SIZE);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ __be16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ memcpy(skb_push(skb, 2), &len, 2);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ }
+
+#ifdef NOT_YET
+ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
+ /* Non-standard frame: get addr4 from its bogus location after
+ * the payload */
+ skb_copy_to_linear_data_offset(skb, ETH_ALEN,
+ skb->data + skb->len - ETH_ALEN,
+ ETH_ALEN);
+ skb_trim(skb, skb->len - ETH_ALEN);
+ }
+#endif
+
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+#ifdef NOT_YET
+ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
+ if (dst[0] & 0x01) {
+ /* copy multicast frame both to the higher layers and
+ * to the wireless media */
+ ieee->ap->bridged_multicast++;
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ printk(KERN_DEBUG "%s: skb_clone failed for "
+ "multicast frame\n", dev->name);
+ } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
+ /* send frame directly to the associated STA using
+ * wireless media and not passing to higher layers */
+ ieee->ap->bridged_unicast++;
+ skb2 = skb;
+ skb = NULL;
+ }
+ }
+
+ if (skb2 != NULL) {
+ /* send to wireless media */
+ skb2->dev = dev;
+ skb2->protocol = htons(ETH_P_802_3);
+ skb_reset_mac_header(skb2);
+ skb_reset_network_header(skb2);
+ /* skb2->network_header += ETH_HLEN; */
+ dev_queue_xmit(skb2);
+ }
+#endif
+
+ if (skb) {
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
+ if (netif_rx(skb) == NET_RX_DROP) {
+ /* netif_rx always succeeds, but it might drop
+ * the packet. If it drops the packet, we log that
+ * in our stats. */
+ IEEE80211_DEBUG_DROP
+ ("RX: netif_rx dropped the packet\n");
+ stats->rx_dropped++;
+ }
+ }
+
+ rx_exit:
+#ifdef NOT_YET
+ if (sta)
+ hostap_handle_sta_release(sta);
+#endif
+ return 1;
+
+ rx_dropped:
+ stats->rx_dropped++;
+
+ /* Returning 0 indicates to caller that we have not handled the SKB--
+ * so it is still allocated and can be used again by underlying
+ * hardware as a DMA target */
+ return 0;
+}
+
+/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+ * This function takes over the skb, it should not be used again after calling
+ * this function. */
+void ieee80211_rx_any(struct ieee80211_device *ieee,
+ struct sk_buff *skb, struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_hdr_4addr *hdr;
+ int is_packet_for_us;
+ u16 fc;
+
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ if (!ieee80211_rx(ieee, skb, stats))
+ dev_kfree_skb_irq(skb);
+ return;
+ }
+
+ if (skb->len < sizeof(struct ieee80211_hdr))
+ goto drop_free;
+
+ hdr = (struct ieee80211_hdr_4addr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+
+ if ((fc & IEEE80211_FCTL_VERS) != 0)
+ goto drop_free;
+
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
+ if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+ goto drop_free;
+ ieee80211_rx_mgt(ieee, hdr, stats);
+ dev_kfree_skb_irq(skb);
+ return;
+ case IEEE80211_FTYPE_DATA:
+ break;
+ case IEEE80211_FTYPE_CTL:
+ return;
+ default:
+ return;
+ }
+
+ is_packet_for_us = 0;
+ switch (ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ /* our BSS and not from/to DS */
+ if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
+ if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
+ /* promisc: get all */
+ if (ieee->dev->flags & IFF_PROMISC)
+ is_packet_for_us = 1;
+ /* to us */
+ else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+ is_packet_for_us = 1;
+ /* mcast */
+ else if (is_multicast_ether_addr(hdr->addr1))
+ is_packet_for_us = 1;
+ }
+ break;
+ case IW_MODE_INFRA:
+ /* our BSS (== from our AP) and from DS */
+ if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
+ if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
+ /* promisc: get all */
+ if (ieee->dev->flags & IFF_PROMISC)
+ is_packet_for_us = 1;
+ /* to us */
+ else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
+ is_packet_for_us = 1;
+ /* mcast */
+ else if (is_multicast_ether_addr(hdr->addr1)) {
+ /* not our own packet bcasted from AP */
+ if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
+ is_packet_for_us = 1;
+ }
+ }
+ break;
+ default:
+ /* ? */
+ break;
+ }
+
+ if (is_packet_for_us)
+ if (!ieee80211_rx(ieee, skb, stats))
+ dev_kfree_skb_irq(skb);
+ return;
+
+drop_free:
+ dev_kfree_skb_irq(skb);
+ ieee->stats.rx_dropped++;
+ return;
+}
+
+#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
+
+static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
+
+/*
+* Make ther structure we read from the beacon packet has
+* the right values
+*/
+static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element
+ *info_element, int sub_type)
+{
+
+ if (info_element->qui_subtype != sub_type)
+ return -1;
+ if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
+ return -1;
+ if (info_element->qui_type != QOS_OUI_TYPE)
+ return -1;
+ if (info_element->version != QOS_VERSION_1)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Parse a QoS parameter element
+ */
+static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info
+ *element_param, struct ieee80211_info_element
+ *info_element)
+{
+ int ret = 0;
+ u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2;
+
+ if ((info_element == NULL) || (element_param == NULL))
+ return -1;
+
+ if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) {
+ memcpy(element_param->info_element.qui, info_element->data,
+ info_element->len);
+ element_param->info_element.elementID = info_element->id;
+ element_param->info_element.length = info_element->len;
+ } else
+ ret = -1;
+ if (ret == 0)
+ ret = ieee80211_verify_qos_info(&element_param->info_element,
+ QOS_OUI_PARAM_SUB_TYPE);
+ return ret;
+}
+
+/*
+ * Parse a QoS information element
+ */
+static int ieee80211_read_qos_info_element(struct
+ ieee80211_qos_information_element
+ *element_info, struct ieee80211_info_element
+ *info_element)
+{
+ int ret = 0;
+ u16 size = sizeof(struct ieee80211_qos_information_element) - 2;
+
+ if (element_info == NULL)
+ return -1;
+ if (info_element == NULL)
+ return -1;
+
+ if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) {
+ memcpy(element_info->qui, info_element->data,
+ info_element->len);
+ element_info->elementID = info_element->id;
+ element_info->length = info_element->len;
+ } else
+ ret = -1;
+
+ if (ret == 0)
+ ret = ieee80211_verify_qos_info(element_info,
+ QOS_OUI_INFO_SUB_TYPE);
+ return ret;
+}
+
+/*
+ * Write QoS parameters from the ac parameters.
+ */
+static int ieee80211_qos_convert_ac_to_parameters(struct
+ ieee80211_qos_parameter_info
+ *param_elm, struct
+ ieee80211_qos_parameters
+ *qos_param)
+{
+ int rc = 0;
+ int i;
+ struct ieee80211_qos_ac_parameter *ac_params;
+ u32 txop;
+ u8 cw_min;
+ u8 cw_max;
+
+ for (i = 0; i < QOS_QUEUE_NUM; i++) {
+ ac_params = &(param_elm->ac_params_record[i]);
+
+ qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
+ qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
+
+ cw_min = ac_params->ecw_min_max & 0x0F;
+ qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
+
+ cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
+ qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
+
+ qos_param->flag[i] =
+ (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
+
+ txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
+ qos_param->tx_op_limit[i] = cpu_to_le16(txop);
+ }
+ return rc;
+}
+
+/*
+ * we have a generic data element which it may contain QoS information or
+ * parameters element. check the information element length to decide
+ * which type to read
+ */
+static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
+ *info_element,
+ struct ieee80211_network *network)
+{
+ int rc = 0;
+ struct ieee80211_qos_parameters *qos_param = NULL;
+ struct ieee80211_qos_information_element qos_info_element;
+
+ rc = ieee80211_read_qos_info_element(&qos_info_element, info_element);
+
+ if (rc == 0) {
+ network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
+ network->flags |= NETWORK_HAS_QOS_INFORMATION;
+ } else {
+ struct ieee80211_qos_parameter_info param_element;
+
+ rc = ieee80211_read_qos_param_element(&param_element,
+ info_element);
+ if (rc == 0) {
+ qos_param = &(network->qos_data.parameters);
+ ieee80211_qos_convert_ac_to_parameters(&param_element,
+ qos_param);
+ network->flags |= NETWORK_HAS_QOS_PARAMETERS;
+ network->qos_data.param_count =
+ param_element.info_element.ac_info & 0x0F;
+ }
+ }
+
+ if (rc == 0) {
+ IEEE80211_DEBUG_QOS("QoS is supported\n");
+ network->qos_data.supported = 1;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_IEEE80211_DEBUG
+#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
+
+static const char *get_info_element_string(u16 id)
+{
+ switch (id) {
+ MFIE_STRING(SSID);
+ MFIE_STRING(RATES);
+ MFIE_STRING(FH_SET);
+ MFIE_STRING(DS_SET);
+ MFIE_STRING(CF_SET);
+ MFIE_STRING(TIM);
+ MFIE_STRING(IBSS_SET);
+ MFIE_STRING(COUNTRY);
+ MFIE_STRING(HOP_PARAMS);
+ MFIE_STRING(HOP_TABLE);
+ MFIE_STRING(REQUEST);
+ MFIE_STRING(CHALLENGE);
+ MFIE_STRING(POWER_CONSTRAINT);
+ MFIE_STRING(POWER_CAPABILITY);
+ MFIE_STRING(TPC_REQUEST);
+ MFIE_STRING(TPC_REPORT);
+ MFIE_STRING(SUPP_CHANNELS);
+ MFIE_STRING(CSA);
+ MFIE_STRING(MEASURE_REQUEST);
+ MFIE_STRING(MEASURE_REPORT);
+ MFIE_STRING(QUIET);
+ MFIE_STRING(IBSS_DFS);
+ MFIE_STRING(ERP_INFO);
+ MFIE_STRING(RSN);
+ MFIE_STRING(RATES_EX);
+ MFIE_STRING(GENERIC);
+ MFIE_STRING(QOS_PARAMETER);
+ default:
+ return "UNKNOWN";
+ }
+}
+#endif
+
+static int ieee80211_parse_info_param(struct ieee80211_info_element
+ *info_element, u16 length,
+ struct ieee80211_network *network)
+{
+ DECLARE_SSID_BUF(ssid);
+ u8 i;
+#ifdef CONFIG_IEEE80211_DEBUG
+ char rates_str[64];
+ char *p;
+#endif
+
+ while (length >= sizeof(*info_element)) {
+ if (sizeof(*info_element) + info_element->len > length) {
+ IEEE80211_DEBUG_MGMT("Info elem: parse failed: "
+ "info_element->len + 2 > left : "
+ "info_element->len+2=%zd left=%d, id=%d.\n",
+ info_element->len +
+ sizeof(*info_element),
+ length, info_element->id);
+ /* We stop processing but don't return an error here
+ * because some misbehaviour APs break this rule. ie.
+ * Orinoco AP1000. */
+ break;
+ }
+
+ switch (info_element->id) {
+ case MFIE_TYPE_SSID:
+ network->ssid_len = min(info_element->len,
+ (u8) IW_ESSID_MAX_SIZE);
+ memcpy(network->ssid, info_element->data,
+ network->ssid_len);
+ if (network->ssid_len < IW_ESSID_MAX_SIZE)
+ memset(network->ssid + network->ssid_len, 0,
+ IW_ESSID_MAX_SIZE - network->ssid_len);
+
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->ssid_len);
+ break;
+
+ case MFIE_TYPE_RATES:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_len = min(info_element->len,
+ MAX_RATES_LENGTH);
+ for (i = 0; i < network->rates_len; i++) {
+ network->rates[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p, sizeof(rates_str) -
+ (p - rates_str), "%02X ",
+ network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate
+ (info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n",
+ rates_str, network->rates_len);
+ break;
+
+ case MFIE_TYPE_RATES_EX:
+#ifdef CONFIG_IEEE80211_DEBUG
+ p = rates_str;
+#endif
+ network->rates_ex_len = min(info_element->len,
+ MAX_RATES_EX_LENGTH);
+ for (i = 0; i < network->rates_ex_len; i++) {
+ network->rates_ex[i] = info_element->data[i];
+#ifdef CONFIG_IEEE80211_DEBUG
+ p += snprintf(p, sizeof(rates_str) -
+ (p - rates_str), "%02X ",
+ network->rates[i]);
+#endif
+ if (ieee80211_is_ofdm_rate
+ (info_element->data[i])) {
+ network->flags |= NETWORK_HAS_OFDM;
+ if (info_element->data[i] &
+ IEEE80211_BASIC_RATE_MASK)
+ network->flags &=
+ ~NETWORK_HAS_CCK;
+ }
+ }
+
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+ rates_str, network->rates_ex_len);
+ break;
+
+ case MFIE_TYPE_DS_SET:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n",
+ info_element->data[0]);
+ network->channel = info_element->data[0];
+ break;
+
+ case MFIE_TYPE_FH_SET:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_CF_SET:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n");
+ break;
+
+ case MFIE_TYPE_TIM:
+ network->tim.tim_count = info_element->data[0];
+ network->tim.tim_period = info_element->data[1];
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
+ break;
+
+ case MFIE_TYPE_ERP_INFO:
+ network->erp_value = info_element->data[0];
+ network->flags |= NETWORK_HAS_ERP_VALUE;
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
+ network->erp_value);
+ break;
+
+ case MFIE_TYPE_IBSS_SET:
+ network->atim_window = info_element->data[0];
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n",
+ network->atim_window);
+ break;
+
+ case MFIE_TYPE_CHALLENGE:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n");
+ break;
+
+ case MFIE_TYPE_GENERIC:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n",
+ info_element->len);
+ if (!ieee80211_parse_qos_info_param_IE(info_element,
+ network))
+ break;
+
+ if (info_element->len >= 4 &&
+ info_element->data[0] == 0x00 &&
+ info_element->data[1] == 0x50 &&
+ info_element->data[2] == 0xf2 &&
+ info_element->data[3] == 0x01) {
+ network->wpa_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->wpa_ie, info_element,
+ network->wpa_ie_len);
+ }
+ break;
+
+ case MFIE_TYPE_RSN:
+ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n",
+ info_element->len);
+ network->rsn_ie_len = min(info_element->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(network->rsn_ie, info_element,
+ network->rsn_ie_len);
+ break;
+
+ case MFIE_TYPE_QOS_PARAMETER:
+ printk(KERN_ERR
+ "QoS Error need to parse QOS_PARAMETER IE\n");
+ break;
+ /* 802.11h */
+ case MFIE_TYPE_POWER_CONSTRAINT:
+ network->power_constraint = info_element->data[0];
+ network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
+ break;
+
+ case MFIE_TYPE_CSA:
+ network->power_constraint = info_element->data[0];
+ network->flags |= NETWORK_HAS_CSA;
+ break;
+
+ case MFIE_TYPE_QUIET:
+ network->quiet.count = info_element->data[0];
+ network->quiet.period = info_element->data[1];
+ network->quiet.duration = info_element->data[2];
+ network->quiet.offset = info_element->data[3];
+ network->flags |= NETWORK_HAS_QUIET;
+ break;
+
+ case MFIE_TYPE_IBSS_DFS:
+ if (network->ibss_dfs)
+ break;
+ network->ibss_dfs = kmemdup(info_element->data,
+ info_element->len,
+ GFP_ATOMIC);
+ if (!network->ibss_dfs)
+ return 1;
+ network->flags |= NETWORK_HAS_IBSS_DFS;
+ break;
+
+ case MFIE_TYPE_TPC_REPORT:
+ network->tpc_report.transmit_power =
+ info_element->data[0];
+ network->tpc_report.link_margin = info_element->data[1];
+ network->flags |= NETWORK_HAS_TPC_REPORT;
+ break;
+
+ default:
+ IEEE80211_DEBUG_MGMT
+ ("Unsupported info element: %s (%d)\n",
+ get_info_element_string(info_element->id),
+ info_element->id);
+ break;
+ }
+
+ length -= sizeof(*info_element) + info_element->len;
+ info_element =
+ (struct ieee80211_info_element *)&info_element->
+ data[info_element->len];
+ }
+
+ return 0;
+}
+
+static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
+ *frame, struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_network network_resp = {
+ .ibss_dfs = NULL,
+ };
+ struct ieee80211_network *network = &network_resp;
+ struct net_device *dev = ieee->dev;
+
+ network->flags = 0;
+ network->qos_data.active = 0;
+ network->qos_data.supported = 0;
+ network->qos_data.param_count = 0;
+ network->qos_data.old_param_count = 0;
+
+ //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
+ network->atim_window = le16_to_cpu(frame->aid);
+ network->listen_interval = le16_to_cpu(frame->status);
+ memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
+ network->capability = le16_to_cpu(frame->capability);
+ network->last_scanned = jiffies;
+ network->rates_len = network->rates_ex_len = 0;
+ network->last_associate = 0;
+ network->ssid_len = 0;
+ network->erp_value =
+ (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
+
+ if (stats->freq == IEEE80211_52GHZ_BAND) {
+ /* for A band (No DS info) */
+ network->channel = stats->received_channel;
+ } else
+ network->flags |= NETWORK_HAS_CCK;
+
+ network->wpa_ie_len = 0;
+ network->rsn_ie_len = 0;
+
+ if (ieee80211_parse_info_param
+ (frame->info_element, stats->len - sizeof(*frame), network))
+ return 1;
+
+ network->mode = 0;
+ if (stats->freq == IEEE80211_52GHZ_BAND)
+ network->mode = IEEE_A;
+ else {
+ if (network->flags & NETWORK_HAS_OFDM)
+ network->mode |= IEEE_G;
+ if (network->flags & NETWORK_HAS_CCK)
+ network->mode |= IEEE_B;
+ }
+
+ memcpy(&network->stats, stats, sizeof(network->stats));
+
+ if (ieee->handle_assoc_response != NULL)
+ ieee->handle_assoc_response(dev, frame, network);
+
+ return 0;
+}
+
+/***************************************************/
+
+static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
+ *beacon,
+ struct ieee80211_network *network,
+ struct ieee80211_rx_stats *stats)
+{
+ DECLARE_SSID_BUF(ssid);
+
+ network->qos_data.active = 0;
+ network->qos_data.supported = 0;
+ network->qos_data.param_count = 0;
+ network->qos_data.old_param_count = 0;
+
+ /* Pull out fixed field data */
+ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
+ network->capability = le16_to_cpu(beacon->capability);
+ network->last_scanned = jiffies;
+ network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
+ network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
+ network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
+ /* Where to pull this? beacon->listen_interval; */
+ network->listen_interval = 0x0A;
+ network->rates_len = network->rates_ex_len = 0;
+ network->last_associate = 0;
+ network->ssid_len = 0;
+ network->flags = 0;
+ network->atim_window = 0;
+ network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
+ 0x3 : 0x0;
+
+ if (stats->freq == IEEE80211_52GHZ_BAND) {
+ /* for A band (No DS info) */
+ network->channel = stats->received_channel;
+ } else
+ network->flags |= NETWORK_HAS_CCK;
+
+ network->wpa_ie_len = 0;
+ network->rsn_ie_len = 0;
+
+ if (ieee80211_parse_info_param
+ (beacon->info_element, stats->len - sizeof(*beacon), network))
+ return 1;
+
+ network->mode = 0;
+ if (stats->freq == IEEE80211_52GHZ_BAND)
+ network->mode = IEEE_A;
+ else {
+ if (network->flags & NETWORK_HAS_OFDM)
+ network->mode |= IEEE_G;
+ if (network->flags & NETWORK_HAS_CCK)
+ network->mode |= IEEE_B;
+ }
+
+ if (network->mode == 0) {
+ IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' "
+ "network.\n",
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid);
+ return 1;
+ }
+
+ memcpy(&network->stats, stats, sizeof(network->stats));
+
+ return 0;
+}
+
+static inline int is_same_network(struct ieee80211_network *src,
+ struct ieee80211_network *dst)
+{
+ /* A network is only a duplicate if the channel, BSSID, and ESSID
+ * all match. We treat all <hidden> with the same BSSID and channel
+ * as one network */
+ return ((src->ssid_len == dst->ssid_len) &&
+ (src->channel == dst->channel) &&
+ !compare_ether_addr(src->bssid, dst->bssid) &&
+ !memcmp(src->ssid, dst->ssid, src->ssid_len));
+}
+
+static void update_network(struct ieee80211_network *dst,
+ struct ieee80211_network *src)
+{
+ int qos_active;
+ u8 old_param;
+
+ ieee80211_network_reset(dst);
+ dst->ibss_dfs = src->ibss_dfs;
+
+ /* We only update the statistics if they were created by receiving
+ * the network information on the actual channel the network is on.
+ *
+ * This keeps beacons received on neighbor channels from bringing
+ * down the signal level of an AP. */
+ if (dst->channel == src->stats.received_channel)
+ memcpy(&dst->stats, &src->stats,
+ sizeof(struct ieee80211_rx_stats));
+ else
+ IEEE80211_DEBUG_SCAN("Network %pM info received "
+ "off channel (%d vs. %d)\n", src->bssid,
+ dst->channel, src->stats.received_channel);
+
+ dst->capability = src->capability;
+ memcpy(dst->rates, src->rates, src->rates_len);
+ dst->rates_len = src->rates_len;
+ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
+ dst->rates_ex_len = src->rates_ex_len;
+
+ dst->mode = src->mode;
+ dst->flags = src->flags;
+ dst->time_stamp[0] = src->time_stamp[0];
+ dst->time_stamp[1] = src->time_stamp[1];
+
+ dst->beacon_interval = src->beacon_interval;
+ dst->listen_interval = src->listen_interval;
+ dst->atim_window = src->atim_window;
+ dst->erp_value = src->erp_value;
+ dst->tim = src->tim;
+
+ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
+ dst->wpa_ie_len = src->wpa_ie_len;
+ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
+ dst->rsn_ie_len = src->rsn_ie_len;
+
+ dst->last_scanned = jiffies;
+ qos_active = src->qos_data.active;
+ old_param = dst->qos_data.old_param_count;
+ if (dst->flags & NETWORK_HAS_QOS_MASK)
+ memcpy(&dst->qos_data, &src->qos_data,
+ sizeof(struct ieee80211_qos_data));
+ else {
+ dst->qos_data.supported = src->qos_data.supported;
+ dst->qos_data.param_count = src->qos_data.param_count;
+ }
+
+ if (dst->qos_data.supported == 1) {
+ if (dst->ssid_len)
+ IEEE80211_DEBUG_QOS
+ ("QoS the network %s is QoS supported\n",
+ dst->ssid);
+ else
+ IEEE80211_DEBUG_QOS
+ ("QoS the network is QoS supported\n");
+ }
+ dst->qos_data.active = qos_active;
+ dst->qos_data.old_param_count = old_param;
+
+ /* dst->last_associate is not overwritten */
+}
+
+static inline int is_beacon(__le16 fc)
+{
+ return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
+}
+
+static void ieee80211_process_probe_response(struct ieee80211_device
+ *ieee, struct
+ ieee80211_probe_response
+ *beacon, struct ieee80211_rx_stats
+ *stats)
+{
+ struct net_device *dev = ieee->dev;
+ struct ieee80211_network network = {
+ .ibss_dfs = NULL,
+ };
+ struct ieee80211_network *target;
+ struct ieee80211_network *oldest = NULL;
+#ifdef CONFIG_IEEE80211_DEBUG
+ struct ieee80211_info_element *info_element = beacon->info_element;
+#endif
+ unsigned long flags;
+ DECLARE_SSID_BUF(ssid);
+
+ IEEE80211_DEBUG_SCAN("'%s' (%pM"
+ "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+ print_ssid(ssid, info_element->data, info_element->len),
+ beacon->header.addr3,
+ (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
+ (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
+
+ if (ieee80211_network_init(ieee, beacon, &network, stats)) {
+ IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
+ print_ssid(ssid, info_element->data,
+ info_element->len),
+ beacon->header.addr3,
+ is_beacon(beacon->header.frame_ctl) ?
+ "BEACON" : "PROBE RESPONSE");
+ return;
+ }
+
+ /* The network parsed correctly -- so now we scan our known networks
+ * to see if we can find it in our list.
+ *
+ * NOTE: This search is definitely not optimized. Once its doing
+ * the "right thing" we'll optimize it for efficiency if
+ * necessary */
+
+ /* Search for this entry in the list and update it if it is
+ * already there. */
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ list_for_each_entry(target, &ieee->network_list, list) {
+ if (is_same_network(target, &network))
+ break;
+
+ if ((oldest == NULL) ||
+ (target->last_scanned < oldest->last_scanned))
+ oldest = target;
+ }
+
+ /* If we didn't find a match, then get a new network slot to initialize
+ * with this beacon's information */
+ if (&target->list == &ieee->network_list) {
+ if (list_empty(&ieee->network_free_list)) {
+ /* If there are no more slots, expire the oldest */
+ list_del(&oldest->list);
+ target = oldest;
+ IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from "
+ "network list.\n",
+ print_ssid(ssid, target->ssid,
+ target->ssid_len),
+ target->bssid);
+ ieee80211_network_reset(target);
+ } else {
+ /* Otherwise just pull from the free list */
+ target = list_entry(ieee->network_free_list.next,
+ struct ieee80211_network, list);
+ list_del(ieee->network_free_list.next);
+ }
+
+#ifdef CONFIG_IEEE80211_DEBUG
+ IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
+ print_ssid(ssid, network.ssid,
+ network.ssid_len),
+ network.bssid,
+ is_beacon(beacon->header.frame_ctl) ?
+ "BEACON" : "PROBE RESPONSE");
+#endif
+ memcpy(target, &network, sizeof(*target));
+ network.ibss_dfs = NULL;
+ list_add_tail(&target->list, &ieee->network_list);
+ } else {
+ IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
+ print_ssid(ssid, target->ssid,
+ target->ssid_len),
+ target->bssid,
+ is_beacon(beacon->header.frame_ctl) ?
+ "BEACON" : "PROBE RESPONSE");
+ update_network(target, &network);
+ network.ibss_dfs = NULL;
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ if (is_beacon(beacon->header.frame_ctl)) {
+ if (ieee->handle_beacon != NULL)
+ ieee->handle_beacon(dev, beacon, target);
+ } else {
+ if (ieee->handle_probe_response != NULL)
+ ieee->handle_probe_response(dev, beacon, target);
+ }
+}
+
+void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *header,
+ struct ieee80211_rx_stats *stats)
+{
+ switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
+ case IEEE80211_STYPE_ASSOC_RESP:
+ IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ ieee80211_handle_assoc_resp(ieee,
+ (struct ieee80211_assoc_response *)
+ header, stats);
+ break;
+
+ case IEEE80211_STYPE_REASSOC_RESP:
+ IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+ IEEE80211_DEBUG_MGMT("received auth (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+
+ if (ieee->handle_probe_request != NULL)
+ ieee->handle_probe_request(ieee->dev,
+ (struct
+ ieee80211_probe_request *)
+ header, stats);
+ break;
+
+ case IEEE80211_STYPE_PROBE_RESP:
+ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ IEEE80211_DEBUG_SCAN("Probe response\n");
+ ieee80211_process_probe_response(ieee,
+ (struct
+ ieee80211_probe_response *)
+ header, stats);
+ break;
+
+ case IEEE80211_STYPE_BEACON:
+ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ IEEE80211_DEBUG_SCAN("Beacon\n");
+ ieee80211_process_probe_response(ieee,
+ (struct
+ ieee80211_probe_response *)
+ header, stats);
+ break;
+ case IEEE80211_STYPE_AUTH:
+
+ IEEE80211_DEBUG_MGMT("received auth (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+
+ if (ieee->handle_auth != NULL)
+ ieee->handle_auth(ieee->dev,
+ (struct ieee80211_auth *)header);
+ break;
+
+ case IEEE80211_STYPE_DISASSOC:
+ if (ieee->handle_disassoc != NULL)
+ ieee->handle_disassoc(ieee->dev,
+ (struct ieee80211_disassoc *)
+ header);
+ break;
+
+ case IEEE80211_STYPE_ACTION:
+ IEEE80211_DEBUG_MGMT("ACTION\n");
+ if (ieee->handle_action)
+ ieee->handle_action(ieee->dev,
+ (struct ieee80211_action *)
+ header, stats);
+ break;
+
+ case IEEE80211_STYPE_REASSOC_REQ:
+ IEEE80211_DEBUG_MGMT("received reassoc (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+
+ IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n",
+ ieee->dev->name);
+ if (ieee->handle_reassoc_request != NULL)
+ ieee->handle_reassoc_request(ieee->dev,
+ (struct ieee80211_reassoc_request *)
+ header);
+ break;
+
+ case IEEE80211_STYPE_ASSOC_REQ:
+ IEEE80211_DEBUG_MGMT("received assoc (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+
+ IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n",
+ ieee->dev->name);
+ if (ieee->handle_assoc_request != NULL)
+ ieee->handle_assoc_request(ieee->dev);
+ break;
+
+ case IEEE80211_STYPE_DEAUTH:
+ IEEE80211_DEBUG_MGMT("DEAUTH\n");
+ if (ieee->handle_deauth != NULL)
+ ieee->handle_deauth(ieee->dev,
+ (struct ieee80211_deauth *)
+ header);
+ break;
+ default:
+ IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n",
+ ieee->dev->name,
+ WLAN_FC_GET_STYPE(le16_to_cpu
+ (header->frame_ctl)));
+ break;
+ }
+}
+
+EXPORT_SYMBOL_GPL(ieee80211_rx_any);
+EXPORT_SYMBOL(ieee80211_rx_mgt);
+EXPORT_SYMBOL(ieee80211_rx);
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
new file mode 100644
index 00000000000..f78f57e8844
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -0,0 +1,546 @@
+/******************************************************************************
+
+ Copyright(c) 2003 - 2005 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., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/wireless.h>
+#include <linux/etherdevice.h>
+#include <asm/uaccess.h>
+
+#include <net/ieee80211.h>
+
+/*
+
+802.11 Data Frame
+
+ ,-------------------------------------------------------------------.
+Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
+ |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
+ | | tion | (BSSID) | | | ence | data | |
+ `--------------------------------------------------| |------'
+Total: 28 non-data bytes `----.----'
+ |
+ .- 'Frame data' expands, if WEP enabled, to <----------'
+ |
+ V
+ ,-----------------------.
+Bytes | 4 | 0-2296 | 4 |
+ |-----|-----------|-----|
+Desc. | IV | Encrypted | ICV |
+ | | Packet | |
+ `-----| |-----'
+ `-----.-----'
+ |
+ .- 'Encrypted Packet' expands to
+ |
+ V
+ ,---------------------------------------------------.
+Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
+ |------|------|---------|----------|------|---------|
+Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
+ | DSAP | SSAP | | | | Packet |
+ | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
+ `----------------------------------------------------
+Total: 8 non-data bytes
+
+802.3 Ethernet Data Frame
+
+ ,-----------------------------------------.
+Bytes | 6 | 6 | 2 | Variable | 4 |
+ |-------|-------|------|-----------|------|
+Desc. | Dest. | Source| Type | IP Packet | fcs |
+ | MAC | MAC | | | |
+ `-----------------------------------------'
+Total: 18 non-data bytes
+
+In the event that fragmentation is required, the incoming payload is split into
+N parts of size ieee->fts. The first fragment contains the SNAP header and the
+remaining packets are just data.
+
+If encryption is enabled, each fragment payload size is reduced by enough space
+to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
+So if you have 1500 bytes of payload with ieee->fts set to 500 without
+encryption it will take 3 frames. With WEP it will take 4 frames as the
+payload of each frame is reduced to 492 bytes.
+
+* SKB visualization
+*
+* ,- skb->data
+* |
+* | ETHERNET HEADER ,-<-- PAYLOAD
+* | | 14 bytes from skb->data
+* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
+* | | | |
+* |,-Dest.--. ,--Src.---. | | |
+* | 6 bytes| | 6 bytes | | | |
+* v | | | | | |
+* 0 | v 1 | v | v 2
+* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+* ^ | ^ | ^ |
+* | | | | | |
+* | | | | `T' <---- 2 bytes for Type
+* | | | |
+* | | '---SNAP--' <-------- 6 bytes for SNAP
+* | |
+* `-IV--' <-------------------- 4 bytes for IV (WEP)
+*
+* SNAP HEADER
+*
+*/
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static int ieee80211_copy_snap(u8 * data, __be16 h_proto)
+{
+ struct ieee80211_snap_hdr *snap;
+ u8 *oui;
+
+ snap = (struct ieee80211_snap_hdr *)data;
+ snap->dsap = 0xaa;
+ snap->ssap = 0xaa;
+ snap->ctrl = 0x03;
+
+ if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX))
+ oui = P802_1H_OUI;
+ else
+ oui = RFC1042_OUI;
+ snap->oui[0] = oui[0];
+ snap->oui[1] = oui[1];
+ snap->oui[2] = oui[2];
+
+ memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16));
+
+ return SNAP_SIZE + sizeof(u16);
+}
+
+static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+ struct sk_buff *frag, int hdr_len)
+{
+ struct lib80211_crypt_data *crypt =
+ ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
+ int res;
+
+ if (crypt == NULL)
+ return -1;
+
+ /* To encrypt, frame format is:
+ * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
+ atomic_inc(&crypt->refcnt);
+ res = 0;
+ if (crypt->ops && crypt->ops->encrypt_mpdu)
+ res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
+
+ atomic_dec(&crypt->refcnt);
+ if (res < 0) {
+ printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
+ ieee->dev->name, frag->len);
+ ieee->ieee_stats.tx_discards++;
+ return -1;
+ }
+
+ return 0;
+}
+
+void ieee80211_txb_free(struct ieee80211_txb *txb)
+{
+ int i;
+ if (unlikely(!txb))
+ return;
+ for (i = 0; i < txb->nr_frags; i++)
+ if (txb->fragments[i])
+ dev_kfree_skb_any(txb->fragments[i]);
+ kfree(txb);
+}
+
+static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
+ int headroom, gfp_t gfp_mask)
+{
+ struct ieee80211_txb *txb;
+ int i;
+ txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
+ gfp_mask);
+ if (!txb)
+ return NULL;
+
+ memset(txb, 0, sizeof(struct ieee80211_txb));
+ txb->nr_frags = nr_frags;
+ txb->frag_size = txb_size;
+
+ for (i = 0; i < nr_frags; i++) {
+ txb->fragments[i] = __dev_alloc_skb(txb_size + headroom,
+ gfp_mask);
+ if (unlikely(!txb->fragments[i])) {
+ i--;
+ break;
+ }
+ skb_reserve(txb->fragments[i], headroom);
+ }
+ if (unlikely(i != nr_frags)) {
+ while (i >= 0)
+ dev_kfree_skb_any(txb->fragments[i--]);
+ kfree(txb);
+ return NULL;
+ }
+ return txb;
+}
+
+static int ieee80211_classify(struct sk_buff *skb)
+{
+ struct ethhdr *eth;
+ struct iphdr *ip;
+
+ eth = (struct ethhdr *)skb->data;
+ if (eth->h_proto != htons(ETH_P_IP))
+ return 0;
+
+ ip = ip_hdr(skb);
+ switch (ip->tos & 0xfc) {
+ case 0x20:
+ return 2;
+ case 0x40:
+ return 1;
+ case 0x60:
+ return 3;
+ case 0x80:
+ return 4;
+ case 0xa0:
+ return 5;
+ case 0xc0:
+ return 6;
+ case 0xe0:
+ return 7;
+ default:
+ return 0;
+ }
+}
+
+/* Incoming skb is converted to a txb which consists of
+ * a block of 802.11 fragment packets (stored as skbs) */
+int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_device *ieee = netdev_priv(dev);
+ struct ieee80211_txb *txb = NULL;
+ struct ieee80211_hdr_3addrqos *frag_hdr;
+ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
+ rts_required;
+ unsigned long flags;
+ struct net_device_stats *stats = &ieee->stats;
+ int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
+ __be16 ether_type;
+ int bytes, fc, hdr_len;
+ struct sk_buff *skb_frag;
+ struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */
+ .duration_id = 0,
+ .seq_ctl = 0,
+ .qos_ctl = 0
+ };
+ u8 dest[ETH_ALEN], src[ETH_ALEN];
+ struct lib80211_crypt_data *crypt;
+ int priority = skb->priority;
+ int snapped = 0;
+
+ if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
+ return NETDEV_TX_BUSY;
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ /* If there is no driver handler to take the TXB, dont' bother
+ * creating it... */
+ if (!ieee->hard_start_xmit) {
+ printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
+ goto success;
+ }
+
+ if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
+ printk(KERN_WARNING "%s: skb too small (%d).\n",
+ ieee->dev->name, skb->len);
+ goto success;
+ }
+
+ ether_type = ((struct ethhdr *)skb->data)->h_proto;
+
+ crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
+
+ encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
+ ieee->sec.encrypt;
+
+ host_encrypt = ieee->host_encrypt && encrypt && crypt;
+ host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
+ host_build_iv = ieee->host_build_iv && encrypt && crypt;
+
+ if (!encrypt && ieee->ieee802_1x &&
+ ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
+ stats->tx_dropped++;
+ goto success;
+ }
+
+ /* Save source and destination addresses */
+ skb_copy_from_linear_data(skb, dest, ETH_ALEN);
+ skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
+
+ if (host_encrypt || host_build_iv)
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
+ IEEE80211_FCTL_PROTECTED;
+ else
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+ if (ieee->iw_mode == IW_MODE_INFRA) {
+ fc |= IEEE80211_FCTL_TODS;
+ /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
+ memcpy(header.addr1, ieee->bssid, ETH_ALEN);
+ memcpy(header.addr2, src, ETH_ALEN);
+ memcpy(header.addr3, dest, ETH_ALEN);
+ } else if (ieee->iw_mode == IW_MODE_ADHOC) {
+ /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
+ memcpy(header.addr1, dest, ETH_ALEN);
+ memcpy(header.addr2, src, ETH_ALEN);
+ memcpy(header.addr3, ieee->bssid, ETH_ALEN);
+ }
+ hdr_len = IEEE80211_3ADDR_LEN;
+
+ if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
+ fc |= IEEE80211_STYPE_QOS_DATA;
+ hdr_len += 2;
+
+ skb->priority = ieee80211_classify(skb);
+ header.qos_ctl |= cpu_to_le16(skb->priority & IEEE80211_QCTL_TID);
+ }
+ header.frame_ctl = cpu_to_le16(fc);
+
+ /* Advance the SKB to the start of the payload */
+ skb_pull(skb, sizeof(struct ethhdr));
+
+ /* Determine total amount of storage required for TXB packets */
+ bytes = skb->len + SNAP_SIZE + sizeof(u16);
+
+ /* Encrypt msdu first on the whole data packet. */
+ if ((host_encrypt || host_encrypt_msdu) &&
+ crypt && crypt->ops && crypt->ops->encrypt_msdu) {
+ int res = 0;
+ int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
+ crypt->ops->extra_msdu_postfix_len;
+ struct sk_buff *skb_new = dev_alloc_skb(len);
+
+ if (unlikely(!skb_new))
+ goto failed;
+
+ skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
+ memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
+ snapped = 1;
+ ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
+ ether_type);
+ skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
+ res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
+ if (res < 0) {
+ IEEE80211_ERROR("msdu encryption failed\n");
+ dev_kfree_skb_any(skb_new);
+ goto failed;
+ }
+ dev_kfree_skb_any(skb);
+ skb = skb_new;
+ bytes += crypt->ops->extra_msdu_prefix_len +
+ crypt->ops->extra_msdu_postfix_len;
+ skb_pull(skb, hdr_len);
+ }
+
+ if (host_encrypt || ieee->host_open_frag) {
+ /* Determine fragmentation size based on destination (multicast
+ * and broadcast are not fragmented) */
+ if (is_multicast_ether_addr(dest) ||
+ is_broadcast_ether_addr(dest))
+ frag_size = MAX_FRAG_THRESHOLD;
+ else
+ frag_size = ieee->fts;
+
+ /* Determine amount of payload per fragment. Regardless of if
+ * this stack is providing the full 802.11 header, one will
+ * eventually be affixed to this fragment -- so we must account
+ * for it when determining the amount of payload space. */
+ bytes_per_frag = frag_size - hdr_len;
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ bytes_per_frag -= IEEE80211_FCS_LEN;
+
+ /* Each fragment may need to have room for encryptiong
+ * pre/postfix */
+ if (host_encrypt)
+ bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
+ crypt->ops->extra_mpdu_postfix_len;
+
+ /* Number of fragments is the total
+ * bytes_per_frag / payload_per_fragment */
+ nr_frags = bytes / bytes_per_frag;
+ bytes_last_frag = bytes % bytes_per_frag;
+ if (bytes_last_frag)
+ nr_frags++;
+ else
+ bytes_last_frag = bytes_per_frag;
+ } else {
+ nr_frags = 1;
+ bytes_per_frag = bytes_last_frag = bytes;
+ frag_size = bytes + hdr_len;
+ }
+
+ rts_required = (frag_size > ieee->rts
+ && ieee->config & CFG_IEEE80211_RTS);
+ if (rts_required)
+ nr_frags++;
+
+ /* When we allocate the TXB we allocate enough space for the reserve
+ * and full fragment bytes (bytes_per_frag doesn't include prefix,
+ * postfix, header, FCS, etc.) */
+ txb = ieee80211_alloc_txb(nr_frags, frag_size,
+ ieee->tx_headroom, GFP_ATOMIC);
+ if (unlikely(!txb)) {
+ printk(KERN_WARNING "%s: Could not allocate TXB\n",
+ ieee->dev->name);
+ goto failed;
+ }
+ txb->encrypted = encrypt;
+ if (host_encrypt)
+ txb->payload_size = frag_size * (nr_frags - 1) +
+ bytes_last_frag;
+ else
+ txb->payload_size = bytes;
+
+ if (rts_required) {
+ skb_frag = txb->fragments[0];
+ frag_hdr =
+ (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
+
+ /*
+ * Set header frame_ctl to the RTS.
+ */
+ header.frame_ctl =
+ cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
+ memcpy(frag_hdr, &header, hdr_len);
+
+ /*
+ * Restore header frame_ctl to the original data setting.
+ */
+ header.frame_ctl = cpu_to_le16(fc);
+
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ skb_put(skb_frag, 4);
+
+ txb->rts_included = 1;
+ i = 1;
+ } else
+ i = 0;
+
+ for (; i < nr_frags; i++) {
+ skb_frag = txb->fragments[i];
+
+ if (host_encrypt || host_build_iv)
+ skb_reserve(skb_frag,
+ crypt->ops->extra_mpdu_prefix_len);
+
+ frag_hdr =
+ (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len);
+ memcpy(frag_hdr, &header, hdr_len);
+
+ /* If this is not the last fragment, then add the MOREFRAGS
+ * bit to the frame control */
+ if (i != nr_frags - 1) {
+ frag_hdr->frame_ctl =
+ cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
+ bytes = bytes_per_frag;
+ } else {
+ /* The last fragment takes the remaining length */
+ bytes = bytes_last_frag;
+ }
+
+ if (i == 0 && !snapped) {
+ ieee80211_copy_snap(skb_put
+ (skb_frag, SNAP_SIZE + sizeof(u16)),
+ ether_type);
+ bytes -= SNAP_SIZE + sizeof(u16);
+ }
+
+ skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
+
+ /* Advance the SKB... */
+ skb_pull(skb, bytes);
+
+ /* Encryption routine will move the header forward in order
+ * to insert the IV between the header and the payload */
+ if (host_encrypt)
+ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
+ else if (host_build_iv) {
+ atomic_inc(&crypt->refcnt);
+ if (crypt->ops->build_iv)
+ crypt->ops->build_iv(skb_frag, hdr_len,
+ ieee->sec.keys[ieee->sec.active_key],
+ ieee->sec.key_sizes[ieee->sec.active_key],
+ crypt->priv);
+ atomic_dec(&crypt->refcnt);
+ }
+
+ if (ieee->config &
+ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
+ skb_put(skb_frag, 4);
+ }
+
+ success:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ dev_kfree_skb_any(skb);
+
+ if (txb) {
+ int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
+ if (ret == 0) {
+ stats->tx_packets++;
+ stats->tx_bytes += txb->payload_size;
+ return 0;
+ }
+
+ ieee80211_txb_free(txb);
+ }
+
+ return 0;
+
+ failed:
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ netif_stop_queue(dev);
+ stats->tx_errors++;
+ return 1;
+}
+
+EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
new file mode 100644
index 00000000000..31ea3abfc32
--- /dev/null
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -0,0 +1,760 @@
+/******************************************************************************
+
+ Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
+
+ Portions of this file are based on the WEP enablement code provided by the
+ Host AP project hostap-drivers v0.1.3
+ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+
+ 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., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The full GNU General Public License is included in this distribution in the
+ file called LICENSE.
+
+ Contact Information:
+ James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+
+#include <net/lib80211.h>
+#include <net/ieee80211.h>
+#include <linux/wireless.h>
+
+static const char *ieee80211_modes[] = {
+ "?", "a", "b", "ab", "g", "ag", "bg", "abg"
+};
+
+#define MAX_CUSTOM_LEN 64
+static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
+ char *start, char *stop,
+ struct ieee80211_network *network,
+ struct iw_request_info *info)
+{
+ char custom[MAX_CUSTOM_LEN];
+ char *p;
+ struct iw_event iwe;
+ int i, j;
+ char *current_val; /* For rates */
+ u8 rate;
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
+
+ /* Remaining entries will be displayed in the order we provide them */
+
+ /* Add the ESSID */
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ iwe.u.data.length = min(network->ssid_len, (u8) 32);
+ start = iwe_stream_add_point(info, start, stop,
+ &iwe, network->ssid);
+
+ /* Add the protocol name */
+ iwe.cmd = SIOCGIWNAME;
+ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
+ ieee80211_modes[network->mode]);
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ if (network->capability & WLAN_CAPABILITY_ESS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+
+ start = iwe_stream_add_event(info, start, stop,
+ &iwe, IW_EV_UINT_LEN);
+ }
+
+ /* Add channel and frequency */
+ /* Note : userspace automatically computes channel using iwrange */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+ iwe.u.freq.e = 6;
+ iwe.u.freq.i = 0;
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (network->capability & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ start = iwe_stream_add_point(info, start, stop,
+ &iwe, network->ssid);
+
+ /* Add basic and extended rates */
+ /* Rate : stuffing multiple values in a single event require a bit
+ * more of magic - Jean II */
+ current_val = start + iwe_stream_lcp_len(info);
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+ for (i = 0, j = 0; i < network->rates_len;) {
+ if (j < network->rates_ex_len &&
+ ((network->rates_ex[j] & 0x7F) <
+ (network->rates[i] & 0x7F)))
+ rate = network->rates_ex[j++] & 0x7F;
+ else
+ rate = network->rates[i++] & 0x7F;
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
+ /* Add new value to event */
+ current_val = iwe_stream_add_value(info, start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+ }
+ for (; j < network->rates_ex_len; j++) {
+ rate = network->rates_ex[j] & 0x7F;
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
+ /* Add new value to event */
+ current_val = iwe_stream_add_value(info, start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+ }
+ /* Check if we added any rate */
+ if ((current_val - start) > iwe_stream_lcp_len(info))
+ start = current_val;
+
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
+ IW_QUAL_NOISE_UPDATED;
+
+ if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
+ iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
+ IW_QUAL_LEVEL_INVALID;
+ iwe.u.qual.qual = 0;
+ } else {
+ if (ieee->perfect_rssi == ieee->worst_rssi)
+ iwe.u.qual.qual = 100;
+ else
+ iwe.u.qual.qual =
+ (100 *
+ (ieee->perfect_rssi - ieee->worst_rssi) *
+ (ieee->perfect_rssi - ieee->worst_rssi) -
+ (ieee->perfect_rssi - network->stats.rssi) *
+ (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
+ 62 * (ieee->perfect_rssi -
+ network->stats.rssi))) /
+ ((ieee->perfect_rssi -
+ ieee->worst_rssi) * (ieee->perfect_rssi -
+ ieee->worst_rssi));
+ if (iwe.u.qual.qual > 100)
+ iwe.u.qual.qual = 100;
+ else if (iwe.u.qual.qual < 1)
+ iwe.u.qual.qual = 0;
+ }
+
+ if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
+ iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
+ iwe.u.qual.noise = 0;
+ } else {
+ iwe.u.qual.noise = network->stats.noise;
+ }
+
+ if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
+ iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
+ iwe.u.qual.level = 0;
+ } else {
+ iwe.u.qual.level = network->stats.signal;
+ }
+
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
+
+ iwe.cmd = IWEVCUSTOM;
+ p = custom;
+
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(info, start, stop, &iwe, custom);
+
+ memset(&iwe, 0, sizeof(iwe));
+ if (network->wpa_ie_len) {
+ char buf[MAX_WPA_IE_LEN];
+ memcpy(buf, network->wpa_ie, network->wpa_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = network->wpa_ie_len;
+ start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ if (network->rsn_ie_len) {
+ char buf[MAX_WPA_IE_LEN];
+ memcpy(buf, network->rsn_ie, network->rsn_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = network->rsn_ie_len;
+ start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+ }
+
+ /* Add EXTRA: Age to display seconds since last beacon/probe response
+ * for given network. */
+ iwe.cmd = IWEVCUSTOM;
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ " Last beacon: %dms ago",
+ jiffies_to_msecs(jiffies - network->last_scanned));
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(info, start, stop, &iwe, custom);
+
+ /* Add spectrum management information */
+ iwe.cmd = -1;
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
+
+ if (ieee80211_get_channel_flags(ieee, network->channel) &
+ IEEE80211_CH_INVALID) {
+ iwe.cmd = IWEVCUSTOM;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
+ }
+
+ if (ieee80211_get_channel_flags(ieee, network->channel) &
+ IEEE80211_CH_RADAR_DETECT) {
+ iwe.cmd = IWEVCUSTOM;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
+ }
+
+ if (iwe.cmd == IWEVCUSTOM) {
+ iwe.u.data.length = p - custom;
+ start = iwe_stream_add_point(info, start, stop, &iwe, custom);
+ }
+
+ return start;
+}
+
+#define SCAN_ITEM_SIZE 128
+
+int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ieee80211_network *network;
+ unsigned long flags;
+ int err = 0;
+
+ char *ev = extra;
+ char *stop = ev + wrqu->data.length;
+ int i = 0;
+ DECLARE_SSID_BUF(ssid);
+
+ IEEE80211_DEBUG_WX("Getting scan\n");
+
+ spin_lock_irqsave(&ieee->lock, flags);
+
+ list_for_each_entry(network, &ieee->network_list, list) {
+ i++;
+ if (stop - ev < SCAN_ITEM_SIZE) {
+ err = -E2BIG;
+ break;
+ }
+
+ if (ieee->scan_age == 0 ||
+ time_after(network->last_scanned + ieee->scan_age, jiffies))
+ ev = ieee80211_translate_scan(ieee, ev, stop, network,
+ info);
+ else
+ IEEE80211_DEBUG_SCAN("Not showing network '%s ("
+ "%pM)' due to age (%dms).\n",
+ print_ssid(ssid, network->ssid,
+ network->ssid_len),
+ network->bssid,
+ jiffies_to_msecs(jiffies -
+ network->
+ last_scanned));
+ }
+
+ spin_unlock_irqrestore(&ieee->lock, flags);
+
+ wrqu->data.length = ev - extra;
+ wrqu->data.flags = 0;
+
+ IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
+
+ return err;
+}
+
+int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ struct iw_point *erq = &(wrqu->encoding);
+ struct net_device *dev = ieee->dev;
+ struct ieee80211_security sec = {
+ .flags = 0
+ };
+ int i, key, key_provided, len;
+ struct lib80211_crypt_data **crypt;
+ int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
+ DECLARE_SSID_BUF(ssid);
+
+ IEEE80211_DEBUG_WX("SET_ENCODE\n");
+
+ key = erq->flags & IW_ENCODE_INDEX;
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ key_provided = 1;
+ } else {
+ key_provided = 0;
+ key = ieee->crypt_info.tx_keyidx;
+ }
+
+ IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
+ "provided" : "default");
+
+ crypt = &ieee->crypt_info.crypt[key];
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ if (key_provided && *crypt) {
+ IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
+ key);
+ lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ } else
+ IEEE80211_DEBUG_WX("Disabling encryption.\n");
+
+ /* Check all the keys to see if any are still configured,
+ * and if no key index was provided, de-init them all */
+ for (i = 0; i < WEP_KEYS; i++) {
+ if (ieee->crypt_info.crypt[i] != NULL) {
+ if (key_provided)
+ break;
+ lib80211_crypt_delayed_deinit(&ieee->crypt_info,
+ &ieee->crypt_info.crypt[i]);
+ }
+ }
+
+ if (i == WEP_KEYS) {
+ sec.enabled = 0;
+ sec.encrypt = 0;
+ sec.level = SEC_LEVEL_0;
+ sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
+ }
+
+ goto done;
+ }
+
+ sec.enabled = 1;
+ sec.encrypt = 1;
+ sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
+
+ if (*crypt != NULL && (*crypt)->ops != NULL &&
+ strcmp((*crypt)->ops->name, "WEP") != 0) {
+ /* changing to use WEP; deinit previously used algorithm
+ * on this key */
+ lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ }
+
+ if (*crypt == NULL && host_crypto) {
+ struct lib80211_crypt_data *new_crypt;
+
+ /* take WEP into use */
+ new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
+ GFP_KERNEL);
+ if (new_crypt == NULL)
+ return -ENOMEM;
+ new_crypt->ops = lib80211_get_crypto_ops("WEP");
+ if (!new_crypt->ops) {
+ request_module("lib80211_crypt_wep");
+ new_crypt->ops = lib80211_get_crypto_ops("WEP");
+ }
+
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv = new_crypt->ops->init(key);
+
+ if (!new_crypt->ops || !new_crypt->priv) {
+ kfree(new_crypt);
+ new_crypt = NULL;
+
+ printk(KERN_WARNING "%s: could not initialize WEP: "
+ "load module lib80211_crypt_wep\n", dev->name);
+ return -EOPNOTSUPP;
+ }
+ *crypt = new_crypt;
+ }
+
+ /* If a new key was provided, set it up */
+ if (erq->length > 0) {
+#ifdef CONFIG_IEEE80211_DEBUG
+ DECLARE_SSID_BUF(ssid);
+#endif
+
+ len = erq->length <= 5 ? 5 : 13;
+ memcpy(sec.keys[key], keybuf, erq->length);
+ if (len > erq->length)
+ memset(sec.keys[key] + erq->length, 0,
+ len - erq->length);
+ IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
+ key, print_ssid(ssid, sec.keys[key], len),
+ erq->length, len);
+ sec.key_sizes[key] = len;
+ if (*crypt)
+ (*crypt)->ops->set_key(sec.keys[key], len, NULL,
+ (*crypt)->priv);
+ sec.flags |= (1 << key);
+ /* This ensures a key will be activated if no key is
+ * explicitly set */
+ if (key == sec.active_key)
+ sec.flags |= SEC_ACTIVE_KEY;
+
+ } else {
+ if (host_crypto) {
+ len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
+ NULL, (*crypt)->priv);
+ if (len == 0) {
+ /* Set a default key of all 0 */
+ IEEE80211_DEBUG_WX("Setting key %d to all "
+ "zero.\n", key);
+ memset(sec.keys[key], 0, 13);
+ (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
+ (*crypt)->priv);
+ sec.key_sizes[key] = 13;
+ sec.flags |= (1 << key);
+ }
+ }
+ /* No key data - just set the default TX key index */
+ if (key_provided) {
+ IEEE80211_DEBUG_WX("Setting key %d to default Tx "
+ "key.\n", key);
+ ieee->crypt_info.tx_keyidx = key;
+ sec.active_key = key;
+ sec.flags |= SEC_ACTIVE_KEY;
+ }
+ }
+ if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
+ ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
+ sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
+ WLAN_AUTH_SHARED_KEY;
+ sec.flags |= SEC_AUTH_MODE;
+ IEEE80211_DEBUG_WX("Auth: %s\n",
+ sec.auth_mode == WLAN_AUTH_OPEN ?
+ "OPEN" : "SHARED KEY");
+ }
+
+ /* For now we just support WEP, so only set that security level...
+ * TODO: When WPA is added this is one place that needs to change */
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
+ sec.encode_alg[key] = SEC_ALG_WEP;
+
+ done:
+ if (ieee->set_security)
+ ieee->set_security(dev, &sec);
+
+ /* Do not reset port if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. If your hardware requires a reset after WEP
+ * configuration (for example... Prism2), implement the reset_port in
+ * the callbacks structures used to initialize the 802.11 stack. */
+ if (ieee->reset_on_keychange &&
+ ieee->iw_mode != IW_MODE_INFRA &&
+ ieee->reset_port && ieee->reset_port(dev)) {
+ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ struct iw_point *erq = &(wrqu->encoding);
+ int len, key;
+ struct lib80211_crypt_data *crypt;
+ struct ieee80211_security *sec = &ieee->sec;
+
+ IEEE80211_DEBUG_WX("GET_ENCODE\n");
+
+ key = erq->flags & IW_ENCODE_INDEX;
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ } else
+ key = ieee->crypt_info.tx_keyidx;
+
+ crypt = ieee->crypt_info.crypt[key];
+ erq->flags = key + 1;
+
+ if (!sec->enabled) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+
+ len = sec->key_sizes[key];
+ memcpy(keybuf, sec->keys[key], len);
+
+ erq->length = len;
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ if (ieee->open_wep)
+ erq->flags |= IW_ENCODE_OPEN;
+ else
+ erq->flags |= IW_ENCODE_RESTRICTED;
+
+ return 0;
+}
+
+int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct net_device *dev = ieee->dev;
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int i, idx, ret = 0;
+ int group_key = 0;
+ const char *alg, *module;
+ struct lib80211_crypto_ops *ops;
+ struct lib80211_crypt_data **crypt;
+
+ struct ieee80211_security sec = {
+ .flags = 0,
+ };
+
+ idx = encoding->flags & IW_ENCODE_INDEX;
+ if (idx) {
+ if (idx < 1 || idx > WEP_KEYS)
+ return -EINVAL;
+ idx--;
+ } else
+ idx = ieee->crypt_info.tx_keyidx;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ crypt = &ieee->crypt_info.crypt[idx];
+ group_key = 1;
+ } else {
+ /* some Cisco APs use idx>0 for unicast in dynamic WEP */
+ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
+ return -EINVAL;
+ if (ieee->iw_mode == IW_MODE_INFRA)
+ crypt = &ieee->crypt_info.crypt[idx];
+ else
+ return -EINVAL;
+ }
+
+ sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
+ if ((encoding->flags & IW_ENCODE_DISABLED) ||
+ ext->alg == IW_ENCODE_ALG_NONE) {
+ if (*crypt)
+ lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+
+ for (i = 0; i < WEP_KEYS; i++)
+ if (ieee->crypt_info.crypt[i] != NULL)
+ break;
+
+ if (i == WEP_KEYS) {
+ sec.enabled = 0;
+ sec.encrypt = 0;
+ sec.level = SEC_LEVEL_0;
+ sec.flags |= SEC_LEVEL;
+ }
+ goto done;
+ }
+
+ sec.enabled = 1;
+ sec.encrypt = 1;
+
+ if (group_key ? !ieee->host_mc_decrypt :
+ !(ieee->host_encrypt || ieee->host_decrypt ||
+ ieee->host_encrypt_msdu))
+ goto skip_host_crypt;
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_WEP:
+ alg = "WEP";
+ module = "lib80211_crypt_wep";
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ alg = "TKIP";
+ module = "lib80211_crypt_tkip";
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ alg = "CCMP";
+ module = "lib80211_crypt_ccmp";
+ break;
+ default:
+ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
+ dev->name, ext->alg);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ops = lib80211_get_crypto_ops(alg);
+ if (ops == NULL) {
+ request_module(module);
+ ops = lib80211_get_crypto_ops(alg);
+ }
+ if (ops == NULL) {
+ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
+ dev->name, ext->alg);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (*crypt == NULL || (*crypt)->ops != ops) {
+ struct lib80211_crypt_data *new_crypt;
+
+ lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+
+ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
+ if (new_crypt == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ new_crypt->ops = ops;
+ if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
+ new_crypt->priv = new_crypt->ops->init(idx);
+ if (new_crypt->priv == NULL) {
+ kfree(new_crypt);
+ ret = -EINVAL;
+ goto done;
+ }
+ *crypt = new_crypt;
+ }
+
+ if (ext->key_len > 0 && (*crypt)->ops->set_key &&
+ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
+ (*crypt)->priv) < 0) {
+ IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ skip_host_crypt:
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ ieee->crypt_info.tx_keyidx = idx;
+ sec.active_key = idx;
+ sec.flags |= SEC_ACTIVE_KEY;
+ }
+
+ if (ext->alg != IW_ENCODE_ALG_NONE) {
+ memcpy(sec.keys[idx], ext->key, ext->key_len);
+ sec.key_sizes[idx] = ext->key_len;
+ sec.flags |= (1 << idx);
+ if (ext->alg == IW_ENCODE_ALG_WEP) {
+ sec.encode_alg[idx] = SEC_ALG_WEP;
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
+ sec.encode_alg[idx] = SEC_ALG_TKIP;
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_2;
+ } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
+ sec.encode_alg[idx] = SEC_ALG_CCMP;
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_3;
+ }
+ /* Don't set sec level for group keys. */
+ if (group_key)
+ sec.flags &= ~SEC_LEVEL;
+ }
+ done:
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+
+ /*
+ * Do not reset port if card is in Managed mode since resetting will
+ * generate new IEEE 802.11 authentication which may end up in looping
+ * with IEEE 802.1X. If your hardware requires a reset after WEP
+ * configuration (for example... Prism2), implement the reset_port in
+ * the callbacks structures used to initialize the 802.11 stack.
+ */
+ if (ieee->reset_on_keychange &&
+ ieee->iw_mode != IW_MODE_INFRA &&
+ ieee->reset_port && ieee->reset_port(dev)) {
+ IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ struct ieee80211_security *sec = &ieee->sec;
+ int idx, max_key_len;
+
+ max_key_len = encoding->length - sizeof(*ext);
+ if (max_key_len < 0)
+ return -EINVAL;
+
+ idx = encoding->flags & IW_ENCODE_INDEX;
+ if (idx) {
+ if (idx < 1 || idx > WEP_KEYS)
+ return -EINVAL;
+ idx--;
+ } else
+ idx = ieee->crypt_info.tx_keyidx;
+
+ if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
+ ext->alg != IW_ENCODE_ALG_WEP)
+ if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
+ return -EINVAL;
+
+ encoding->flags = idx + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ if (!sec->enabled) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ encoding->flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (sec->encode_alg[idx] == SEC_ALG_WEP)
+ ext->alg = IW_ENCODE_ALG_WEP;
+ else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ else
+ return -EINVAL;
+
+ ext->key_len = sec->key_sizes[idx];
+ memcpy(ext->key, sec->keys[idx], ext->key_len);
+ encoding->flags |= IW_ENCODE_ENABLED;
+ if (ext->key_len &&
+ (ext->alg == IW_ENCODE_ALG_TKIP ||
+ ext->alg == IW_ENCODE_ALG_CCMP))
+ ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
+
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
+EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
+
+EXPORT_SYMBOL(ieee80211_wx_get_scan);
+EXPORT_SYMBOL(ieee80211_wx_set_encode);
+EXPORT_SYMBOL(ieee80211_wx_get_encode);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index b0ac0ce3fb9..47bee0ee0a7 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -4,6 +4,7 @@ config IWLWIFI
config IWLCORE
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ select LIB80211
select IWLWIFI
select MAC80211_LEDS if IWLWIFI_LEDS
select LEDS_CLASS if IWLWIFI_LEDS
@@ -105,6 +106,7 @@ config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
+ select LIB80211
select IWLWIFI
select MAC80211_LEDS if IWL3945_LEDS
select LEDS_CLASS if IWL3945_LEDS
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 47aa28f6a51..0be9e6b66aa 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -5,9 +5,10 @@ iwlcore-objs += iwl-scan.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
+iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-hcmd-check.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
index 817ece77364..c6f4eb54a2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -69,6 +69,12 @@
#ifndef __iwl_3945_commands_h__
#define __iwl_3945_commands_h__
+/* uCode version contains 4 values: Major/Minor/API/Serial */
+#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24)
+#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16)
+#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8)
+#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF)
+
enum {
REPLY_ALIVE = 0x1,
REPLY_ERROR = 0x2,
@@ -121,7 +127,7 @@ enum {
REPLY_TX_PWR_TABLE_CMD = 0x97,
MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
- /* Bluetooth device coexistance config command */
+ /* Bluetooth device coexistence config command */
REPLY_BT_CONFIG = 0x9b,
/* Statistics */
@@ -158,7 +164,7 @@ struct iwl3945_cmd_header {
u8 cmd; /* Command ID: REPLY_RXON, etc. */
u8 flags; /* IWL_CMD_* */
/*
- * The driver sets up the sequence number to values of its chosing.
+ * The driver sets up the sequence number to values of its choosing.
* uCode does not use this value, but passes it back to the driver
* when sending the response to each driver-originated command, so
* the driver can match the response to the command. Since the values
@@ -220,7 +226,7 @@ struct iwl3945_power_per_rate {
*
*****************************************************************************/
-#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
+#define UCODE_VALID_OK cpu_to_le32(0x1)
#define INITIALIZE_SUBTYPE (9)
/*
@@ -322,42 +328,42 @@ enum {
/* rx_config flags */
/* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1)
+#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 __constant_cpu_to_le32(1 << 2)
+#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2)
/* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3)
+#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3)
/* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5)
+#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 __constant_cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#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 __constant_cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13)
+#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 __constant_cpu_to_le32(1 << 15)
+#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15)
/* rx_config filter flags */
/* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0)
+#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0)
/* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1)
+#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1)
/* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2)
+#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2)
/* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3)
+#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3)
/* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
/* STA is associated */
-#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5)
+#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 __constant_cpu_to_le32(1 << 6)
+#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6)
/**
* REPLY_RXON = 0x10 (command, has simple generic response)
@@ -471,9 +477,9 @@ struct iwl3945_ac_qos {
} __attribute__ ((packed));
/* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10)
+#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
@@ -508,27 +514,27 @@ struct iwl3945_qosparam_cmd {
#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
#define IWL_INVALID_STATION 255
-#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1 << 2);
-#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8);
+#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2);
+#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
/* 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 __constant_cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003)
+#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 __constant_cpu_to_le16(0x0800)
+#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_WEP_KEY_MAP_MSK __constant_cpu_to_le16(0x0008)
+#define STA_KEY_FLG_WEP_KEY_MAP_MSK cpu_to_le16(0x0008)
/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
+#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000)
/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
@@ -666,14 +672,14 @@ struct iwl3945_rx_frame_hdr {
u8 payload[0];
} __attribute__ ((packed));
-#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+#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 __constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+#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 cpu_to_le16(0xf0)
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
@@ -733,57 +739,57 @@ struct iwl3945_rx_frame {
/* 1: Use Request-To-Send protocol before this frame.
* Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
-#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
/* 1: Transmit Clear-To-Send to self before this frame.
* Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
* Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
-#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
/* 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 __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
/* 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 __constant_cpu_to_le32(1 << 4)
+#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 __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6)
/* 1: Frame requires full Tx-Op protection.
* Set this if either RTS or CTS Tx Flag gets set. */
-#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
* Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
-#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
-#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9)
/* 1: Ignore Bluetooth priority for this frame.
* 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+#define TX_CMD_FLG_BT_DIS_MSK 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 __constant_cpu_to_le32(1 << 13)
+#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 __constant_cpu_to_le32(1 << 14)
+#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 __constant_cpu_to_le32(1 << 16)
+#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.
@@ -791,10 +797,10 @@ struct iwl3945_rx_frame {
* 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 __constant_cpu_to_le32(1 << 20)
+#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20)
/* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
/*
* TX command security control
@@ -991,7 +997,7 @@ struct iwl3945_rate_scaling_cmd {
*
* 3945 and 4965 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 accomodate.
+ * wireless device can delay or kill its own Tx to accommodate.
*/
struct iwl3945_bt_cmd {
u8 flags;
@@ -1158,9 +1164,9 @@ struct iwl3945_spectrum_notification {
*/
#define IWL_POWER_VEC_SIZE 5
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1 << 0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1 << 2)
-#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1 << 3)
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le32(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le32(1 << 2)
+#define IWL_POWER_PCI_PM_MSK cpu_to_le32(1 << 3)
struct iwl3945_powertable_cmd {
__le32 flags;
__le32 rx_data_timeout;
@@ -1278,8 +1284,8 @@ struct iwl3945_ssid_ie {
} __attribute__ ((packed));
#define PROBE_OPTION_MAX 0x4
-#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
+#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH cpu_to_le16(1)
#define IWL_MAX_SCAN_SIZE 1024
/*
@@ -1379,7 +1385,7 @@ struct iwl3945_scan_cmd {
} __attribute__ ((packed));
/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1)
+#define CAN_ABORT_STATUS cpu_to_le32(0x1)
/* complete notification statuses */
#define ABORT_STATUS 0x2
@@ -1572,8 +1578,8 @@ struct statistics_general {
* 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 __constant_cpu_to_le32(0x1) /* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+#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 iwl3945_statistics_cmd {
__le32 configuration_flags; /* IWL_STATS_CONF_* */
} __attribute__ ((packed));
@@ -1593,8 +1599,8 @@ struct iwl3945_statistics_cmd {
* appropriately so that each notification contains statistics for only the
* one channel that has just been scanned.
*/
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8)
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8)
struct iwl3945_notif_statistics {
__le32 flag;
struct statistics_rx rx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h
index bc12f97ba0b..6f463555402 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -71,9 +71,33 @@
#define IWL_SKU_G 0x1
#define IWL_SKU_A 0x2
+/**
+ * struct iwl_3945_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * (.ucode) will be added to filename before loading from disk. The
+ * filename is constructed as fw_name_pre<api>.ucode.
+ * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @ucode_api_min: Lowest version of uCode API supported by driver.
+ *
+ * We enable the driver to be backward compatible wrt API version. The
+ * driver specifies which APIs it supports (with @ucode_api_max being the
+ * highest and @ucode_api_min the lowest). Firmware will only be loaded if
+ * it has a supported API version. The firmware's API version will be
+ * stored in @iwl_priv, enabling the driver to make runtime changes based
+ * on firmware version used.
+ *
+ * For example,
+ * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+ * Driver interacts with Firmware API version >= 2.
+ * } else {
+ * Driver interacts with Firmware API version 1.
+ * }
+ */
struct iwl_3945_cfg {
const char *name;
- const char *fw_name;
+ const char *fw_name_pre;
+ const unsigned int ucode_api_max;
+ const unsigned int ucode_api_min;
unsigned int sku;
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
index 33016fb5e9b..85eb778f9df 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
@@ -21,7 +21,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 644bd9e0805..94ea0e60c41 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -103,7 +103,6 @@
* Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
*/
#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
-#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */
/*
* Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags.
@@ -321,6 +320,7 @@ struct iwl3945_eeprom {
/* RSSR */
#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000)
#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004)
+#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000)
/* TCSR */
#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20)
#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
index b3fe48de3ae..2440fd664dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -21,7 +21,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -53,7 +53,7 @@
* _iwl3945_read32.)
*
* These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguring of the hardware I/O. In combination with
+ * which result in misconfiguration of the hardware I/O. In combination with
* git-bisect and the IO debug level you can quickly determine the specific
* commit which breaks the IO sequence to the hardware.
*
@@ -93,7 +93,7 @@ static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr,
do {
if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask))
return i;
- mdelay(10);
+ udelay(10);
i += 10;
} while (i < timeout);
@@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l,
int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask,
- unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
+ unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret;
}
#define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \
@@ -271,16 +271,7 @@ static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv,
static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv,
u32 addr, u32 mask, int timeout)
{
- int i = 0;
-
- do {
- if ((_iwl3945_read_direct32(priv, addr) & mask) == mask)
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
-
- return -ETIMEDOUT;
+ return _iwl3945_poll_bit(priv, addr, mask, mask, timeout);
}
#ifdef CONFIG_IWL3945_DEBUG
@@ -307,6 +298,7 @@ static inline int __iwl3945_poll_direct_bit(const char *f, u32 l,
static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg)
{
_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ rmb();
return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
}
#ifdef CONFIG_IWL3945_DEBUG
@@ -328,6 +320,7 @@ static inline void _iwl3945_write_prph(struct iwl3945_priv *priv,
{
_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
((addr & 0x0000FFFF) | (3 << 24)));
+ wmb();
_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
}
#ifdef CONFIG_IWL3945_DEBUG
@@ -389,12 +382,14 @@ static inline void iwl3945_clear_bits_prph(struct iwl3945_priv
static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr)
{
iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+ rmb();
return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
}
static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val)
{
iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+ wmb();
iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
}
@@ -402,6 +397,7 @@ static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 add
u32 len, u32 *values)
{
iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+ wmb();
for (; 0 < len; len -= sizeof(u32), values++)
iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 705c65bed9f..4c638909a7d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 2fbd126c134..749ac035fd6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 6fc5e7361f2..9b60a0c5de5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -63,6 +63,9 @@ struct iwl3945_rs_sta {
u8 ibss_sta_added;
struct timer_list rate_scale_flush;
struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+#endif
/* used to be in sta_info */
int last_txrate_idx;
@@ -114,9 +117,11 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
};
#define IWL_RATE_MAX_WINDOW 62
-#define IWL_RATE_FLUSH (3*HZ/10)
+#define IWL_RATE_FLUSH (3*HZ)
#define IWL_RATE_WIN_FLUSH (HZ/2)
#define IWL_RATE_HIGH_TH 11520
+#define IWL_SUCCESS_UP_TH 8960
+#define IWL_SUCCESS_DOWN_TH 10880
#define IWL_RATE_MIN_FAILURE_TH 8
#define IWL_RATE_MIN_SUCCESS_TH 8
#define IWL_RATE_DECREASE_TH 1920
@@ -203,6 +208,7 @@ static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta)
#define IWL_RATE_FLUSH_MAX 5000 /* msec */
#define IWL_RATE_FLUSH_MIN 50 /* msec */
+#define IWL_AVERAGE_PACKETS 1500
static void iwl3945_bg_rate_scale_flush(unsigned long data)
{
@@ -217,8 +223,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data)
spin_lock_irqsave(&rs_sta->lock, flags);
- rs_sta->flush_pending = 0;
-
/* Number of packets Rx'd since last time this timer ran */
packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
@@ -227,7 +231,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data)
if (unflushed) {
duration =
jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
-/* duration = jiffies_to_msecs(rs_sta->flush_time); */
IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
packet_count, duration);
@@ -239,9 +242,11 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data)
pps = 0;
if (pps) {
- duration = IWL_RATE_FLUSH_MAX / pps;
+ duration = (IWL_AVERAGE_PACKETS * 1000) / pps;
if (duration < IWL_RATE_FLUSH_MIN)
duration = IWL_RATE_FLUSH_MIN;
+ else if (duration > IWL_RATE_FLUSH_MAX)
+ duration = IWL_RATE_FLUSH_MAX;
} else
duration = IWL_RATE_FLUSH_MAX;
@@ -254,8 +259,10 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data)
rs_sta->flush_time);
rs_sta->last_partial_flush = jiffies;
+ } else {
+ rs_sta->flush_time = IWL_RATE_FLUSH;
+ rs_sta->flush_pending = 0;
}
-
/* If there weren't any unflushed entries, we don't schedule the timer
* to run again */
@@ -275,17 +282,18 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data)
*/
static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
struct iwl3945_rate_scale_data *window,
- int success, int retries)
+ int success, int retries, int index)
{
unsigned long flags;
+ s32 fail_count;
if (!retries) {
IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
return;
}
+ spin_lock_irqsave(&rs_sta->lock, flags);
while (retries--) {
- spin_lock_irqsave(&rs_sta->lock, flags);
/* If we have filled up the window then subtract one from the
* success counter if the high-bit is counting toward
@@ -313,14 +321,25 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
/* Tag this window as having been updated */
window->stamp = jiffies;
- spin_unlock_irqrestore(&rs_sta->lock, flags);
}
+
+ fail_count = window->counter - window->success_counter;
+ if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+ (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+ window->average_tpt = ((window->success_ratio *
+ rs_sta->expected_tpt[index] + 64) / 128);
+ else
+ window->average_tpt = IWL_INV_TPT;
+
+ spin_unlock_irqrestore(&rs_sta->lock, flags);
+
}
-static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
+static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
struct iwl3945_rs_sta *rs_sta = priv_sta;
+ struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
int i;
IWL_DEBUG_RATE("enter\n");
@@ -330,16 +349,21 @@ static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband,
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
- for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
+ for (i = sband->n_bitrates - 1; i >= 0; i--) {
if (sta->supp_rates[sband->band] & (1 << i)) {
rs_sta->last_txrate_idx = i;
break;
}
}
+ priv->sta_supp_rates = sta->supp_rates[sband->band];
/* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
- if (sband->band == IEEE80211_BAND_5GHZ)
+ if (sband->band == IEEE80211_BAND_5GHZ) {
rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ priv->sta_supp_rates = priv->sta_supp_rates <<
+ IWL_FIRST_OFDM_RATE;
+ }
+
IWL_DEBUG_RATE("leave\n");
}
@@ -355,12 +379,6 @@ static void rs_free(void *priv)
return;
}
-static void rs_clear(void *priv)
-{
- return;
-}
-
-
static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
struct iwl3945_rs_sta *rs_sta;
@@ -422,34 +440,6 @@ static void rs_free_sta(void *priv, struct ieee80211_sta *sta,
}
-/*
- * get ieee prev rate from rate scale table.
- * for A and B mode we need to overright prev
- * value
- */
-static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
-{
- int next_rate = iwl3945_get_prev_ieee_rate(rate);
-
- switch (priv->band) {
- case IEEE80211_BAND_5GHZ:
- if (rate == IWL_RATE_12M_INDEX)
- next_rate = IWL_RATE_9M_INDEX;
- else if (rate == IWL_RATE_6M_INDEX)
- next_rate = IWL_RATE_6M_INDEX;
- break;
-/* XXX cannot be invoked in current mac80211 so not a regression
- case MODE_IEEE80211B:
- if (rate == IWL_RATE_11M_INDEX_TABLE)
- next_rate = IWL_RATE_5M_INDEX_TABLE;
- break;
- */
- default:
- break;
- }
-
- return next_rate;
-}
/**
* rs_tx_status - Update rate control values based on Tx results
*
@@ -460,7 +450,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
- u8 retries, current_count;
+ s8 retries = 0, current_count;
int scale_rate_index, first_index, last_index;
unsigned long flags;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
@@ -469,8 +459,9 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
IWL_DEBUG_RATE("enter\n");
- retries = info->status.retry_count;
- first_index = sband->bitrates[info->tx_rate_idx].hw_value;
+ retries = info->status.rates[0].count;
+
+ first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
return;
@@ -496,13 +487,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
* at which the frame was finally transmitted (or failed if no
* ACK)
*/
- while (retries > 0) {
- if (retries < priv->retry_rate) {
- current_count = retries;
+ while (retries > 1) {
+ if ((retries - 1) < priv->retry_rate) {
+ current_count = (retries - 1);
last_index = scale_rate_index;
} else {
current_count = priv->retry_rate;
- last_index = rs_adjust_next_rate(priv,
+ last_index = iwl3945_rs_next_rate(priv,
scale_rate_index);
}
@@ -510,15 +501,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
* as was used for it (per current_count) */
iwl3945_collect_tx_data(rs_sta,
&rs_sta->win[scale_rate_index],
- 0, current_count);
+ 0, current_count, scale_rate_index);
IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
scale_rate_index, current_count);
retries -= current_count;
- if (retries)
- scale_rate_index =
- rs_adjust_next_rate(priv, scale_rate_index);
+ scale_rate_index = last_index;
}
@@ -529,7 +518,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
"success" : "failure");
iwl3945_collect_tx_data(rs_sta,
&rs_sta->win[last_index],
- info->flags & IEEE80211_TX_STAT_ACK, 1);
+ info->flags & IEEE80211_TX_STAT_ACK, 1, last_index);
/* We updated the rate scale window -- if its been more than
* flush_time since the last run, schedule the flush
@@ -537,9 +526,10 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
spin_lock_irqsave(&rs_sta->lock, flags);
if (!rs_sta->flush_pending &&
- time_after(jiffies, rs_sta->last_partial_flush +
+ time_after(jiffies, rs_sta->last_flush +
rs_sta->flush_time)) {
+ rs_sta->last_partial_flush = jiffies;
rs_sta->flush_pending = 1;
mod_timer(&rs_sta->rate_scale_flush,
jiffies + rs_sta->flush_time);
@@ -630,10 +620,11 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
* rate table and must reference the driver allocated rate table
*
*/
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
+ void *priv_sta, struct ieee80211_tx_rate_control *txrc)
{
+ struct ieee80211_supported_band *sband = txrc->sband;
+ struct sk_buff *skb = txrc->skb;
u8 low = IWL_RATE_INVALID;
u8 high = IWL_RATE_INVALID;
u16 high_low;
@@ -649,7 +640,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
u16 fc, rate_mask;
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
- DECLARE_MAC_BUF(mac);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE("enter\n");
@@ -660,7 +651,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
is_multicast_ether_addr(hdr->addr1) ||
!sta || !priv_sta) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
- sel->rate_idx = rate_lowest_index(sband, sta);
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
return;
}
@@ -675,8 +666,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, hdr->addr1));
+ IWL_DEBUG_RATE("LQ: ADD station %pm\n",
+ hdr->addr1);
sta_id = iwl3945_add_station(priv,
hdr->addr1, 0, CMD_ASYNC);
}
@@ -686,8 +677,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
spin_lock_irqsave(&rs_sta->lock, flags);
+ /* for recent assoc, choose best rate regarding
+ * to rssi value
+ */
if (rs_sta->start_rate != IWL_RATE_INVALID) {
- index = rs_sta->start_rate;
+ if (rs_sta->start_rate < index &&
+ (rate_mask & (1 << rs_sta->start_rate)))
+ index = rs_sta->start_rate;
rs_sta->start_rate = IWL_RATE_INVALID;
}
@@ -697,7 +693,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
(window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
- window->average_tpt = IWL_INV_TPT;
spin_unlock_irqrestore(&rs_sta->lock, flags);
IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
@@ -711,8 +706,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
}
- window->average_tpt = ((window->success_ratio *
- rs_sta->expected_tpt[index] + 64) / 128);
current_tpt = window->average_tpt;
high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask,
@@ -760,13 +753,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
}
}
- if ((window->success_ratio > IWL_RATE_HIGH_TH) ||
- (current_tpt > window->average_tpt)) {
- IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or "
- "current_tpt [%d] > average_tpt [%d]\n",
- window->success_ratio,
- current_tpt, window->average_tpt);
- scale_action = 0;
+ if (scale_action == -1) {
+ if (window->success_ratio > IWL_SUCCESS_DOWN_TH)
+ scale_action = 0;
+ } else if (scale_action == 1) {
+ if (window->success_ratio < IWL_SUCCESS_UP_TH) {
+ IWL_DEBUG_RATE("No action -- success_ratio [%d] < "
+ "SUCCESS UP\n", window->success_ratio);
+ scale_action = 0;
+ }
}
switch (scale_action) {
@@ -793,24 +788,83 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
rs_sta->last_txrate_idx = index;
if (sband->band == IEEE80211_BAND_5GHZ)
- sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
+ info->control.rates[0].idx = rs_sta->last_txrate_idx -
+ IWL_FIRST_OFDM_RATE;
else
- sel->rate_idx = rs_sta->last_txrate_idx;
+ info->control.rates[0].idx = rs_sta->last_txrate_idx;
IWL_DEBUG_RATE("leave: %d\n", index);
}
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int iwl3945_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int j;
+ struct iwl3945_rs_sta *lq_sta = file->private_data;
+
+ desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n"
+ "rate=0x%X flush time %d\n",
+ lq_sta->tx_packets,
+ lq_sta->last_txrate_idx,
+ lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time));
+ for (j = 0; j < IWL_RATE_COUNT; j++) {
+ desc += sprintf(buff+desc,
+ "counter=%d success=%d %%=%d\n",
+ lq_sta->win[j].counter,
+ lq_sta->win[j].success_counter,
+ lq_sta->win[j].success_ratio);
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+ .read = iwl3945_sta_dbgfs_stats_table_read,
+ .open = iwl3945_open_file_generic,
+};
+
+static void iwl3945_add_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct iwl3945_rs_sta *lq_sta = priv_sta;
+
+ lq_sta->rs_sta_dbgfs_stats_table_file =
+ debugfs_create_file("rate_stats_table", 0600, dir,
+ lq_sta, &rs_sta_dbgfs_stats_table_ops);
+
+}
+
+static void iwl3945_remove_debugfs(void *priv, void *priv_sta)
+{
+ struct iwl3945_rs_sta *lq_sta = priv_sta;
+ debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
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,
- .clear = rs_clear,
.alloc = rs_alloc,
.free = rs_free,
.alloc_sta = rs_alloc_sta,
.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = iwl3945_add_debugfs,
+ .remove_sta_debugfs = iwl3945_remove_debugfs,
+#endif
+
};
void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
@@ -827,13 +881,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
rcu_read_lock();
sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
- psta = (void *) sta->drv_priv;
- if (!sta || !psta) {
- IWL_DEBUG_RATE("leave - no private rate data!\n");
+ if (!sta) {
rcu_read_unlock();
return;
}
+ psta = (void *) sta->drv_priv;
rs_sta = psta->rs_sta;
spin_lock_irqsave(&rs_sta->lock, flags);
@@ -857,7 +910,6 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
break;
}
- rcu_read_unlock();
spin_unlock_irqrestore(&rs_sta->lock, flags);
rssi = priv->last_rx_rssi;
@@ -871,6 +923,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
"%d (plcp 0x%x)\n", rssi, rs_sta->start_rate,
iwl3945_rates[rs_sta->start_rate].plcp);
+ rcu_read_unlock();
}
int iwl3945_rate_control_register(void)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index 98b17ae6ef2..b5a66135ded 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 7ca5627cc07..8fdb34222c0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -200,7 +200,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
* priv->eeprom is used to determine if antenna AUX/MAIN are reversed
* priv->antenna specifies the antenna diversity mode:
*
- * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
+ * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself
* IWL_ANTENNA_MAIN - Force MAIN antenna
* IWL_ANTENNA_AUX - Force AUX antenna
*/
@@ -261,6 +261,37 @@ static inline const char *iwl3945_get_tx_fail_reason(u32 status)
}
#endif
+/*
+ * get ieee prev rate from rate scale table.
+ * for A and B mode we need to overright prev
+ * value
+ */
+int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate)
+{
+ int next_rate = iwl3945_get_prev_ieee_rate(rate);
+
+ switch (priv->band) {
+ case IEEE80211_BAND_5GHZ:
+ if (rate == IWL_RATE_12M_INDEX)
+ next_rate = IWL_RATE_9M_INDEX;
+ else if (rate == IWL_RATE_6M_INDEX)
+ next_rate = IWL_RATE_6M_INDEX;
+ break;
+ case IEEE80211_BAND_2GHZ:
+ if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+ iwl3945_is_associated(priv)) {
+ if (rate == IWL_RATE_11M_INDEX)
+ next_rate = IWL_RATE_5M_INDEX;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return next_rate;
+}
+
/**
* iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
@@ -308,6 +339,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->status);
int rate_idx;
+ int fail;
if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
@@ -318,9 +350,18 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
}
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
- memset(&info->status, 0, sizeof(info->status));
+ ieee80211_tx_info_clear_status(info);
+
+ /* Fill the MRR chain with some info about on-chip retransmissions */
+ rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate_idx -= IWL_FIRST_OFDM_RATE;
+
+ fail = tx_resp->failure_frame;
+
+ info->status.rates[0].idx = rate_idx;
+ info->status.rates[0].count = fail + 1; /* add final attempt */
- info->status.retry_count = tx_resp->failure_frame;
/* tx_status->rts_retry_count = tx_resp->failure_rts; */
info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
IEEE80211_TX_STAT_ACK : 0;
@@ -329,10 +370,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
txq_id, iwl3945_get_tx_fail_reason(status), status,
tx_resp->rate, tx_resp->failure_frame);
- rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
- if (info->band == IEEE80211_BAND_5GHZ)
- rate_idx -= IWL_FIRST_OFDM_RATE;
- info->tx_rate_idx = rate_idx;
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
iwl3945_tx_queue_reclaim(priv, txq_id, index);
@@ -756,13 +793,19 @@ int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *
u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
{
- int i;
+ int i, start = IWL_AP_ID;
int ret = IWL_INVALID_STATION;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
+
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+ (priv->iw_mode == NL80211_IFTYPE_AP))
+ start = IWL_STA_ID;
+
+ if (is_broadcast_ether_addr(addr))
+ return priv->hw_setting.bcast_sta_id;
spin_lock_irqsave(&priv->sta_lock, flags);
- for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ for (i = start; i < priv->hw_setting.max_stations; i++)
if ((priv->stations[i].used) &&
(!compare_ether_addr
(priv->stations[i].sta.sta.addr, addr))) {
@@ -770,8 +813,8 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
goto out;
}
- IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
- print_mac(mac, addr), priv->num_stations);
+ IWL_DEBUG_INFO("can not find STA %pM (total %d)\n",
+ addr, priv->num_stations);
out:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
@@ -1060,9 +1103,8 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ rc = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (rc < 0) {
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("Failed to init the card\n");
@@ -1243,8 +1285,7 @@ int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv)
IWL_DEBUG_INFO("Card in power save, master is already "
"stopped\n");
else {
- rc = iwl3945_poll_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ rc = iwl3945_poll_direct_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (rc < 0) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1269,9 +1310,8 @@ int iwl3945_hw_nic_reset(struct iwl3945_priv *priv)
iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
- rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
rc = iwl3945_grab_nic_access(priv);
if (!rc) {
@@ -1830,7 +1870,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv)
ref_temp = (s16)priv->eeprom.groups[ch_info->group_index].
temperature;
- /* get power index adjustment based on curr and factory
+ /* get power index adjustment based on current and factory
* temps */
delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
ref_temp);
@@ -2268,7 +2308,8 @@ int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv)
}
iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0);
- rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+ rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS,
+ FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
if (rc < 0)
IWL_ERROR("Can't stop Rx DMA.\n");
@@ -2337,7 +2378,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv)
iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0);
table[index].try_cnt = priv->retry_rate;
prev_index = iwl3945_get_prev_ieee_rate(i);
- table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index;
+ table[index].next_rate_index =
+ iwl3945_rates[prev_index].table_rs_index;
}
switch (priv->band) {
@@ -2345,11 +2387,14 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv)
IWL_DEBUG_RATE("Select A mode rate scale\n");
/* If one of the following CCK rates is used,
* have it fall back to the 6M OFDM rate */
- for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++)
- table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+ for (i = IWL_RATE_1M_INDEX_TABLE;
+ i <= IWL_RATE_11M_INDEX_TABLE; i++)
+ table[i].next_rate_index =
+ iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
/* Don't fall back to CCK rates */
- table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE;
+ table[IWL_RATE_12M_INDEX_TABLE].next_rate_index =
+ IWL_RATE_9M_INDEX_TABLE;
/* Don't drop out of OFDM rates */
table[IWL_RATE_6M_INDEX_TABLE].next_rate_index =
@@ -2360,11 +2405,20 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv)
IWL_DEBUG_RATE("Select B/G mode rate scale\n");
/* If an OFDM rate is used, have it fall back to the
* 1M CCK rates */
- for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
- table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index;
- /* CCK shouldn't fall back to OFDM... */
- table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
+ if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+ iwl3945_is_associated(priv)) {
+
+ index = IWL_FIRST_CCK_RATE;
+ for (i = IWL_RATE_6M_INDEX_TABLE;
+ i <= IWL_RATE_54M_INDEX_TABLE; i++)
+ table[i].next_rate_index =
+ iwl3945_rates[index].table_rs_index;
+
+ index = IWL_RATE_11M_INDEX_TABLE;
+ /* CCK shouldn't fall back to OFDM... */
+ table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
+ }
break;
default:
@@ -2428,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
frame_size = iwl3945_fill_beacon_frame(priv,
tx_beacon_cmd->frame,
- iwl3945_broadcast_addr,
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -2467,13 +2520,17 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv)
static struct iwl_3945_cfg iwl3945_bg_cfg = {
.name = "3945BG",
- .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+ .fw_name_pre = IWL3945_FW_PRE,
+ .ucode_api_max = IWL3945_UCODE_API_MAX,
+ .ucode_api_min = IWL3945_UCODE_API_MIN,
.sku = IWL_SKU_G,
};
static struct iwl_3945_cfg iwl3945_abg_cfg = {
.name = "3945ABG",
- .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode",
+ .fw_name_pre = IWL3945_FW_PRE,
+ .ucode_api_max = IWL3945_UCODE_API_MAX,
+ .ucode_api_min = IWL3945_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index bdd32475b99..2c0ddc5110c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -50,11 +50,15 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
#include "iwl-3945-debug.h"
#include "iwl-3945-led.h"
-/* Change firmware file name, using "-" and incrementing number,
- * *only* when uCode interface or architecture changes so that it
- * is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL3945_UCODE_API "-1"
+/* Highest firmware API version supported */
+#define IWL3945_UCODE_API_MAX 2
+
+/* Lowest firmware API version supported */
+#define IWL3945_UCODE_API_MIN 1
+
+#define IWL3945_FW_PRE "iwlwifi-3945-"
+#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode"
+#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api)
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
@@ -401,12 +405,6 @@ struct iwl3945_rx_queue {
#define SCAN_INTERVAL 100
-#define MAX_A_CHANNELS 252
-#define MIN_A_CHANNELS 7
-
-#define MAX_B_CHANNELS 14
-#define MIN_B_CHANNELS 1
-
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
#define STATUS_INT_ENABLED 2
@@ -472,7 +470,6 @@ union iwl3945_qos_capabity {
/* QoS structures */
struct iwl3945_qos_info {
- int qos_enable;
int qos_active;
union iwl3945_qos_capabity qos_cap;
struct iwl3945_qosparam_cmd def_qos_parm;
@@ -505,7 +502,7 @@ struct fw_desc {
/* uCode file layout */
struct iwl3945_ucode {
- __le32 ver; /* major/minor/subminor */
+ __le32 ver; /* major/minor/API/serial */
__le32 inst_size; /* bytes of runtime instructions */
__le32 data_size; /* bytes of runtime data */
__le32 init_size; /* bytes of initialization instructions */
@@ -587,8 +584,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len,
extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
struct iwl3945_host_cmd *cmd);
extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
- struct ieee80211_hdr *hdr,
- const u8 *dest, int left);
+ struct ieee80211_hdr *hdr,int left);
extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
struct iwl3945_rx_queue *q);
extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
@@ -762,6 +758,8 @@ struct iwl3945_priv {
void __iomem *hw_base;
/* uCode images, save to reload in case of failure */
+ u32 ucode_ver; /* ucode version, copy of
+ iwl3945_ucode.ver */
struct fw_desc ucode_code; /* runtime inst */
struct fw_desc ucode_data; /* runtime data original */
struct fw_desc ucode_data_backup; /* runtime data save/restore */
@@ -804,6 +802,8 @@ struct iwl3945_priv {
u16 active_rate;
u16 active_rate_basic;
+ u32 sta_supp_rates;
+
u8 call_post_assoc_from_beacon;
/* Rate scaling data */
s8 data_retry_limit;
@@ -828,8 +828,6 @@ struct iwl3945_priv {
unsigned long last_statistics_time;
/* context information */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
u16 rates_mask;
u32 power_mode;
@@ -888,7 +886,6 @@ struct iwl3945_priv {
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
- struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
@@ -903,9 +900,6 @@ struct iwl3945_priv {
s8 user_txpower_limit;
s8 max_channel_txpower_limit;
-#ifdef CONFIG_PM
- u32 pm_state[16];
-#endif
#ifdef CONFIG_IWL3945_DEBUG
/* debugging info */
@@ -954,6 +948,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch)
extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
+extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate);
+
/* Requires full declaration of iwl3945_priv before including */
#include "iwl-3945-io.h"
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index f4793a60944..6649f7b5565 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -71,7 +71,7 @@
#include "iwl-fh.h"
-/* EERPROM */
+/* EEPROM */
#define IWL4965_EEPROM_IMG_SIZE 1024
/*
@@ -84,12 +84,6 @@
#define IWL_CMD_FIFO_NUM 4
#define IWL49_FIRST_AMPDU_QUEUE 7
-/* Tx rates */
-#define IWL_CCK_RATES 4
-#define IWL_OFDM_RATES 8
-#define IWL_HT_RATES 16
-#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
-
/* Time constants */
#define SHORT_SLOT_TIME 9
#define LONG_SLOT_TIME 20
@@ -111,7 +105,6 @@
#define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
-#define TFD_QUEUE_SIZE_MAX (256)
#define IWL_NUM_SCAN_RATES (2)
@@ -287,13 +280,13 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
* that target txpower.
*
*
- * 3) Determine (EEPROM) calibration subband for the target channel, by
- * comparing against first and last channels in each subband
+ * 3) Determine (EEPROM) calibration sub band for the target channel, by
+ * comparing against first and last channels in each sub band
* (see struct iwl4965_eeprom_calib_subband_info).
*
*
* 4) Linearly interpolate (EEPROM) factory calibration measurement sets,
- * referencing the 2 factory-measured (sample) channels within the subband.
+ * referencing the 2 factory-measured (sample) channels within the sub band.
*
* Interpolation is based on difference between target channel's frequency
* and the sample channels' frequencies. Since channel numbers are based
@@ -301,7 +294,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
* to interpolating based on channel number differences.
*
* Note that the sample channels may or may not be the channels at the
- * edges of the subband. The target channel may be "outside" of the
+ * edges of the sub band. The target channel may be "outside" of the
* span of the sampled channels.
*
* Driver may choose the pair (for 2 Tx chains) of measurements (see
@@ -345,7 +338,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
* "4965 temperature calculation".
*
* If current temperature is higher than factory temperature, driver must
- * increase gain (lower gain table index), and vice versa.
+ * increase gain (lower gain table index), and vice verse.
*
* Temperature affects gain differently for different channels:
*
@@ -815,125 +808,14 @@ enum {
* up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array
* in DRAM containing 256 Transmit Frame Descriptors (TFDs).
*/
-#define IWL49_MAX_WIN_SIZE 64
-#define IWL49_QUEUE_SIZE 256
#define IWL49_NUM_FIFOS 7
#define IWL49_CMD_FIFO_NUM 4
#define IWL49_NUM_QUEUES 16
#define IWL49_NUM_AMPDU_QUEUES 8
-/**
- * struct iwl_tfd_frame_data
- *
- * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
- * Each buffer must be on dword boundary.
- * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers,
- * may be filled within a TFD (iwl_tfd_frame).
- *
- * Bit fields in tb1_addr:
- * 31- 0: Tx buffer 1 address bits [31:0]
- *
- * Bit fields in val1:
- * 31-16: Tx buffer 2 address bits [15:0]
- * 15- 4: Tx buffer 1 length (bytes)
- * 3- 0: Tx buffer 1 address bits [32:32]
- *
- * Bit fields in val2:
- * 31-20: Tx buffer 2 length (bytes)
- * 19- 0: Tx buffer 2 address bits [35:16]
- */
-struct iwl_tfd_frame_data {
- __le32 tb1_addr;
-
- __le32 val1;
- /* __le32 ptb1_32_35:4; */
-#define IWL_tb1_addr_hi_POS 0
-#define IWL_tb1_addr_hi_LEN 4
-#define IWL_tb1_addr_hi_SYM val1
- /* __le32 tb_len1:12; */
-#define IWL_tb1_len_POS 4
-#define IWL_tb1_len_LEN 12
-#define IWL_tb1_len_SYM val1
- /* __le32 ptb2_0_15:16; */
-#define IWL_tb2_addr_lo16_POS 16
-#define IWL_tb2_addr_lo16_LEN 16
-#define IWL_tb2_addr_lo16_SYM val1
-
- __le32 val2;
- /* __le32 ptb2_16_35:20; */
-#define IWL_tb2_addr_hi20_POS 0
-#define IWL_tb2_addr_hi20_LEN 20
-#define IWL_tb2_addr_hi20_SYM val2
- /* __le32 tb_len2:12; */
-#define IWL_tb2_len_POS 20
-#define IWL_tb2_len_LEN 12
-#define IWL_tb2_len_SYM val2
-} __attribute__ ((packed));
-
/**
- * struct iwl_tfd_frame
- *
- * Transmit Frame Descriptor (TFD)
- *
- * 4965 supports up to 16 Tx queues resident in host DRAM.
- * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
- * Both driver and device share these circular buffers, each of which must be
- * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965.
- *
- * Driver must indicate the physical address of the base of each
- * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers.
- *
- * Each TFD contains pointer/size information for up to 20 data buffers
- * in host DRAM. These buffers collectively contain the (one) frame described
- * by the TFD. Each buffer must be a single contiguous block of memory within
- * itself, but buffers may be scattered in host DRAM. Each buffer has max size
- * of (4K - 4). The 4965 concatenates all of a TFD's buffers into a single
- * Tx frame, up to 8 KBytes in size.
- *
- * Bit fields in the control dword (val0):
- * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound
- * 29: reserved
- * 28-24: # Transmit Buffer Descriptors in TFD
- * 23- 0: reserved
- *
- * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
- */
-struct iwl_tfd_frame {
- __le32 val0;
- /* __le32 rsvd1:24; */
- /* __le32 num_tbs:5; */
-#define IWL_num_tbs_POS 24
-#define IWL_num_tbs_LEN 5
-#define IWL_num_tbs_SYM val0
- /* __le32 rsvd2:1; */
- /* __le32 padding:2; */
- struct iwl_tfd_frame_data pa[10];
- __le32 reserved;
-} __attribute__ ((packed));
-
-
-/**
- * struct iwl4965_queue_byte_cnt_entry
- *
- * Byte Count Table Entry
- *
- * Bit fields:
- * 15-12: reserved
- * 11- 0: total to-be-transmitted byte count of frame (does not include command)
- */
-struct iwl4965_queue_byte_cnt_entry {
- __le16 val;
- /* __le16 byte_cnt:12; */
-#define IWL_byte_cnt_POS 0
-#define IWL_byte_cnt_LEN 12
-#define IWL_byte_cnt_SYM val
- /* __le16 rsvd:4; */
-} __attribute__ ((packed));
-
-
-/**
- * struct iwl4965_sched_queue_byte_cnt_tbl
+ * struct iwl4965_schedq_bc_tbl
*
* Byte Count table
*
@@ -947,71 +829,12 @@ struct iwl4965_queue_byte_cnt_entry {
* count table for the chosen Tx queue. If the TFD index is 0-63, the driver
* must duplicate the byte count entry in corresponding index 256-319.
*
- * "dont_care" padding puts each byte count table on a 1024-byte boundary;
+ * padding puts each byte count table on a 1024-byte boundary;
* 4965 assumes tables are separated by 1024 bytes.
*/
-struct iwl4965_sched_queue_byte_cnt_tbl {
- struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE +
- IWL49_MAX_WIN_SIZE];
- u8 dont_care[1024 -
- (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) *
- sizeof(__le16)];
-} __attribute__ ((packed));
-
-
-/**
- * struct iwl4965_shared - handshake area for Tx and Rx
- *
- * For convenience in allocating memory, this structure combines 2 areas of
- * DRAM which must be shared between driver and 4965. These do not need to
- * be combined, if better allocation would result from keeping them separate:
- *
- * 1) The Tx byte count tables occupy 1024 bytes each (16 KBytes total for
- * 16 queues). Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find
- * the first of these tables. 4965 assumes tables are 1024 bytes apart.
- *
- * 2) The Rx status (val0 and val1) occupies only 8 bytes. Driver uses
- * FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area.
- * Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD)
- * that has been filled by the 4965.
- *
- * Bit fields val0:
- * 31-12: Not used
- * 11- 0: Index of last filled Rx buffer descriptor (4965 writes, driver reads)
- *
- * Bit fields val1:
- * 31- 0: Not used
- */
-struct iwl4965_shared {
- struct iwl4965_sched_queue_byte_cnt_tbl
- queues_byte_cnt_tbls[IWL49_NUM_QUEUES];
- __le32 rb_closed;
-
- /* __le32 rb_closed_stts_rb_num:12; */
-#define IWL_rb_closed_stts_rb_num_POS 0
-#define IWL_rb_closed_stts_rb_num_LEN 12
-#define IWL_rb_closed_stts_rb_num_SYM rb_closed
- /* __le32 rsrv1:4; */
- /* __le32 rb_closed_stts_rx_frame_num:12; */
-#define IWL_rb_closed_stts_rx_frame_num_POS 16
-#define IWL_rb_closed_stts_rx_frame_num_LEN 12
-#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
- /* __le32 rsrv2:4; */
-
- __le32 frm_finished;
- /* __le32 frame_finished_stts_rb_num:12; */
-#define IWL_frame_finished_stts_rb_num_POS 0
-#define IWL_frame_finished_stts_rb_num_LEN 12
-#define IWL_frame_finished_stts_rb_num_SYM frm_finished
- /* __le32 rsrv3:4; */
- /* __le32 frame_finished_stts_rx_frame_num:12; */
-#define IWL_frame_finished_stts_rx_frame_num_POS 16
-#define IWL_frame_finished_stts_rx_frame_num_LEN 12
-#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
- /* __le32 rsrv4:4; */
-
- __le32 padding1; /* so that allocation will be aligned to 16B */
- __le32 padding2;
+struct iwl4965_scd_bc_tbl {
+ __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
+ u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
} __attribute__ ((packed));
-#endif /* __iwl4965_4965_hw_h__ */
+#endif /* !__iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 9838de5f436..5a72bc0377d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -48,18 +48,21 @@
static int iwl4965_send_tx_power(struct iwl_priv *priv);
static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
-/* Change firmware file name, using "-" and incrementing number,
- * *only* when uCode interface or architecture changes so that it
- * is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-2"
+/* Highest firmware API version supported */
+#define IWL4965_UCODE_API_MAX 2
+
+/* Lowest firmware API version supported */
+#define IWL4965_UCODE_API_MIN 2
+
+#define IWL4965_FW_PRE "iwlwifi-4965-"
+#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode"
+#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api)
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
.num_of_queues = IWL49_NUM_QUEUES,
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
- .enable_qos = 1,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -246,7 +249,7 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
priv->ucode_data.len);
- /* Inst bytecount must be last to set up, bit 31 signals uCode
+ /* Inst byte count must be last to set up, bit 31 signals uCode
* that all new ptr/size info is in place */
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
priv->ucode_code.len | BSM_DRAM_INST_LOAD);
@@ -318,31 +321,13 @@ static int is_fat_channel(__le32 rxon_flags)
/*
* EEPROM handlers
*/
-
-static int iwl4965_eeprom_check_version(struct iwl_priv *priv)
+static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv)
{
- u16 eeprom_ver;
- u16 calib_ver;
-
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-
- calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
-
- if (eeprom_ver < EEPROM_4965_EEPROM_VERSION ||
- calib_ver < EEPROM_4965_TX_POWER_VERSION)
- goto err;
-
- return 0;
-err:
- IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
- eeprom_ver, EEPROM_4965_EEPROM_VERSION,
- calib_ver, EEPROM_4965_TX_POWER_VERSION);
- return -EINVAL;
-
+ return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
}
/*
- * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access
*/
static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
@@ -366,9 +351,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO("Failed to init the card\n");
goto out;
@@ -414,7 +398,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
/* L1 is enabled by BIOS */
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* diable L0S disabled L1A enabled */
+ /* disable L0S disabled L1A enabled */
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
else
/* L0S enabled L1A disabled */
@@ -442,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
static int iwl4965_apm_stop_master(struct iwl_priv *priv)
{
- int ret = 0;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -450,17 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv)
/* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
- ret = iwl_poll_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
- if (ret < 0)
- goto out;
+ iwl_poll_direct_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-out:
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n");
- return ret;
+ return 0;
}
static void iwl4965_apm_stop(struct iwl_priv *priv)
@@ -496,11 +475,9 @@ static int iwl4965_apm_reset(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- ret = iwl_poll_bit(priv, CSR_RESET,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
-
- if (ret)
+ ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (ret < 0)
goto out;
udelay(10);
@@ -537,10 +514,10 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
- struct iwl4965_calibration_cmd cmd;
+ struct iwl_calib_diff_gain_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
cmd.diff_gain_a = 0;
cmd.diff_gain_b = 0;
cmd.diff_gain_c = 0;
@@ -587,11 +564,11 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
/* Differential gain gets sent to uCode only once */
if (!data->radio_write) {
- struct iwl4965_calibration_cmd cmd;
+ struct iwl_calib_diff_gain_cmd cmd;
data->radio_write = 1;
memset(&cmd, 0, sizeof(cmd));
- cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
cmd.diff_gain_a = data->delta_gain_code[0];
cmd.diff_gain_b = data->delta_gain_code[1];
cmd.diff_gain_c = data->delta_gain_code[2];
@@ -619,10 +596,10 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags)
{
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
*tx_flags |= TX_CMD_FLG_RTS_MSK;
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
*tx_flags |= TX_CMD_FLG_CTS_MSK;
}
@@ -643,7 +620,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work)
mutex_lock(&priv->mutex);
- /* Regardless of if we are assocaited, we must reconfigure the
+ /* Regardless of if we are associated, we must reconfigure the
* TX power since frames can be sent on non-radar channels while
* not associated */
iwl4965_send_tx_power(priv);
@@ -679,7 +656,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
int txq_id = txq->q.id;
/* Find out whether to activate Tx queue */
- int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
/* Set up and activate */
iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
@@ -709,9 +686,10 @@ static const u16 default_queue_to_tx_fifo[] = {
static int iwl4965_alive_notify(struct iwl_priv *priv)
{
u32 a;
- int i = 0;
unsigned long flags;
int ret;
+ int i, chan;
+ u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
@@ -733,8 +711,18 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
/* Tel 4965 where to find Tx byte count tables */
iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR,
- (priv->shared_phys +
- offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
+ priv->scd_bc_tbls.dma >> 10);
+
+ /* Enable DMA channel */
+ for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++)
+ iwl_write_direct32(priv, 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(priv, FH_TX_CHICKEN_BITS_REG);
+ iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+ reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
/* Disable chain mode for all queues */
iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0);
@@ -766,7 +754,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
(1 << priv->hw_params.max_txq_num) - 1);
/* Activate all Tx DMA/FIFO channels */
- priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+ priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
@@ -822,7 +810,9 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
- priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE;
+ priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
+ priv->hw_params.scd_bc_tbls_size =
+ IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl);
priv->hw_params.max_stations = IWL4965_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
@@ -1650,36 +1640,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
}
#endif
-static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
-{
- struct iwl4965_shared *s = priv->shared_virt;
- return le32_to_cpu(s->rb_closed) & 0xFFF;
-}
-
-static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
-{
- priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
- sizeof(struct iwl4965_shared),
- &priv->shared_phys);
- if (!priv->shared_virt)
- return -ENOMEM;
-
- memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
-
- priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
-
- return 0;
-}
-
-static void iwl4965_free_shared_mem(struct iwl_priv *priv)
-{
- if (priv->shared_virt)
- pci_free_consistent(priv->pci_dev,
- sizeof(struct iwl4965_shared),
- priv->shared_virt,
- priv->shared_phys);
-}
-
/**
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
@@ -1687,21 +1647,22 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
u16 byte_cnt)
{
- int len;
+ struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int txq_id = txq->q.id;
- struct iwl4965_shared *shared_data = priv->shared_virt;
+ int write_ptr = txq->q.write_ptr;
+ int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+ __le16 bc_ent;
- len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+ WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
+ bc_ent = cpu_to_le16(len & 0xFFF);
/* Set up byte count within first 256 entries */
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[txq->q.write_ptr], byte_cnt, len);
+ scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
/* If within first 64 entries, duplicate at end */
- if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE)
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr],
- byte_cnt, len);
+ if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+ scd_bc_tbl[txq_id].
+ tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
/**
@@ -1956,7 +1917,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+ iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
@@ -2037,7 +1998,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
}
/**
- * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue
*/
static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
struct iwl_ht_agg *agg,
@@ -2059,7 +2020,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
agg->rate_n_flags = rate_n_flags;
agg->bitmap = 0;
- /* # frames attempted by Tx command */
+ /* num frames attempted by Tx command */
if (agg->frame_count == 1) {
/* Only one frame was attempted; no block-ack will arrive */
status = le16_to_cpu(frame_status[0].status);
@@ -2070,9 +2031,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
agg->frame_count, agg->start_idx, idx);
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
- info->status.retry_count = tx_resp->failure_frame;
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status)?
+ info->flags |= iwl_is_tx_success(status) ?
IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
/* FIXME: code repetition end */
@@ -2158,12 +2119,13 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info;
struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->u.status);
- int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
- __le16 fc;
- struct ieee80211_hdr *hdr;
+ int tid = MAX_TID_COUNT;
+ int sta_id;
+ int freed;
u8 *qc = NULL;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
@@ -2178,8 +2140,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
memset(&info->status, 0, sizeof(info->status));
hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
- fc = hdr->frame_control;
- if (ieee80211_is_data_qos(fc)) {
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
}
@@ -2194,8 +2155,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
- if (!qc)
- return;
+ WARN_ON(!qc);
agg = &priv->stations[sta_id].tid[tid].agg;
@@ -2206,54 +2166,49 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
- int freed, ampdu_q;
index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
- txq_id >= 0 && priv->mac80211_registered &&
- agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
- /* calculate mac80211 ampdu sw queue to wake */
- ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE +
- priv->hw->queues;
+ if (priv->mac80211_registered &&
+ (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+ (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
if (agg->state == IWL_AGG_OFF)
ieee80211_wake_queue(priv->hw, txq_id);
else
- ieee80211_wake_queue(priv->hw, ampdu_q);
+ ieee80211_wake_queue(priv->hw,
+ txq->swq_id);
}
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
}
} else {
- info->status.retry_count = tx_resp->failure_frame;
- info->flags |=
- iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ info->flags |= iwl_is_tx_success(status) ?
+ IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv,
le32_to_cpu(tx_resp->rate_n_flags),
info);
- IWL_DEBUG_TX("Tx queue %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("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("Tx queue reclaim %d\n", index);
-
- if (index != -1) {
- int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- if (tid != MAX_TID_COUNT)
+ freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ if (qc && likely(sta_id != IWL_INVALID_STATION))
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
- (txq_id >= 0) && priv->mac80211_registered)
+
+ if (priv->mac80211_registered &&
+ (iwl_queue_space(&txq->q) > txq->q.low_mark))
ieee80211_wake_queue(priv->hw, txq_id);
- if (tid != MAX_TID_COUNT)
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
- }
}
+ if (qc && likely(sta_id != IWL_INVALID_STATION))
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
}
@@ -2328,9 +2283,6 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
static struct iwl_lib_ops iwl4965_lib = {
.set_hw_params = iwl4965_hw_set_hw_params,
- .alloc_shared_mem = iwl4965_alloc_shared_mem,
- .free_shared_mem = iwl4965_free_shared_mem,
- .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx,
.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
.txq_set_sched = iwl4965_txq_set_sched,
.txq_agg_enable = iwl4965_txq_agg_enable,
@@ -2347,7 +2299,7 @@ static struct iwl_lib_ops iwl4965_lib = {
.reset = iwl4965_apm_reset,
.stop = iwl4965_apm_stop,
.config = iwl4965_nic_config,
- .set_pwr_src = iwl4965_set_pwr_src,
+ .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -2362,11 +2314,11 @@ static struct iwl_lib_ops iwl4965_lib = {
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
- .check_version = iwl4965_eeprom_check_version,
+ .calib_version = iwl4965_eeprom_calib_version,
.query_addr = iwlcore_eeprom_query_addr,
},
.send_tx_power = iwl4965_send_tx_power,
- .update_chain_flags = iwl4965_update_chain_flags,
+ .update_chain_flags = iwl_update_chain_flags,
.temperature = iwl4965_temperature_calib,
};
@@ -2378,15 +2330,19 @@ static struct iwl_ops iwl4965_ops = {
struct iwl_cfg iwl4965_agn_cfg = {
.name = "4965AGN",
- .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
+ .fw_name_pre = IWL4965_FW_PRE,
+ .ucode_api_max = IWL4965_UCODE_API_MAX,
+ .ucode_api_min = IWL4965_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.eeprom_size = IWL4965_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
.ops = &iwl4965_ops,
.mod_params = &iwl4965_mod_params,
};
/* Module firmware */
-MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
@@ -2394,7 +2350,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
+module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
@@ -2402,9 +2358,6 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
-/* QoS */
-module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
/* 11n */
module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index c479ee211c5..82c3859ce0f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -73,69 +73,27 @@
#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
-/* EERPROM */
+/* EEPROM */
#define IWL_5000_EEPROM_IMG_SIZE 2048
-
-#define IWL50_MAX_WIN_SIZE 64
-#define IWL50_QUEUE_SIZE 256
#define IWL50_CMD_FIFO_NUM 7
#define IWL50_NUM_QUEUES 20
#define IWL50_NUM_AMPDU_QUEUES 10
#define IWL50_FIRST_AMPDU_QUEUE 10
-#define IWL_sta_id_POS 12
-#define IWL_sta_id_LEN 4
-#define IWL_sta_id_SYM val
-
/* Fixed (non-configurable) rx data from phy */
-/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR
- * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
-struct iwl5000_sched_queue_byte_cnt_tbl {
- struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE +
- IWL50_MAX_WIN_SIZE];
-} __attribute__ ((packed));
-
-struct iwl5000_shared {
- struct iwl5000_sched_queue_byte_cnt_tbl
- queues_byte_cnt_tbls[IWL50_NUM_QUEUES];
- __le32 rb_closed;
-
- /* __le32 rb_closed_stts_rb_num:12; */
-#define IWL_rb_closed_stts_rb_num_POS 0
-#define IWL_rb_closed_stts_rb_num_LEN 12
-#define IWL_rb_closed_stts_rb_num_SYM rb_closed
- /* __le32 rsrv1:4; */
- /* __le32 rb_closed_stts_rx_frame_num:12; */
-#define IWL_rb_closed_stts_rx_frame_num_POS 16
-#define IWL_rb_closed_stts_rx_frame_num_LEN 12
-#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
- /* __le32 rsrv2:4; */
-
- __le32 frm_finished;
- /* __le32 frame_finished_stts_rb_num:12; */
-#define IWL_frame_finished_stts_rb_num_POS 0
-#define IWL_frame_finished_stts_rb_num_LEN 12
-#define IWL_frame_finished_stts_rb_num_SYM frm_finished
- /* __le32 rsrv3:4; */
- /* __le32 frame_finished_stts_rx_frame_num:12; */
-#define IWL_frame_finished_stts_rx_frame_num_POS 16
-#define IWL_frame_finished_stts_rx_frame_num_LEN 12
-#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
- /* __le32 rsrv4:4; */
-
- __le32 padding1; /* so that allocation will be aligned to 16B */
- __le32 padding2;
+/**
+ * struct iwl5000_schedq_bc_tbl scheduler byte count table
+ * base physical address of iwl5000_shared
+ * is provided to SCD_DRAM_BASE_ADDR
+ * @tfd_offset 0-12 - tx command byte count
+ * 12-16 - station index
+ */
+struct iwl5000_scd_bc_tbl {
+ __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
} __attribute__ ((packed));
-/* calibrations defined for 5000 */
-/* defines the order in which results should be sent to the runtime uCode */
-enum iwl5000_calib {
- IWL5000_CALIB_LO,
- IWL5000_CALIB_TX_IQ,
- IWL5000_CALIB_TX_IQ_PERD,
-};
#endif /* __iwl_5000_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 5155b8a760a..66d053d28a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -44,7 +44,21 @@
#include "iwl-helpers.h"
#include "iwl-5000-hw.h"
-#define IWL5000_UCODE_API "-1"
+/* Highest firmware API version supported */
+#define IWL5000_UCODE_API_MAX 1
+#define IWL5150_UCODE_API_MAX 1
+
+/* Lowest firmware API version supported */
+#define IWL5000_UCODE_API_MIN 1
+#define IWL5150_UCODE_API_MIN 1
+
+#define IWL5000_FW_PRE "iwlwifi-5000-"
+#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
+#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api)
+
+#define IWL5150_FW_PRE "iwlwifi-5150-"
+#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
+#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
static const u16 iwl5000_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_AC3,
@@ -59,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
/* FIXME: same implementation as 4965 */
static int iwl5000_apm_stop_master(struct iwl_priv *priv)
{
- int ret = 0;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -67,17 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
/* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
- ret = iwl_poll_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ iwl_poll_direct_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
- if (ret < 0)
- goto out;
-out:
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n");
- return ret;
+ return 0;
}
@@ -92,7 +101,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
- /* Set FH wait treshold to maximum (HW error during stress W/A) */
+ /* Set FH wait threshold to maximum (HW error during stress W/A) */
iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
/* enable HAP INTA to move device L1a -> L0s */
@@ -106,9 +115,8 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO("Failed to init the card\n");
return ret;
@@ -132,7 +140,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
return ret;
}
-/* FIXME: this is indentical to 4965 */
+/* FIXME: this is identical to 4965 */
static void iwl5000_apm_stop(struct iwl_priv *priv)
{
unsigned long flags;
@@ -175,9 +183,8 @@ static int iwl5000_apm_reset(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
- ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO("Failed to init the card\n");
goto out;
@@ -217,7 +224,7 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
/* L1 is enabled by BIOS */
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* diable L0S disabled L1A enabled */
+ /* disable L0S disabled L1A enabled */
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
else
/* L0S enabled L1A disabled */
@@ -291,30 +298,17 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
return (address & ADDRESS_MSK) + (offset << 1);
}
-static int iwl5000_eeprom_check_version(struct iwl_priv *priv)
+static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
{
- u16 eeprom_ver;
struct iwl_eeprom_calib_hdr {
u8 version;
u8 pa_type;
u16 voltage;
} *hdr;
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-
hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
EEPROM_5000_CALIB_ALL);
-
- if (eeprom_ver < EEPROM_5000_EEPROM_VERSION ||
- hdr->version < EEPROM_5000_TX_POWER_VERSION)
- goto err;
-
- return 0;
-err:
- IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
- eeprom_ver, EEPROM_5000_EEPROM_VERSION,
- hdr->version, EEPROM_5000_TX_POWER_VERSION);
- return -EINVAL;
+ return hdr->version;
}
@@ -348,10 +342,14 @@ static void iwl5000_gain_computation(struct iwl_priv *priv,
data->delta_gain_code[1], data->delta_gain_code[2]);
if (!data->radio_write) {
- struct iwl5000_calibration_chain_noise_gain_cmd cmd;
+ struct iwl_calib_chain_noise_gain_cmd cmd;
+
memset(&cmd, 0, sizeof(cmd));
- cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+ cmd.hdr.first_group = 0;
+ cmd.hdr.groups_num = 1;
+ cmd.hdr.data_valid = 1;
cmd.delta_gain_1 = data->delta_gain_code[1];
cmd.delta_gain_2 = data->delta_gain_code[2];
iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
@@ -373,14 +371,19 @@ static void iwl5000_gain_computation(struct iwl_priv *priv,
static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
{
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+ int ret;
if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
- struct iwl5000_calibration_chain_noise_reset_cmd cmd;
-
+ struct iwl_calib_chain_noise_reset_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
- cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
- if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
- sizeof(cmd), &cmd))
+
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+ cmd.hdr.first_group = 0;
+ cmd.hdr.groups_num = 1;
+ cmd.hdr.data_valid = 1;
+ ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd);
+ if (ret)
IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
data->state = IWL_CHAIN_NOISE_ACCUMULATE;
IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
@@ -390,8 +393,8 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags)
{
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+ if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+ (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
else
*tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
@@ -426,31 +429,41 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
return &priv->eeprom[address];
}
+static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
+{
+ const s32 volt2temp_coef = -5;
+ u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
+ EEPROM_5000_TEMPERATURE);
+ /* offset = temperate - voltage / coef */
+ s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef;
+ s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset;
+ return threshold * volt2temp_coef;
+}
+
/*
* Calibration
*/
-static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
+static int iwl5000_set_Xtal_calib(struct iwl_priv *priv)
{
+ struct iwl_calib_xtal_freq_cmd cmd;
u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
- struct iwl5000_calibration cal_cmd = {
- .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
- .data = {
- (u8)xtal_calib[0],
- (u8)xtal_calib[1],
- }
- };
-
- return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
- sizeof(cal_cmd), &cal_cmd);
+ cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
+ cmd.hdr.first_group = 0;
+ cmd.hdr.groups_num = 1;
+ cmd.hdr.data_valid = 1;
+ cmd.cap_pin1 = (u8)xtal_calib[0];
+ cmd.cap_pin2 = (u8)xtal_calib[1];
+ return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
+ (u8 *)&cmd, sizeof(cmd));
}
static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
{
- struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
+ struct iwl_calib_cfg_cmd calib_cfg_cmd;
struct iwl_host_cmd cmd = {
.id = CALIBRATION_CFG_CMD,
- .len = sizeof(struct iwl5000_calib_cfg_cmd),
+ .len = sizeof(struct iwl_calib_cfg_cmd),
.data = &calib_cfg_cmd,
};
@@ -467,7 +480,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
- struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
+ struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
int index;
@@ -478,14 +491,20 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
* uCode. iwl_send_calib_results sends them in a row according to their
* index. We sort them here */
switch (hdr->op_code) {
- case IWL5000_PHY_CALIBRATE_LO_CMD:
- index = IWL5000_CALIB_LO;
+ case IWL_PHY_CALIBRATE_DC_CMD:
+ index = IWL_CALIB_DC;
+ break;
+ case IWL_PHY_CALIBRATE_LO_CMD:
+ index = IWL_CALIB_LO;
break;
- case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
- index = IWL5000_CALIB_TX_IQ;
+ case IWL_PHY_CALIBRATE_TX_IQ_CMD:
+ index = IWL_CALIB_TX_IQ;
break;
- case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
- index = IWL5000_CALIB_TX_IQ_PERD;
+ case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+ index = IWL_CALIB_TX_IQ_PERD;
+ break;
+ case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+ index = IWL_CALIB_BASE_BAND;
break;
default:
IWL_ERROR("Unknown calibration notification %d\n",
@@ -535,7 +554,7 @@ static int iwl5000_load_section(struct iwl_priv *priv,
iwl_write_direct32(priv,
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
- (iwl_get_dma_hi_address(phy_addr)
+ (iwl_get_dma_hi_addr(phy_addr)
<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
iwl_write_direct32(priv,
@@ -547,7 +566,7 @@ static int iwl5000_load_section(struct iwl_priv *priv,
iwl_write_direct32(priv,
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_VAL |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
iwl_release_nic_access(priv);
@@ -561,14 +580,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
{
int ret = 0;
- ret = iwl5000_load_section(
- priv, inst_image, RTC_INST_LOWER_BOUND);
+ ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND);
if (ret)
return ret;
IWL_DEBUG_INFO("INST uCode section being loaded...\n");
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- priv->ucode_write_complete, 5 * HZ);
+ priv->ucode_write_complete, 5 * HZ);
if (ret == -ERESTARTSYS) {
IWL_ERROR("Could not load the INST uCode section due "
"to interrupt\n");
@@ -682,7 +700,7 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
int tx_fifo_id, int scd_retry)
{
int txq_id = txq->q.id;
- int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
(active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
@@ -710,9 +728,10 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
static int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
- int i = 0;
unsigned long flags;
int ret;
+ int i, chan;
+ u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
@@ -734,11 +753,21 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl_write_targ_mem(priv, a, 0);
iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
- (priv->shared_phys +
- offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10);
+ priv->scd_bc_tbls.dma >> 10);
+
+ /* Enable DMA channel */
+ for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+ iwl_write_direct32(priv, 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(priv, FH_TX_CHICKEN_BITS_REG);
+ iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+ reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
- IWL50_SCD_QUEUECHAIN_SEL_ALL(
- priv->hw_params.max_txq_num));
+ IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
/* initiate the queues */
@@ -765,6 +794,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
/* map qos queues to fifos one-to-one */
for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
int ac = iwl5000_default_queue_to_tx_fifo[i];
@@ -784,10 +814,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl5000_send_wimax_coex(priv);
- iwl5000_send_Xtal_calib(priv);
-
- if (priv->ucode_type == UCODE_RT)
- iwl_send_calib_results(priv);
+ iwl5000_set_Xtal_calib(priv);
+ iwl_send_calib_results(priv);
return 0;
}
@@ -802,7 +830,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
- priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE;
+ priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+ priv->hw_params.scd_bc_tbls_size =
+ IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
@@ -814,10 +844,14 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5100:
+ priv->hw_params.tx_chains_num = 1;
+ priv->hw_params.rx_chains_num = 2;
+ priv->hw_params.valid_tx_ant = ANT_B;
+ priv->hw_params.valid_rx_ant = ANT_AB;
+ break;
case CSR_HW_REV_TYPE_5150:
priv->hw_params.tx_chains_num = 1;
priv->hw_params.rx_chains_num = 2;
- /* FIXME: move to ANT_A, ANT_B, ANT_C enum */
priv->hw_params.valid_tx_ant = ANT_A;
priv->hw_params.valid_rx_ant = ANT_AB;
break;
@@ -840,43 +874,36 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
case CSR_HW_REV_TYPE_5150:
/* 5150 wants in Kelvin */
priv->hw_params.ct_kill_threshold =
- CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+ iwl5150_get_ct_threshold(priv);
break;
}
- return 0;
-}
-
-static int iwl5000_alloc_shared_mem(struct iwl_priv *priv)
-{
- priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
- sizeof(struct iwl5000_shared),
- &priv->shared_phys);
- if (!priv->shared_virt)
- return -ENOMEM;
+ /* Set initial calibration set */
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_5100:
+ case CSR_HW_REV_TYPE_5300:
+ case CSR_HW_REV_TYPE_5350:
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_XTAL) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_TX_IQ_PERD) |
+ BIT(IWL_CALIB_BASE_BAND);
+ break;
+ case CSR_HW_REV_TYPE_5150:
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_DC) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_BASE_BAND);
- memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared));
+ break;
+ }
- priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed);
return 0;
}
-static void iwl5000_free_shared_mem(struct iwl_priv *priv)
-{
- if (priv->shared_virt)
- pci_free_consistent(priv->pci_dev,
- sizeof(struct iwl5000_shared),
- priv->shared_virt,
- priv->shared_phys);
-}
-
-static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv)
-{
- struct iwl5000_shared *s = priv->shared_virt;
- return le32_to_cpu(s->rb_closed) & 0xFFF;
-}
-
/**
* iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
@@ -884,16 +911,18 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
u16 byte_cnt)
{
- struct iwl5000_shared *shared_data = priv->shared_virt;
+ struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+ int write_ptr = txq->q.write_ptr;
int txq_id = txq->q.id;
u8 sec_ctl = 0;
- u8 sta = 0;
- int len;
+ u8 sta_id = 0;
+ u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+ __le16 bc_ent;
- len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+ WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
if (txq_id != IWL_CMD_QUEUE_NUM) {
- sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+ sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
switch (sec_ctl & TX_CMD_SEC_MSK) {
@@ -909,40 +938,35 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
}
}
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[txq->q.write_ptr], byte_cnt, len);
+ bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[txq->q.write_ptr], sta_id, sta);
+ scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
- if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
- byte_cnt, len);
- IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
- sta_id, sta);
- }
+ if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+ scd_bc_tbl[txq_id].
+ tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
+ struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int txq_id = txq->q.id;
- struct iwl5000_shared *shared_data = priv->shared_virt;
- u8 sta = 0;
+ int read_ptr = txq->q.read_ptr;
+ u8 sta_id = 0;
+ __le16 bc_ent;
+
+ WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
if (txq_id != IWL_CMD_QUEUE_NUM)
- sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id;
+ sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
- shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
- val = cpu_to_le16(1 | (sta << 12));
+ bc_ent = cpu_to_le16(1 | (sta_id << 12));
+ scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
- if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
- shared_data->queues_byte_cnt_tbls[txq_id].
- tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr].
- val = cpu_to_le16(1 | (sta << 12));
- }
+ if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+ scd_bc_tbl[txq_id].
+ tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
}
static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@ -996,7 +1020,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+ iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
@@ -1089,7 +1113,7 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
/*
- * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access
*/
static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
@@ -1136,10 +1160,10 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
agg->frame_count, agg->start_idx, idx);
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
- info->status.retry_count = tx_resp->failure_frame;
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- info->flags |= iwl_is_tx_success(status)?
- IEEE80211_TX_STAT_ACK : 0;
+ info->flags |= iwl_is_tx_success(status) ?
+ IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
/* FIXME: code repetition end */
@@ -1225,9 +1249,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
struct ieee80211_tx_info *info;
struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le16_to_cpu(tx_resp->status.status);
- int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
- struct ieee80211_hdr *hdr;
- u8 *qc = NULL;
+ int tid;
+ int sta_id;
+ int freed;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
@@ -1240,25 +1264,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
memset(&info->status, 0, sizeof(info->status));
- hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
- }
-
- sta_id = iwl_get_ra_sta_id(priv, hdr);
- if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
- IWL_ERROR("Station not known\n");
- return;
- }
+ tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
+ sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
if (txq->sched_retry) {
const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
- if (!qc)
- return;
-
agg = &priv->stations[sta_id].tid[tid].agg;
iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
@@ -1268,58 +1280,58 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
- int freed, ampdu_q;
index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
- IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
- "%d index %d\n", scd_ssn , index);
+ IWL_DEBUG_TX_REPLY("Retry scheduler reclaim "
+ "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+ scd_ssn , index, txq_id, txq->swq_id);
+
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
- txq_id >= 0 && priv->mac80211_registered &&
- agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
- /* calculate mac80211 ampdu sw queue to wake */
- ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE +
- priv->hw->queues;
+ if (priv->mac80211_registered &&
+ (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+ (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
if (agg->state == IWL_AGG_OFF)
ieee80211_wake_queue(priv->hw, txq_id);
else
- ieee80211_wake_queue(priv->hw, ampdu_q);
+ ieee80211_wake_queue(priv->hw,
+ txq->swq_id);
}
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
}
} else {
- info->status.retry_count = tx_resp->failure_frame;
- info->flags =
- iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+ BUG_ON(txq_id != txq->swq_id);
+
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
+ info->flags |= iwl_is_tx_success(status) ?
+ IEEE80211_TX_STAT_ACK : 0;
iwl_hwrate_to_tx_control(priv,
le32_to_cpu(tx_resp->rate_n_flags),
info);
- IWL_DEBUG_TX("Tx queue %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("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("Tx queue reclaim %d\n", index);
- if (index != -1) {
- int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- if (tid != MAX_TID_COUNT)
+ freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
- (txq_id >= 0) && priv->mac80211_registered)
+
+ if (priv->mac80211_registered &&
+ (iwl_queue_space(&txq->q) > txq->q.low_mark))
ieee80211_wake_queue(priv->hw, txq_id);
- if (tid != MAX_TID_COUNT)
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
- }
}
+ if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
}
-/* Currently 5000 is the supperset of everything */
+/* Currently 5000 is the superset of everything */
static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
{
return len;
@@ -1466,9 +1478,6 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
static struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
- .alloc_shared_mem = iwl5000_alloc_shared_mem,
- .free_shared_mem = iwl5000_free_shared_mem,
- .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
@@ -1482,13 +1491,13 @@ static struct iwl_lib_ops iwl5000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.temperature = iwl5000_temperature,
- .update_chain_flags = iwl4965_update_chain_flags,
+ .update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
.config = iwl5000_nic_config,
- .set_pwr_src = iwl4965_set_pwr_src,
+ .set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
@@ -1503,7 +1512,7 @@ static struct iwl_lib_ops iwl5000_lib = {
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
- .check_version = iwl5000_eeprom_check_version,
+ .calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
},
};
@@ -1517,7 +1526,6 @@ static struct iwl_ops iwl5000_ops = {
static struct iwl_mod_params iwl50_mod_params = {
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
- .enable_qos = 1,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -1526,50 +1534,84 @@ static struct iwl_mod_params iwl50_mod_params = {
struct iwl_cfg iwl5300_agn_cfg = {
.name = "5300AGN",
- .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
};
struct iwl_cfg iwl5100_bg_cfg = {
.name = "5100BG",
- .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_G,
.ops = &iwl5000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
};
struct iwl_cfg iwl5100_abg_cfg = {
.name = "5100ABG",
- .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl5000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
};
struct iwl_cfg iwl5100_agn_cfg = {
.name = "5100AGN",
- .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
};
struct iwl_cfg iwl5350_agn_cfg = {
.name = "5350AGN",
- .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .fw_name_pre = IWL5000_FW_PRE,
+ .ucode_api_max = IWL5000_UCODE_API_MAX,
+ .ucode_api_min = IWL5000_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+ .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5150_agn_cfg = {
+ .name = "5150AGN",
+ .fw_name_pre = IWL5150_FW_PRE,
+ .ucode_api_max = IWL5150_UCODE_API_MAX,
+ .ucode_api_min = IWL5150_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
};
-MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable50,
@@ -1577,12 +1619,10 @@ MODULE_PARM_DESC(disable50,
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, int, 0444);
+module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444);
-MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c
new file mode 100644
index 00000000000..b8137eeae1d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 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 <net/mac80211.h>
+#include "iwl-dev.h"
+#include "iwl-debug.h"
+#include "iwl-commands.h"
+
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE: This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+ int error = 0;
+ int counter = 1;
+
+ if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+ error |= le32_to_cpu(rxon->flags &
+ (RXON_FLG_TGJ_NARROW_BAND_MSK |
+ RXON_FLG_RADAR_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check 24G fields %d | %d\n",
+ counter++, error);
+ } else {
+ error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+ 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+ if (error)
+ IWL_WARNING("check 52 fields %d | %d\n",
+ counter++, error);
+ error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+ if (error)
+ IWL_WARNING("check 52 CCK %d | %d\n",
+ counter++, error);
+ }
+ error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+ if (error)
+ IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+ /* make sure basic rates 6Mbps and 1Mbps are supported */
+ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+ ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+ if (error)
+ IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+ error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+ if (error)
+ IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+ if (error)
+ IWL_WARNING("check CCK and short slot %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check CCK & auto detect %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+ if (error)
+ IWL_WARNING("check TGG and auto detect %d | %d\n",
+ counter++, error);
+
+ if (error)
+ IWL_WARNING("Tuning to channel %d\n",
+ le16_to_cpu(rxon->channel));
+
+ if (error) {
+ IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index e2a58e47703..f3f17929ca0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -38,7 +38,6 @@
#include "iwl-dev.h"
#include "iwl-sta.h"
#include "iwl-core.h"
-#include "iwl-helpers.h"
#define RS_NAME "iwl-agn-rs"
@@ -188,7 +187,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
* 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
* "G" is the only table that supports CCK (the first 4 rates).
*/
-/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/
+/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/
static s32 expected_tpt_A[IWL_RATE_COUNT] = {
0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
};
@@ -281,10 +280,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
u32 time_diff;
s32 index;
struct iwl_traffic_load *tl = NULL;
- __le16 fc = hdr->frame_control;
u8 tid;
- if (ieee80211_is_data_qos(fc)) {
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
} else
@@ -357,11 +355,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
struct iwl_lq_sta *lq_data, u8 tid,
struct ieee80211_sta *sta)
{
- DECLARE_MAC_BUF(mac);
-
if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
- IWL_DEBUG_HT("Starting Tx agg: STA: %s tid: %d\n",
- print_mac(mac, sta->addr), tid);
+ IWL_DEBUG_HT("Starting Tx agg: STA: %pM tid: %d\n",
+ sta->addr, tid);
ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid);
}
}
@@ -775,7 +771,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
int status;
u8 retries;
int rs_index, index = 0;
- struct iwl_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
@@ -787,12 +783,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct iwl_scale_tbl_info tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
u8 active_index = 0;
- __le16 fc = hdr->frame_control;
s32 tpt = 0;
IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1))
return;
/* This packet was aggregated but doesn't carry rate scale info */
@@ -800,13 +796,11 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- retries = info->status.retry_count;
+ retries = info->status.rates[0].count - 1;
if (retries > 15)
retries = 15;
- lq_sta = (struct iwl_lq_sta *)priv_sta;
-
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added)
goto out;
@@ -832,21 +826,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
if (priv->band == IEEE80211_BAND_5GHZ)
rs_index -= IWL_FIRST_OFDM_RATE;
- if ((info->tx_rate_idx < 0) ||
- (tbl_type.is_SGI ^
- !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
- (tbl_type.is_fat ^
- !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
- (tbl_type.is_dup ^
- !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
- (tbl_type.ant_type ^ info->antenna_sel_tx) ||
- (!!(tx_rate & RATE_MCS_HT_MSK) ^
- !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
- (!!(tx_rate & RATE_MCS_GF_MSK) ^
- !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
+ if ((info->status.rates[0].idx < 0) ||
+ (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
+ (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+ (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
+ (tbl_type.ant_type != info->antenna_sel_tx) ||
+ (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
+ (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
(hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
- hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
+ hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
+ /* the last LQ command could failed so the LQ in ucode not
+ * the same in driver sync up
+ */
+ iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
goto out;
}
@@ -1135,11 +1128,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
s32 rate;
s8 is_green = lq_sta->is_green;
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
- !sta->ht_info.ht_supported)
+ if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
return -1;
- if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
+ if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
== WLAN_HT_CAP_SM_PS_STATIC)
return -1;
@@ -1203,8 +1195,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
u8 is_green = lq_sta->is_green;
s32 rate;
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
- !sta->ht_info.ht_supported)
+ if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
return -1;
IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@@ -1684,7 +1675,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
int high_tpt = IWL_INVALID_VALUE;
u32 fail_count;
s8 scale_action = 0;
- __le16 fc;
u16 rate_mask;
u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1;
@@ -1699,13 +1689,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
- fc = hdr->frame_control;
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
- /* Send management frames and broadcast/multicast data using
- * lowest rate. */
- /* TODO: this could probably be improved.. */
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1))
return;
- }
if (!sta || !lq_sta)
return;
@@ -2003,9 +1992,8 @@ lq_update:
* 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->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) &&
- (lq_sta->action_counter >= 1)) {
+ if (is_legacy(tbl1->lq_type) && !conf->ht.enabled &&
+ lq_sta->action_counter >= 1) {
lq_sta->action_counter = 0;
IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
rs_set_stay_in_table(priv, 1, lq_sta);
@@ -2081,15 +2069,13 @@ static void rs_initialize_lq(struct iwl_priv *priv,
if ((i < 0) || (i >= IWL_RATE_COUNT))
i = 0;
- /* FIXME:RS: This is also wrong in 4965 */
rate = iwl_rates[i].plcp;
- rate |= RATE_MCS_ANT_B_MSK;
- rate &= ~RATE_MCS_ANT_A_MSK;
+ 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;
- tbl->ant_type = ANT_B;
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);
@@ -2103,40 +2089,38 @@ static void rs_initialize_lq(struct iwl_priv *priv,
return;
}
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
- struct ieee80211_sta *sta, void *priv_sta,
- struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
- int i;
+ struct sk_buff *skb = txrc->skb;
+ struct ieee80211_supported_band *sband = txrc->sband;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc;
- struct iwl_lq_sta *lq_sta;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_lq_sta *lq_sta = priv_sta;
+ int rate_idx;
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
/* Send management frames and broadcast/multicast data using lowest
* rate. */
- fc = hdr->frame_control;
- if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
- !sta || !priv_sta) {
- sel->rate_idx = rate_lowest_index(sband, sta);
+ if (!ieee80211_is_data(hdr->frame_control) ||
+ is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) {
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
return;
}
- lq_sta = (struct iwl_lq_sta *)priv_sta;
- i = lq_sta->last_txrate_idx;
+ rate_idx = lq_sta->last_txrate_idx;
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added) {
u8 sta_id = iwl_find_station(priv, hdr->addr1);
- DECLARE_MAC_BUF(mac);
if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, hdr->addr1));
+ IWL_DEBUG_RATE("LQ: ADD station %pM\n",
+ hdr->addr1);
sta_id = iwl_add_station_flags(priv, hdr->addr1,
0, CMD_ASYNC, NULL);
}
@@ -2148,14 +2132,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
}
}
- if ((i < 0) || (i > IWL_RATE_COUNT)) {
- sel->rate_idx = rate_lowest_index(sband, sta);
- return;
- }
+ if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
+ rate_idx = rate_lowest_index(sband, sta);
+ else if (sband->band == IEEE80211_BAND_5GHZ)
+ rate_idx -= IWL_FIRST_OFDM_RATE;
- if (sband->band == IEEE80211_BAND_5GHZ)
- i -= IWL_FIRST_OFDM_RATE;
- sel->rate_idx = i;
+ info->control.rates[0].idx = rate_idx;
}
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
@@ -2189,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf;
struct iwl_lq_sta *lq_sta = priv_sta;
+ u16 mask_bit = 0;
lq_sta->flush_timer = 0;
lq_sta->supp_rates = sta->supp_rates[sband->band];
@@ -2205,15 +2188,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->ibss_sta_added = 0;
if (priv->iw_mode == NL80211_IFTYPE_AP) {
u8 sta_id = iwl_find_station(priv, sta->addr);
- DECLARE_MAC_BUF(mac);
/* for IBSS the call are from tasklet */
- IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, sta->addr));
+ IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr);
if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_RATE("LQ: ADD station %s\n",
- print_mac(mac, sta->addr));
+ IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr);
sta_id = iwl_add_station_flags(priv, sta->addr,
0, CMD_ASYNC, NULL);
}
@@ -2225,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
priv->assoc_station_added = 1;
}
- /* Find highest tx rate supported by hardware and destination station */
- lq_sta->last_txrate_idx = 3;
- for (i = 0; i < sband->n_bitrates; i++)
- if (sta->supp_rates[sband->band] & BIT(i))
- lq_sta->last_txrate_idx = i;
-
- /* For MODE_IEEE80211A, skip over cck rates in global rate table */
- if (sband->band == IEEE80211_BAND_5GHZ)
- lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
-
lq_sta->is_dup = 0;
lq_sta->is_green = rs_use_green(priv, conf);
lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
@@ -2244,19 +2214,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
* 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 = conf->ht_conf.supp_mcs_set[0] << 1;
- lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1;
+ lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
+ lq_sta->active_siso_rate |= sta->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 = conf->ht_conf.supp_mcs_set[1] << 1;
- lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1;
+ lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
+ lq_sta->active_mimo2_rate |= sta->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 = conf->ht_conf.supp_mcs_set[2] << 1;
- lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1;
+ lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
+ lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
lq_sta->active_mimo3_rate &= ~((u16)0x2);
lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
@@ -2265,7 +2235,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->active_mimo2_rate,
lq_sta->active_mimo3_rate);
- /* These values will be overriden later */
+ /* These values will be overridden later */
lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
@@ -2273,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->drv = priv;
+ /* Find highest tx rate supported by hardware and destination station */
+ mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate;
+ lq_sta->last_txrate_idx = 3;
+ for (i = 0; i < sband->n_bitrates; i++)
+ if (mask_bit & BIT(i))
+ lq_sta->last_txrate_idx = i;
+
+ /* For MODE_IEEE80211A, skip over cck rates in global rate table */
+ if (sband->band == IEEE80211_BAND_5GHZ)
+ lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+
rs_initialize_lq(priv, conf, sta, lq_sta);
}
@@ -2405,19 +2386,6 @@ static void rs_free(void *priv_rate)
return;
}
-static void rs_clear(void *priv_rate)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
-
- IWL_DEBUG_RATE("enter\n");
-
- /* TODO - add rate scale state reset */
-
- IWL_DEBUG_RATE("leave\n");
-#endif /* CONFIG_IWLWIFI_DEBUG */
-}
-
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
void *priv_sta)
{
@@ -2552,7 +2520,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
for (i = 0; i < LQ_SIZE; i++) {
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
"rate=0x%X\n",
- lq_sta->active_tbl == i?"*":"x",
+ 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_fat,
@@ -2605,7 +2573,6 @@ static struct rate_control_ops rs_ops = {
.tx_status = rs_tx_status,
.get_rate = rs_get_rate,
.rate_init = rs_rate_init,
- .clear = rs_clear,
.alloc = rs_alloc,
.free = rs_free,
.alloc_sta = rs_alloc_sta,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index d148d73635e..78ee83adf74 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -229,7 +229,7 @@ enum {
#define IWL_MIMO2_SWITCH_SISO_C 4
#define IWL_MIMO2_SWITCH_GI 5
-/*FIXME:RS:add posible acctions for MIMO3*/
+/*FIXME:RS:add possible actions for MIMO3*/
#define IWL_ACTION_LIMIT 3 /* # possible actions */
@@ -284,7 +284,17 @@ static inline u8 num_of_ant(u8 mask)
!!((mask) & ANT_C);
}
-static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
+static inline u8 first_antenna(u8 mask)
+{
+ if (mask & ANT_A)
+ return ANT_A;
+ if (mask & ANT_B)
+ return ANT_B;
+ return ANT_C;
+}
+
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
{
u8 rate = iwl_rates[rate_index].prev_ieee;
@@ -294,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
}
/**
- * iwl4965_rate_control_register - Register the rate control algorithm callbacks
+ * 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
- * iwl4965_rate_control_register in order to register the rate control callbacks
+ * 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
*
@@ -306,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
extern int iwlagn_rate_control_register(void);
/**
- * iwl4965_rate_control_unregister - Unregister the rate control callbacks
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
*
* This should be called after calling ieee80211_unregister_hw, but before
* the driver is unloaded.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 444c5cc05f0..5da6b35cd26 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -83,7 +83,7 @@
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
MODULE_ALIAS("iwl4965");
@@ -96,7 +96,7 @@ MODULE_ALIAS("iwl4965");
-static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -108,79 +108,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
}
/**
- * iwl4965_check_rxon_cmd - validate RXON structure is valid
- *
- * NOTE: This is really only useful during development and can eventually
- * be #ifdef'd out once the driver is stable and folks aren't actively
- * making changes
- */
-static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
-{
- int error = 0;
- int counter = 1;
-
- if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
- error |= le32_to_cpu(rxon->flags &
- (RXON_FLG_TGJ_NARROW_BAND_MSK |
- RXON_FLG_RADAR_DETECT_MSK));
- if (error)
- IWL_WARNING("check 24G fields %d | %d\n",
- counter++, error);
- } else {
- error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
- 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
- if (error)
- IWL_WARNING("check 52 fields %d | %d\n",
- counter++, error);
- error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
- if (error)
- IWL_WARNING("check 52 CCK %d | %d\n",
- counter++, error);
- }
- error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
- if (error)
- IWL_WARNING("check mac addr %d | %d\n", counter++, error);
-
- /* make sure basic rates 6Mbps and 1Mbps are supported */
- error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
- ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
- if (error)
- IWL_WARNING("check basic rate %d | %d\n", counter++, error);
-
- error |= (le16_to_cpu(rxon->assoc_id) > 2007);
- if (error)
- IWL_WARNING("check assoc id %d | %d\n", counter++, error);
-
- error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
- == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
- if (error)
- IWL_WARNING("check CCK and short slot %d | %d\n",
- counter++, error);
-
- error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
- == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
- if (error)
- IWL_WARNING("check CCK & auto detect %d | %d\n",
- counter++, error);
-
- error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
- RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
- if (error)
- IWL_WARNING("check TGG and auto detect %d | %d\n",
- counter++, error);
-
- if (error)
- IWL_WARNING("Tuning to channel %d\n",
- le16_to_cpu(rxon->channel));
-
- if (error) {
- IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
- return -1;
- }
- return 0;
-}
-
-/**
* iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
* @priv: staging_rxon is compared to active_rxon
*
@@ -228,18 +155,17 @@ static int iwl_full_rxon_required(struct iwl_priv *priv)
}
/**
- * iwl4965_commit_rxon - commit staging_rxon to hardware
+ * iwl_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.
*/
-static int iwl4965_commit_rxon(struct iwl_priv *priv)
+static int iwl_commit_rxon(struct iwl_priv *priv)
{
/* cast away the const for active_rxon in this function */
struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
- DECLARE_MAC_BUF(mac);
int ret;
bool new_assoc =
!!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
@@ -253,14 +179,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
* 5000, but will not damage 4965 */
priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
- ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
+ ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon);
if (ret) {
IWL_ERROR("Invalid RXON configuration. Not committing.\n");
return -EINVAL;
}
/* If we don't need to send a full RXON, we can use
- * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
+ * iwl_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
if (!iwl_full_rxon_required(priv)) {
ret = iwl_send_rxon_assoc(priv);
@@ -300,12 +226,12 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
IWL_DEBUG_INFO("Sending RXON\n"
"* with%s RXON_FILTER_ASSOC_MSK\n"
"* channel = %d\n"
- "* bssid = %s\n",
+ "* bssid = %pM\n",
(new_assoc ? "" : "out"),
le16_to_cpu(priv->staging_rxon.channel),
- print_mac(mac, priv->staging_rxon.bssid_addr));
+ priv->staging_rxon.bssid_addr);
- iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
/* Apply the new configuration
* RXON unassoc clears the station table in uCode, send it before
@@ -375,16 +301,16 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
return 0;
}
-void iwl4965_update_chain_flags(struct iwl_priv *priv)
+void iwl_update_chain_flags(struct iwl_priv *priv)
{
iwl_set_rxon_chain(priv);
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
-static int iwl4965_send_bt_config(struct iwl_priv *priv)
+static int iwl_send_bt_config(struct iwl_priv *priv)
{
- struct iwl4965_bt_cmd bt_cmd = {
+ struct iwl_bt_cmd bt_cmd = {
.flags = 3,
.lead_time = 0xAA,
.max_kill = 1,
@@ -393,7 +319,7 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv)
};
return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
- sizeof(struct iwl4965_bt_cmd), &bt_cmd);
+ sizeof(struct iwl_bt_cmd), &bt_cmd);
}
static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -445,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
- const u8 *dest, int left)
+ int left)
{
if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
@@ -460,16 +386,16 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
return priv->ibss_beacon->len;
}
-static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
+static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
{
int i;
int rate_mask;
/* Set rate mask*/
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
- rate_mask = priv->active_rate_basic & 0xF;
+ rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
else
- rate_mask = priv->active_rate_basic & 0xFF0;
+ rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
/* Find lowest valid rate */
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
@@ -485,7 +411,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
return IWL_RATE_6M_PLCP;
}
-static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl_frame *frame, u8 rate)
{
struct iwl_tx_beacon_cmd *tx_beacon_cmd;
@@ -498,7 +424,6 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
- iwl_bcast_addr,
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -517,7 +442,7 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
return sizeof(*tx_beacon_cmd) + frame_size;
}
-static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
{
struct iwl_frame *frame;
unsigned int frame_size;
@@ -532,9 +457,9 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
return -ENOMEM;
}
- rate = iwl4965_rate_get_lowest_plcp(priv);
+ rate = iwl_rate_get_lowest_plcp(priv);
- frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
&frame->u.cmd[0]);
@@ -550,20 +475,33 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
*
******************************************************************************/
-static void iwl4965_ht_conf(struct iwl_priv *priv,
+static void iwl_ht_conf(struct iwl_priv *priv,
struct ieee80211_bss_conf *bss_conf)
{
- struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
- struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
+ struct ieee80211_sta_ht_cap *ht_conf;
struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+ struct ieee80211_sta *sta;
IWL_DEBUG_MAC80211("enter: \n");
- iwl_conf->is_ht = bss_conf->assoc_ht;
-
if (!iwl_conf->is_ht)
return;
+
+ /*
+ * It is totally wrong to base global information on something
+ * that is valid only when associated, alas, this driver works
+ * that way and I don't know how to fix it.
+ */
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->hw, priv->bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ ht_conf = &sta->ht_cap;
+
if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
@@ -574,29 +512,36 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
iwl_conf->supported_chan_width =
- !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
- iwl_conf->extension_chan_offset =
- ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+ !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+ /*
+ * XXX: The HT configuration needs to be moved into iwl_mac_config()
+ * to be done there correctly.
+ */
+
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS)
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS)
+ iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+
/* If no above or below channel supplied disable FAT channel */
- if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE &&
- iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) {
- iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE;
+ if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
+ iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
iwl_conf->supported_chan_width = 0;
- }
iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
- memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+ memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
- iwl_conf->control_channel = ht_bss_conf->primary_channel;
- iwl_conf->tx_chan_width =
- !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+ iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
iwl_conf->ht_protection =
- ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+ bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
iwl_conf->non_GF_STA_present =
- !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+ !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+
+ rcu_read_unlock();
- IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
IWL_DEBUG_MAC80211("leave\n");
}
@@ -608,9 +553,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (!priv->qos_data.qos_enable)
- return;
-
priv->qos_data.def_qos_parm.qos_flags = 0;
if (priv->qos_data.qos_cap.q_AP.queue_request &&
@@ -637,23 +579,22 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
#define MAX_UCODE_BEACON_INTERVAL 4096
-static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
+static u16 iwl_adjust_beacon_interval(u16 beacon_val)
{
u16 new_val = 0;
u16 beacon_factor = 0;
- beacon_factor =
- (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
+ beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+ / MAX_UCODE_BEACON_INTERVAL;
new_val = beacon_val / beacon_factor;
- return cpu_to_le16(new_val);
+ return new_val;
}
-static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
{
- u64 interval_tm_unit;
- u64 tsf, result;
+ u64 tsf;
+ s32 interval_tm, rem;
unsigned long flags;
struct ieee80211_conf *conf = NULL;
u16 beacon_int = 0;
@@ -661,49 +602,32 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
conf = ieee80211_get_hw_conf(priv->hw);
spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32);
- priv->rxon_timing.timestamp.dw[0] =
- cpu_to_le32(priv->timestamp & 0xFFFFFFFF);
-
+ priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
- tsf = priv->timestamp;
-
- beacon_int = priv->beacon_int;
- spin_unlock_irqrestore(&priv->lock, flags);
-
if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- if (beacon_int == 0) {
- priv->rxon_timing.beacon_interval = cpu_to_le16(100);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
- } else {
- priv->rxon_timing.beacon_interval =
- cpu_to_le16(beacon_int);
- priv->rxon_timing.beacon_interval =
- iwl4965_adjust_beacon_interval(
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- }
-
+ beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
priv->rxon_timing.atim_window = 0;
} else {
- priv->rxon_timing.beacon_interval =
- iwl4965_adjust_beacon_interval(conf->beacon_int);
+ beacon_int = iwl_adjust_beacon_interval(conf->beacon_int);
+
/* TODO: we need to get atim_window from upper stack
* for now we set to 0 */
priv->rxon_timing.atim_window = 0;
}
- interval_tm_unit =
- (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
- result = do_div(tsf, interval_tm_unit);
- priv->rxon_timing.beacon_init_val =
- cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+ priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
- IWL_DEBUG_ASSOC
- ("beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
+ tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+ interval_tm = beacon_int * 1024;
+ rem = do_div(tsf, interval_tm);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
}
static void iwl_set_flags_for_band(struct iwl_priv *priv,
@@ -715,7 +639,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
| RXON_FLG_CCK_MSK);
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
} else {
- /* Copied from iwl4965_post_associate() */
+ /* Copied from iwl_post_associate() */
if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
@@ -733,13 +657,13 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
/*
* initialize rxon structure with default values from eeprom
*/
-static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
+static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
{
const struct iwl_channel_info *ch_info;
memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
- switch (priv->iw_mode) {
+ switch (mode) {
case NL80211_IFTYPE_AP:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
break;
@@ -762,7 +686,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
break;
default:
- IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+ IWL_ERROR("Unsupported interface type %d\n", mode);
break;
}
@@ -808,11 +732,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
iwl_set_rxon_chain(priv);
}
-static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
{
- priv->iw_mode = mode;
-
- iwl4965_connection_init_rx_config(priv);
+ iwl_connection_init_rx_config(priv, mode);
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
iwl_clear_stations_table(priv);
@@ -828,12 +750,12 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
return -EAGAIN;
}
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
return 0;
}
-static void iwl4965_set_rate(struct iwl_priv *priv)
+static void iwl_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
@@ -880,138 +802,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
-#define BEACON_TIME_MASK_LOW 0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH 0xFF000000
-#define TIME_UNIT 1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
- u32 quot;
- u32 rem;
- u32 interval = beacon_interval * 1024;
-
- if (!interval || !usec)
- return 0;
-
- quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
- rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
- return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
- u32 base_low = base & BEACON_TIME_MASK_LOW;
- u32 addon_low = addon & BEACON_TIME_MASK_LOW;
- u32 interval = beacon_interval * TIME_UNIT;
- u32 res = (base & BEACON_TIME_MASK_HIGH) +
- (addon & BEACON_TIME_MASK_HIGH);
-
- if (base_low > addon_low)
- res += base_low - addon_low;
- else if (base_low < addon_low) {
- res += interval + base_low - addon_low;
- res += (1 << 24);
- } else
- res += (1 << 24);
-
- return cpu_to_le32(res);
-}
-
-static int iwl4965_get_measurement(struct iwl_priv *priv,
- struct ieee80211_measurement_params *params,
- u8 type)
-{
- struct iwl4965_spectrum_cmd spectrum;
- struct iwl_rx_packet *res;
- struct iwl_host_cmd cmd = {
- .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
- .data = (void *)&spectrum,
- .meta.flags = CMD_WANT_SKB,
- };
- u32 add_time = le64_to_cpu(params->start_time);
- int rc;
- int spectrum_resp_status;
- int duration = le16_to_cpu(params->duration);
-
- if (iwl_is_associated(priv))
- add_time =
- iwl4965_usecs_to_beacons(
- le64_to_cpu(params->start_time) - priv->last_tsf,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
-
- memset(&spectrum, 0, sizeof(spectrum));
-
- spectrum.channel_count = cpu_to_le16(1);
- spectrum.flags =
- RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
- spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
- cmd.len = sizeof(spectrum);
- spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
-
- if (iwl_is_associated(priv))
- spectrum.start_time =
- iwl4965_add_beacon_time(priv->last_beacon_time,
- add_time,
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- else
- spectrum.start_time = 0;
-
- spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
- spectrum.channels[0].channel = params->channel;
- spectrum.channels[0].type = type;
- if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
- spectrum.flags |= RXON_FLG_BAND_24G_MSK |
- RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
-
- rc = iwl_send_cmd_sync(priv, &cmd);
- if (rc)
- return rc;
-
- res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
- rc = -EIO;
- }
-
- spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
- switch (spectrum_resp_status) {
- case 0: /* Command will be handled */
- if (res->u.spectrum.id != 0xff) {
- IWL_DEBUG_INFO
- ("Replaced existing measurement: %d\n",
- res->u.spectrum.id);
- priv->measurement_status &= ~MEASUREMENT_READY;
- }
- priv->measurement_status |= MEASUREMENT_ACTIVE;
- rc = 0;
- break;
-
- case 1: /* Command will not be handled */
- rc = -EAGAIN;
- break;
- }
-
- dev_kfree_skb_any(cmd.meta.u.skb);
-
- return rc;
-}
-#endif
/******************************************************************************
*
@@ -1054,7 +844,7 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
IWL_WARNING("uCode did not respond OK.\n");
}
-static void iwl4965_rx_reply_error(struct iwl_priv *priv,
+static void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1070,47 +860,29 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv,
#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
- struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
+ struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
rxon->channel = csa->channel;
priv->staging_rxon.channel = csa->channel;
}
-static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
- if (!report->state) {
- IWL_DEBUG(IWL_DL_11H,
- "Spectrum Measure Notification: Start\n");
- return;
- }
-
- memcpy(&priv->measure_report, report, sizeof(*report));
- priv->measurement_status |= MEASUREMENT_READY;
-#endif
-}
-
-static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
+ struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src);
#endif
}
-static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1120,7 +892,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
}
-static void iwl4965_bg_beacon_update(struct work_struct *work)
+static void iwl_bg_beacon_update(struct work_struct *work)
{
struct iwl_priv *priv =
container_of(work, struct iwl_priv, beacon_update);
@@ -1142,11 +914,11 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
priv->ibss_beacon = beacon;
mutex_unlock(&priv->mutex);
- iwl4965_send_beacon_cmd(priv);
+ iwl_send_beacon_cmd(priv);
}
/**
- * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ * iwl_bg_statistics_periodic - Timer callback to queue statistics
*
* This callback is provided in order to send a statistics request.
*
@@ -1155,22 +927,27 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
* was received. We need to ensure we receive the statistics in order
* to update the temperature used for calibrating the TXPOWER.
*/
-static void iwl4965_bg_statistics_periodic(unsigned long data)
+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);
}
-static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
+ struct iwl4965_beacon_notif *beacon =
+ (struct iwl4965_beacon_notif *)pkt->u.raw;
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
IWL_DEBUG_RX("beacon status %x retries %d iss %d "
@@ -1189,7 +966,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
/* Handle notification from uCode that card's power state is changing
* due to software, hardware, or critical temperature RFKILL */
-static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1258,7 +1035,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
wake_up_interruptible(&priv->wait_command_queue);
}
-int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
+int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
{
int ret;
unsigned long flags;
@@ -1290,7 +1067,7 @@ err:
}
/**
- * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
+ * 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.
@@ -1301,14 +1078,12 @@ err:
static void iwl_setup_rx_handlers(struct iwl_priv *priv)
{
priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
- priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
- priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
- priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
- iwl4965_rx_spectrum_measure_notif;
- priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif;
+ priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+ priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
- iwl4965_rx_pm_debug_statistics_notif;
- priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
+ iwl_rx_pm_debug_statistics_notif;
+ priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
/*
* The same handler is used for both the REPLY to a discrete
@@ -1318,10 +1093,11 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
+ iwl_setup_spectrum_handlers(priv);
iwl_setup_rx_scan_handlers(priv);
/* status change handler */
- priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
+ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
iwl_rx_missed_beacon_notif;
@@ -1334,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
priv->cfg->ops->lib->rx_handler_setup(priv);
}
-/*
- * this should be called while priv->lock is locked
-*/
-static void __iwl_rx_replenish(struct iwl_priv *priv)
-{
- iwl_rx_allocate(priv);
- iwl_rx_queue_restock(priv);
-}
-
-
/**
* iwl_rx_handle - Main entry function for receiving responses from uCode
*
@@ -1364,7 +1130,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
- r = priv->cfg->ops->lib->shared_mem_rx_idx(priv);
+ r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
i = rxq->read;
/* Rx interrupt, but nothing sent from uCode */
@@ -1384,9 +1150,11 @@ void iwl_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
- pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->aligned_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_range_for_cpu(
+ &priv->pci_dev->dev, rxb->real_dma_addr,
+ rxb->aligned_dma_addr - rxb->real_dma_addr,
+ priv->hw_params.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
pkt = (struct iwl_rx_packet *)rxb->skb->data;
/* Reclaim a command buffer only if this packet is a response
@@ -1398,13 +1166,14 @@ void iwl_rx_handle(struct iwl_priv *priv)
reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
(pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
(pkt->hdr.cmd != REPLY_RX) &&
+ (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) &&
(pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
(pkt->hdr.cmd != REPLY_TX);
/* Based on type of command response or notification,
* handle those that need handling via function in
- * rx_handlers table. See iwl4965_setup_rx_handlers() */
+ * rx_handlers table. See iwl_setup_rx_handlers() */
if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r,
i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
@@ -1449,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
count++;
if (count >= 8) {
priv->rxq.read = i;
- __iwl_rx_replenish(priv);
+ iwl_rx_queue_restock(priv);
count = 0;
}
}
@@ -1461,10 +1230,9 @@ void iwl_rx_handle(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
+static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
- DECLARE_MAC_BUF(mac);
IWL_DEBUG_RADIO("RX CONFIG:\n");
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
@@ -1476,50 +1244,26 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
rxon->ofdm_basic_rates);
IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
- IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
- print_mac(mac, rxon->node_addr));
- IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
- print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr);
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
#endif
-static void iwl4965_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR("Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
-}
-
/* call this function to flush any scheduled tasklet */
static inline void iwl_synchronize_irq(struct iwl_priv *priv)
{
- /* wait to make sure we flush pedding tasklet*/
+ /* wait to make sure we flush pending tasklet*/
synchronize_irq(priv->pci_dev->irq);
tasklet_kill(&priv->irq_tasklet);
}
-static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR("Disabled interrupts\n");
-}
-
-
/**
- * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
-static void iwl4965_irq_handle_error(struct iwl_priv *priv)
+static void iwl_irq_handle_error(struct iwl_priv *priv)
{
- /* Set the FW error flag -- cleared on iwl4965_down */
+ /* Set the FW error flag -- cleared on iwl_down */
set_bit(STATUS_FW_ERROR, &priv->status);
/* Cancel currently queued command. */
@@ -1529,7 +1273,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
if (priv->debug_level & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv);
- iwl4965_print_rx_config_cmd(priv);
+ iwl_print_rx_config_cmd(priv);
}
#endif
@@ -1553,14 +1297,14 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
}
}
-static void iwl4965_error_recovery(struct iwl_priv *priv)
+static void iwl_error_recovery(struct iwl_priv *priv)
{
unsigned long flags;
memcpy(&priv->staging_rxon, &priv->recovery_rxon,
sizeof(priv->staging_rxon));
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
iwl_rxon_add_station(priv, priv->bssid, 1);
@@ -1570,7 +1314,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
-static void iwl4965_irq_tasklet(struct iwl_priv *priv)
+static void iwl_irq_tasklet(struct iwl_priv *priv)
{
u32 inta, handled = 0;
u32 inta_fh;
@@ -1616,9 +1360,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
IWL_ERROR("Microcode HW error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
- iwl4965_disable_interrupts(priv);
+ iwl_disable_interrupts(priv);
- iwl4965_irq_handle_error(priv);
+ iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_HW_ERR;
@@ -1650,14 +1394,17 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
hw_rf_kill = 1;
IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio":"enable radio");
+ hw_rf_kill ? "disable radio" : "enable radio");
/* driver only loads ucode once setting the interface up.
* the driver as well won't allow loading if RFKILL is set
* therefore no need to restart the driver from this handler
*/
- if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ if (priv->is_open && !iwl_is_rfkill(priv))
+ queue_work(priv->workqueue, &priv->up);
+ }
handled |= CSR_INT_BIT_RF_KILL;
}
@@ -1672,7 +1419,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
if (inta & CSR_INT_BIT_SW_ERR) {
IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
inta);
- iwl4965_irq_handle_error(priv);
+ iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
@@ -1718,7 +1465,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
/* Re-enable all interrupts */
/* only Re-enable if diabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
- iwl4965_enable_interrupts(priv);
+ iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) {
@@ -1732,7 +1479,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
-static irqreturn_t iwl4965_isr(int irq, void *data)
+static irqreturn_t iwl_isr(int irq, void *data)
{
struct iwl_priv *priv = data;
u32 inta, inta_mask;
@@ -1764,7 +1511,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
/* Hardware disappeared. It might have already raised
* an interrupt */
- IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta);
goto unplugged;
}
@@ -1773,7 +1520,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
inta &= ~CSR_INT_BIT_SCD;
- /* iwl4965_irq_tasklet() will service interrupts and re-enable them */
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
if (likely(inta || inta_fh))
tasklet_schedule(&priv->irq_tasklet);
@@ -1785,7 +1532,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
/* re-enable interrupts here since we don't have anything to service. */
/* only Re-enable if diabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
- iwl4965_enable_interrupts(priv);
+ iwl_enable_interrupts(priv);
spin_unlock(&priv->lock);
return IRQ_NONE;
}
@@ -1796,7 +1543,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
*
******************************************************************************/
-static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
{
iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
@@ -1806,7 +1553,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
}
-static void iwl4965_nic_start(struct iwl_priv *priv)
+static void iwl_nic_start(struct iwl_priv *priv)
{
/* Remove all resets to allow NIC to operate */
iwl_write32(priv, CSR_RESET, 0);
@@ -1814,31 +1561,47 @@ static void iwl4965_nic_start(struct iwl_priv *priv)
/**
- * iwl4965_read_ucode - Read uCode images from disk file.
+ * iwl_read_ucode - Read uCode images from disk file.
*
* Copy into buffers for card to fetch via bus-mastering
*/
-static int iwl4965_read_ucode(struct iwl_priv *priv)
+static int iwl_read_ucode(struct iwl_priv *priv)
{
struct iwl_ucode *ucode;
- int ret;
+ int ret = -EINVAL, index;
const struct firmware *ucode_raw;
- const char *name = priv->cfg->fw_name;
+ const char *name_pre = priv->cfg->fw_name_pre;
+ const unsigned int api_max = priv->cfg->ucode_api_max;
+ const unsigned int api_min = priv->cfg->ucode_api_min;
+ char buf[25];
u8 *src;
size_t len;
- u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
- ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
- if (ret < 0) {
- IWL_ERROR("%s firmware file req failed: Reason %d\n",
- name, ret);
- goto error;
+ for (index = api_max; index >= api_min; index--) {
+ sprintf(buf, "%s%d%s", name_pre, index, ".ucode");
+ ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev);
+ if (ret < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n",
+ buf, ret);
+ if (ret == -ENOENT)
+ continue;
+ else
+ goto error;
+ } else {
+ if (index < api_max)
+ IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n",
+ buf, api_max);
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ buf, ucode_raw->size);
+ break;
+ }
}
- IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
- name, ucode_raw->size);
+ if (ret < 0)
+ goto error;
/* Make sure that we got at least our header! */
if (ucode_raw->size < sizeof(*ucode)) {
@@ -1850,14 +1613,40 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
/* Data from ucode file: header followed by uCode images */
ucode = (void *)ucode_raw->data;
- ver = le32_to_cpu(ucode->ver);
+ priv->ucode_ver = le32_to_cpu(ucode->ver);
+ api_ver = IWL_UCODE_API(priv->ucode_ver);
inst_size = le32_to_cpu(ucode->inst_size);
data_size = le32_to_cpu(ucode->data_size);
init_size = le32_to_cpu(ucode->init_size);
init_data_size = le32_to_cpu(ucode->init_data_size);
boot_size = le32_to_cpu(ucode->boot_size);
- IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ /* api_ver should match the api version forming part of the
+ * firmware filename ... but we don't check for that and only rely
+ * on the API version read from firware header from here on forward */
+
+ if (api_ver < api_min || api_ver > api_max) {
+ IWL_ERROR("Driver unable to support your firmware API. "
+ "Driver supports v%u, firmware is v%u.\n",
+ api_max, api_ver);
+ priv->ucode_ver = 0;
+ ret = -EINVAL;
+ goto err_release;
+ }
+ if (api_ver != api_max)
+ IWL_ERROR("Firmware has old API version. Expected v%u, "
+ "got v%u. New firmware can be obtained "
+ "from http://www.intellinuxwireless.org.\n",
+ api_max, api_ver);
+
+ printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n",
+ IWL_UCODE_MAJOR(priv->ucode_ver),
+ IWL_UCODE_MINOR(priv->ucode_ver),
+ IWL_UCODE_API(priv->ucode_ver),
+ IWL_UCODE_SERIAL(priv->ucode_ver));
+
+ IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n",
+ priv->ucode_ver);
IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
inst_size);
IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
@@ -1962,7 +1751,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
- * NOTE: Copy into backup buffer will be done in iwl4965_up() */
+ * NOTE: Copy into backup buffer will be done in iwl_up() */
src = &ucode->data[inst_size];
len = priv->ucode_data.len;
IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
@@ -2000,7 +1789,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
err_pci_alloc:
IWL_ERROR("failed to allocate pci memory\n");
ret = -ENOMEM;
- iwl4965_dealloc_ucode_pci(priv);
+ iwl_dealloc_ucode_pci(priv);
err_release:
release_firmware(ucode_raw);
@@ -2009,6 +1798,10 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
return ret;
}
+/* temporary */
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *skb);
+
/**
* iwl_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
@@ -2045,7 +1838,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
goto restart;
}
- /* After the ALIVE response, we can send host commands to 4965 uCode */
+ /* After the ALIVE response, we can send host commands to the uCode */
set_bit(STATUS_ALIVE, &priv->status);
if (iwl_is_rfkill(priv))
@@ -2065,17 +1858,17 @@ static void iwl_alive_start(struct iwl_priv *priv)
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} else {
/* Initialize our rx_config data */
- iwl4965_connection_init_rx_config(priv);
+ iwl_connection_init_rx_config(priv, priv->iw_mode);
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
/* Configure Bluetooth device coexistence support */
- iwl4965_send_bt_config(priv);
+ iwl_send_bt_config(priv);
iwl_reset_run_time_calib(priv);
/* Configure the adapter for unassociated operation */
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
@@ -2087,12 +1880,21 @@ static void iwl_alive_start(struct iwl_priv *priv)
wake_up_interruptible(&priv->wait_command_queue);
if (priv->error_recovering)
- iwl4965_error_recovery(priv);
+ iwl_error_recovery(priv);
iwl_power_update_mode(priv, 1);
+ /* reassociate for ADHOC mode */
+ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
+ struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
+ priv->vif);
+ if (beacon)
+ iwl_mac_beacon_update(priv->hw, beacon);
+ }
+
+
if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
- iwl4965_set_mode(priv, priv->iw_mode);
+ iwl_set_mode(priv, priv->iw_mode);
return;
@@ -2102,7 +1904,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
static void iwl_cancel_deferred_work(struct iwl_priv *priv);
-static void __iwl4965_down(struct iwl_priv *priv)
+static void __iwl_down(struct iwl_priv *priv)
{
unsigned long flags;
int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -2129,14 +1931,14 @@ static void __iwl4965_down(struct iwl_priv *priv)
/* tell the device to stop sending interrupts */
spin_lock_irqsave(&priv->lock, flags);
- iwl4965_disable_interrupts(priv);
+ iwl_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_synchronize_irq(priv);
if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
- /* If we have not previously called iwl4965_init() then
+ /* If we have not previously called iwl_init() then
* clear all bits but the RF Kill and SUSPEND bits and return */
if (!iwl_is_init(priv)) {
priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
@@ -2190,8 +1992,6 @@ static void __iwl4965_down(struct iwl_priv *priv)
priv->cfg->ops->lib->apm_ops.stop(priv);
else
priv->cfg->ops->lib->apm_ops.reset(priv);
- priv->cfg->ops->lib->free_shared_mem(priv);
-
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -2203,10 +2003,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
iwl_clear_free_frames(priv);
}
-static void iwl4965_down(struct iwl_priv *priv)
+static void iwl_down(struct iwl_priv *priv)
{
mutex_lock(&priv->mutex);
- __iwl4965_down(priv);
+ __iwl_down(priv);
mutex_unlock(&priv->mutex);
iwl_cancel_deferred_work(priv);
@@ -2214,7 +2014,7 @@ static void iwl4965_down(struct iwl_priv *priv)
#define MAX_HW_RESTARTS 5
-static int __iwl4965_up(struct iwl_priv *priv)
+static int __iwl_up(struct iwl_priv *priv)
{
int i;
int ret;
@@ -2236,7 +2036,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
set_bit(STATUS_RF_KILL_HW, &priv->status);
if (iwl_is_rfkill(priv)) {
- iwl4965_enable_interrupts(priv);
+ iwl_enable_interrupts(priv);
IWL_WARNING("Radio disabled by %s RF Kill switch\n",
test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
return 0;
@@ -2244,12 +2044,6 @@ static int __iwl4965_up(struct iwl_priv *priv)
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
- if (ret) {
- IWL_ERROR("Unable to allocate shared memory\n");
- return ret;
- }
-
ret = iwl_hw_nic_init(priv);
if (ret) {
IWL_ERROR("Unable to init nic\n");
@@ -2263,7 +2057,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
/* clear (again), then enable host interrupts */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl4965_enable_interrupts(priv);
+ iwl_enable_interrupts(priv);
/* really make sure rfkill handshake bits are cleared */
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
@@ -2293,7 +2087,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
clear_bit(STATUS_FW_ERROR, &priv->status);
/* start card; "initialize" will load runtime ucode */
- iwl4965_nic_start(priv);
+ iwl_nic_start(priv);
IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
@@ -2301,7 +2095,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
}
set_bit(STATUS_EXIT_PENDING, &priv->status);
- __iwl4965_down(priv);
+ __iwl_down(priv);
clear_bit(STATUS_EXIT_PENDING, &priv->status);
/* tried to restart and config the device for as long as our
@@ -2343,7 +2137,7 @@ static void iwl_bg_alive_start(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
-static void iwl4965_bg_rf_kill(struct work_struct *work)
+static void iwl_bg_rf_kill(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
@@ -2377,28 +2171,6 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
iwl_rfkill_set_hw_state(priv);
}
-static void iwl4965_bg_set_monitor(struct work_struct *work)
-{
- struct iwl_priv *priv = container_of(work,
- struct iwl_priv, set_monitor);
- int ret;
-
- IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
- mutex_lock(&priv->mutex);
-
- ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR);
-
- if (ret) {
- if (ret == -EAGAIN)
- IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
- else
- IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret);
- }
-
- mutex_unlock(&priv->mutex);
-}
-
static void iwl_bg_run_time_calib_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2422,7 +2194,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
return;
}
-static void iwl4965_bg_up(struct work_struct *data)
+static void iwl_bg_up(struct work_struct *data)
{
struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
@@ -2430,23 +2202,23 @@ static void iwl4965_bg_up(struct work_struct *data)
return;
mutex_lock(&priv->mutex);
- __iwl4965_up(priv);
+ __iwl_up(priv);
mutex_unlock(&priv->mutex);
iwl_rfkill_set_hw_state(priv);
}
-static void iwl4965_bg_restart(struct work_struct *data)
+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;
- iwl4965_down(priv);
+ iwl_down(priv);
queue_work(priv->workqueue, &priv->up);
}
-static void iwl4965_bg_rx_replenish(struct work_struct *data)
+static void iwl_bg_rx_replenish(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, rx_replenish);
@@ -2461,11 +2233,10 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static void iwl4965_post_associate(struct iwl_priv *priv)
+static void iwl_post_associate(struct iwl_priv *priv)
{
struct ieee80211_conf *conf = NULL;
int ret = 0;
- DECLARE_MAC_BUF(mac);
unsigned long flags;
if (priv->iw_mode == NL80211_IFTYPE_AP) {
@@ -2473,9 +2244,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
return;
}
- IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
- priv->assoc_id,
- print_mac(mac, priv->active_rxon.bssid_addr));
+ IWL_DEBUG_ASSOC("Associated as %d to: %pM\n",
+ priv->assoc_id, priv->active_rxon.bssid_addr);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -2491,10 +2261,9 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
conf = ieee80211_get_hw_conf(priv->hw);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
- memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
- iwl4965_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (ret)
@@ -2527,7 +2296,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
}
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
switch (priv->iw_mode) {
case NL80211_IFTYPE_STATION:
@@ -2539,7 +2308,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
priv->assoc_id = 1;
iwl_rxon_add_station(priv, priv->bssid, 0);
- iwl4965_send_beacon_cmd(priv);
+ iwl_send_beacon_cmd(priv);
break;
@@ -2576,7 +2345,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
#define UCODE_READY_TIMEOUT (4 * HZ)
-static int iwl4965_mac_start(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
@@ -2598,7 +2367,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
}
- ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+ ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
DRV_NAME, priv);
if (ret) {
IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -2613,7 +2382,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
* ucode filename and max sizes are card-specific. */
if (!priv->ucode_code.len) {
- ret = iwl4965_read_ucode(priv);
+ ret = iwl_read_ucode(priv);
if (ret) {
IWL_ERROR("Could not read microcode: %d\n", ret);
mutex_unlock(&priv->mutex);
@@ -2621,7 +2390,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
}
}
- ret = __iwl4965_up(priv);
+ ret = __iwl_up(priv);
mutex_unlock(&priv->mutex);
@@ -2667,7 +2436,7 @@ out_disable_msi:
return ret;
}
-static void iwl4965_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -2689,7 +2458,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
mutex_unlock(&priv->mutex);
}
- iwl4965_down(priv);
+ iwl_down(priv);
flush_workqueue(priv->workqueue);
free_irq(priv->pci_dev->irq, priv);
@@ -2700,7 +2469,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
@@ -2716,12 +2485,11 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return 0;
}
-static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
@@ -2732,17 +2500,18 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
spin_lock_irqsave(&priv->lock, flags);
priv->vif = conf->vif;
+ priv->iw_mode = conf->type;
spin_unlock_irqrestore(&priv->lock, flags);
mutex_lock(&priv->mutex);
if (conf->mac_addr) {
- IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
+ IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr);
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
}
- if (iwl4965_set_mode(priv, conf->type) == -EAGAIN)
+ if (iwl_set_mode(priv, conf->type) == -EAGAIN)
/* we are not ready, will run again when ready */
set_bit(STATUS_MODE_PENDING, &priv->status);
@@ -2753,16 +2522,17 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
}
/**
- * iwl4965_mac_config - mac80211 config callback
+ * iwl_mac_config - mac80211 config callback
*
* We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
* be set inappropriately and the driver currently sets the hardware up to
* use it whenever needed.
*/
-static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
{
struct iwl_priv *priv = hw->priv;
const struct iwl_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
unsigned long flags;
int ret = 0;
u16 channel;
@@ -2770,6 +2540,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
+ priv->current_ht_config.is_ht = conf->ht.enabled;
+
if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
goto out;
@@ -2827,13 +2599,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset
* the rate mask to what mac80211 lists */
- iwl4965_set_rate(priv);
+ iwl_set_rate(priv);
spin_unlock_irqrestore(&priv->lock, flags);
#ifdef IEEE80211_CONF_CHANNEL_SWITCH
if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
- iwl4965_hw_channel_switch(priv, conf->channel);
+ iwl_hw_channel_switch(priv, conf->channel);
goto out;
}
#endif
@@ -2861,11 +2633,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
iwl_set_tx_power(priv, conf->power_level, false);
- iwl4965_set_rate(priv);
+ iwl_set_rate(priv);
if (memcmp(&priv->active_rxon,
&priv->staging_rxon, sizeof(priv->staging_rxon)))
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
else
IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
@@ -2876,7 +2648,7 @@ out:
return ret;
}
-static void iwl4965_config_ap(struct iwl_priv *priv)
+static void iwl_config_ap(struct iwl_priv *priv)
{
int ret = 0;
unsigned long flags;
@@ -2885,15 +2657,14 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
return;
/* The following should be done only at AP bring up */
- if (!(iwl_is_associated(priv))) {
+ if (!iwl_is_associated(priv)) {
/* RXON - unassoc (to set timing command) */
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
/* RXON Timing */
- memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
- iwl4965_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (ret)
@@ -2926,29 +2697,25 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_activate_qos(priv, 1);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
}
- iwl4965_send_beacon_cmd(priv);
+ iwl_send_beacon_cmd(priv);
/* FIXME - we need to add code here to detect a totally new
* configuration, reset the AP, unassoc, rxon timing, assoc,
* clear sta table, add BCAST sta... */
}
-/* temporary */
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+static int iwl_mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct iwl_priv *priv = hw->priv;
- DECLARE_MAC_BUF(mac);
- unsigned long flags;
int rc;
if (conf == NULL)
@@ -2964,26 +2731,20 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon)
return -ENOMEM;
- rc = iwl4965_mac_beacon_update(hw, beacon);
+ mutex_lock(&priv->mutex);
+ rc = iwl_mac_beacon_update(hw, beacon);
+ mutex_unlock(&priv->mutex);
if (rc)
return rc;
}
- if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
- (!conf->ssid_len)) {
- IWL_DEBUG_MAC80211
- ("Leaving in AP mode because HostAPD is not ready.\n");
- return 0;
- }
-
if (!iwl_is_alive(priv))
return -EAGAIN;
mutex_lock(&priv->mutex);
if (conf->bssid)
- IWL_DEBUG_MAC80211("bssid: %s\n",
- print_mac(mac, conf->bssid));
+ IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid);
/*
* very dubious code was here; the probe filtering flag is never set:
@@ -2996,8 +2757,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
if (!conf->bssid) {
conf->bssid = priv->mac_addr;
memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
- IWL_DEBUG_MAC80211("bssid was set to: %s\n",
- print_mac(mac, conf->bssid));
+ IWL_DEBUG_MAC80211("bssid was set to: %pM\n",
+ conf->bssid);
}
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
@@ -3028,9 +2789,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
if (priv->iw_mode == NL80211_IFTYPE_AP)
- iwl4965_config_ap(priv);
+ iwl_config_ap(priv);
else {
- rc = iwl4965_commit_rxon(priv);
+ rc = iwl_commit_rxon(priv);
if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
iwl_rxon_add_station(
priv, priv->active_rxon.bssid_addr, 1);
@@ -3039,45 +2800,63 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
} else {
iwl_scan_cancel_timeout(priv, 100);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
done:
- spin_lock_irqsave(&priv->lock, flags);
- if (!conf->ssid_len)
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
- else
- memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
- priv->essid_len = conf->ssid_len;
- spin_unlock_irqrestore(&priv->lock, flags);
-
IWL_DEBUG_MAC80211("leave\n");
mutex_unlock(&priv->mutex);
return 0;
}
-static void iwl4965_configure_filter(struct ieee80211_hw *hw,
+static void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list)
{
struct iwl_priv *priv = hw->priv;
+ __le32 *filter_flags = &priv->staging_rxon.filter_flags;
- if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
- IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- NL80211_IFTYPE_MONITOR,
- changed_flags, *total_flags);
- /* queue work 'cuz mac80211 is holding a lock which
- * prevents us from issuing (synchronous) f/w cmds */
- queue_work(priv->workqueue, &priv->set_monitor);
+ IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+ changed_flags, *total_flags);
+
+ if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+ if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+ *filter_flags |= RXON_FILTER_PROMISC_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
+ }
+ if (changed_flags & FIF_ALLMULTI) {
+ if (*total_flags & FIF_ALLMULTI)
+ *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+ }
+ if (changed_flags & FIF_CONTROL) {
+ if (*total_flags & FIF_CONTROL)
+ *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
}
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+ }
+
+ /* We avoid iwl_commit_rxon here to commit the new filter flags
+ * since mac80211 will call ieee80211_hw_config immediately.
+ * (mc_list is not supported at this time). Otherwise, we need to
+ * queue a background iwl_commit_rxon work.
+ */
+
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
-static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct iwl_priv *priv = hw->priv;
@@ -3089,13 +2868,11 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
if (iwl_is_ready_rf(priv)) {
iwl_scan_cancel_timeout(priv, 100);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
if (priv->vif == conf->vif) {
priv->vif = NULL;
memset(priv->bssid, 0, ETH_ALEN);
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
- priv->essid_len = 0;
}
mutex_unlock(&priv->mutex);
@@ -3104,7 +2881,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
}
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
-static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+static void iwl_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
@@ -3131,8 +2908,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
}
if (changes & BSS_CHANGED_HT) {
- IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
- iwl4965_ht_conf(priv, bss_conf);
+ iwl_ht_conf(priv, bss_conf);
iwl_set_rxon_chain(priv);
}
@@ -3155,7 +2931,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
priv->next_scan_jiffies = jiffies +
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
mutex_lock(&priv->mutex);
- iwl4965_post_associate(priv);
+ iwl_post_associate(priv);
mutex_unlock(&priv->mutex);
} else {
priv->assoc_id = 0;
@@ -3185,12 +2961,6 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
goto out_unlock;
}
- if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */
- ret = -EIO;
- IWL_ERROR("ERROR: APs don't scan\n");
- goto out_unlock;
- }
-
/* We don't schedule scan within next_scan_jiffies period.
* Avoid scanning during possible EAPOL exchange, return
* success immediately.
@@ -3231,64 +3001,24 @@ out_unlock:
return ret;
}
-static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
+static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *keyconf, const u8 *addr,
u32 iv32, u16 *phase1key)
{
- struct iwl_priv *priv = hw->priv;
- u8 sta_id = IWL_INVALID_STATION;
- unsigned long flags;
- __le16 key_flags = 0;
- int i;
- DECLARE_MAC_BUF(mac);
+ struct iwl_priv *priv = hw->priv;
IWL_DEBUG_MAC80211("enter\n");
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
- return;
- }
-
- if (iwl_scan_cancel(priv)) {
- /* cancel scan failed, just live w/ bad key and rely
- briefly on SW decryption */
- return;
- }
-
- key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (sta_id == priv->hw_params.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
-
- for (i = 0; i < 5; i++)
- priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
- cpu_to_le16(phase1key[i]);
-
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
+ iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_addr, const u8 *addr,
struct ieee80211_key_conf *key)
{
struct iwl_priv *priv = hw->priv;
- DECLARE_MAC_BUF(mac);
int ret = 0;
u8 sta_id = IWL_INVALID_STATION;
u8 is_default_wep_key = 0;
@@ -3306,8 +3036,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
sta_id = iwl_find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
+ IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+ addr);
return -EINVAL;
}
@@ -3355,7 +3085,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = hw->priv;
@@ -3374,11 +3104,6 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
- if (!priv->qos_data.qos_enable) {
- priv->qos_data.qos_active = 0;
- IWL_DEBUG_MAC80211("leave - qos not enabled\n");
- return 0;
- }
q = AC_NUM - 1 - queue;
spin_lock_irqsave(&priv->lock, flags);
@@ -3403,15 +3128,14 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
-static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct iwl_priv *priv = hw->priv;
- DECLARE_MAC_BUF(mac);
- IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
- print_mac(mac, sta->addr), tid);
+ IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n",
+ sta->addr, tid);
if (!(priv->cfg->sku & IWL_SKU_N))
return -EACCES;
@@ -3419,10 +3143,10 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
switch (action) {
case IEEE80211_AMPDU_RX_START:
IWL_DEBUG_HT("start Rx\n");
- return iwl_rx_agg_start(priv, sta->addr, tid, *ssn);
+ return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
case IEEE80211_AMPDU_RX_STOP:
IWL_DEBUG_HT("stop Rx\n");
- return iwl_rx_agg_stop(priv, sta->addr, tid);
+ return iwl_sta_rx_agg_stop(priv, sta->addr, tid);
case IEEE80211_AMPDU_TX_START:
IWL_DEBUG_HT("start Tx\n");
return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
@@ -3436,7 +3160,8 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
}
return 0;
}
-static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats)
{
struct iwl_priv *priv = hw->priv;
@@ -3471,7 +3196,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
return 0;
}
-static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct iwl_priv *priv = hw->priv;
@@ -3483,7 +3208,7 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
@@ -3527,7 +3252,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
if (priv->iw_mode != NL80211_IFTYPE_AP) {
iwl_scan_cancel_timeout(priv, 100);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
iwl_power_update_mode(priv, 0);
@@ -3550,31 +3275,28 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
return;
}
- iwl4965_set_rate(priv);
+ iwl_set_rate(priv);
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
__le64 timestamp;
- mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter\n");
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_MAC80211("leave - RF not ready\n");
- mutex_unlock(&priv->mutex);
return -EIO;
}
if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
IWL_DEBUG_MAC80211("leave - not IBSS\n");
- mutex_unlock(&priv->mutex);
return -EIO;
}
@@ -3594,9 +3316,8 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
iwl_reset_qos(priv);
- iwl4965_post_associate(priv);
+ iwl_post_associate(priv);
- mutex_unlock(&priv->mutex);
return 0;
}
@@ -3611,7 +3332,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
/*
* The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
@@ -3697,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
- return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
+
+ if (!iwl_is_ready_rf(priv))
+ return sprintf(buf, "off\n");
+ else
+ return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
}
static ssize_t store_tx_power(struct device *d,
@@ -3748,7 +3473,7 @@ static ssize_t store_flags(struct device *d,
else {
IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags);
priv->staging_rxon.flags = cpu_to_le32(flags);
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -3789,7 +3514,7 @@ static ssize_t store_filter_flags(struct device *d,
"0x%04X\n", filter_flags);
priv->staging_rxon.filter_flags =
cpu_to_le32(filter_flags);
- iwl4965_commit_rxon(priv);
+ iwl_commit_rxon(priv);
}
}
mutex_unlock(&priv->mutex);
@@ -3800,79 +3525,6 @@ static ssize_t store_filter_flags(struct device *d,
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
-
-static ssize_t show_measurement(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- struct iwl4965_spectrum_notification measure_report;
- u32 size = sizeof(measure_report), len = 0, ofs = 0;
- u8 *data = (u8 *)&measure_report;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (!(priv->measurement_status & MEASUREMENT_READY)) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
- }
- memcpy(&measure_report, &priv->measure_report, size);
- priv->measurement_status = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (size && (PAGE_SIZE - len)) {
- hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
- PAGE_SIZE - len, 1);
- len = strlen(buf);
- if (PAGE_SIZE - len)
- buf[len++] = '\n';
-
- ofs += 16;
- size -= min(size, 16U);
- }
-
- return len;
-}
-
-static ssize_t store_measurement(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- struct ieee80211_measurement_params params = {
- .channel = le16_to_cpu(priv->active_rxon.channel),
- .start_time = cpu_to_le64(priv->last_tsf),
- .duration = cpu_to_le16(1),
- };
- u8 type = IWL_MEASURE_BASIC;
- u8 buffer[32];
- u8 channel;
-
- if (count) {
- char *p = buffer;
- strncpy(buffer, buf, min(sizeof(buffer), count));
- channel = simple_strtoul(p, NULL, 0);
- if (channel)
- params.channel = channel;
-
- p = buffer;
- while (*p && *p != ' ')
- p++;
- if (*p)
- type = simple_strtoul(p + 1, NULL, 0);
- }
-
- IWL_DEBUG_INFO("Invoking measurement of type %d on "
- "channel %d (for '%s')\n", type, params.channel, buf);
- iwl4965_get_measurement(priv, &params, type);
-
- return count;
-}
-
-static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
- show_measurement, store_measurement);
-#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */
-
static ssize_t store_retry_rate(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -3951,7 +3603,8 @@ static ssize_t show_power_level(struct device *d,
break;
}
- p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto");
+ p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
+ "fixed" : "auto");
p += sprintf(p, "\tINDEX:%d", level);
p += sprintf(p, "\n");
return p - buf + 1;
@@ -3960,68 +3613,6 @@ static ssize_t show_power_level(struct device *d,
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level);
-static ssize_t show_channels(struct device *d,
- struct device_attribute *attr, char *buf)
-{
-
- struct iwl_priv *priv = dev_get_drvdata(d);
- struct ieee80211_channel *channels = NULL;
- const struct ieee80211_supported_band *supp_band = NULL;
- int len = 0, i;
- int count = 0;
-
- if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
- return -EAGAIN;
-
- supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
- channels = supp_band->channels;
- count = supp_band->n_channels;
-
- len += sprintf(&buf[len],
- "Displaying %d channels in 2.4GHz band "
- "(802.11bg):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- ieee80211_frequency_to_channel(
- channels[i].center_freq),
- 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);
- channels = supp_band->channels;
- count = supp_band->n_channels;
-
- len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
- "(802.11a):\n", count);
-
- for (i = 0; i < count; i++)
- len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
- ieee80211_frequency_to_channel(
- channels[i].center_freq),
- 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");
-
- return len;
-}
-
-static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -4084,12 +3675,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
init_waitqueue_head(&priv->wait_command_queue);
- INIT_WORK(&priv->up, iwl4965_bg_up);
- INIT_WORK(&priv->restart, iwl4965_bg_restart);
- INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish);
- INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
- INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
- INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
+ INIT_WORK(&priv->up, iwl_bg_up);
+ INIT_WORK(&priv->restart, iwl_bg_restart);
+ INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+ INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -4102,10 +3692,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
init_timer(&priv->statistics_periodic);
priv->statistics_periodic.data = (unsigned long)priv;
- priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+ priv->statistics_periodic.function = iwl_bg_statistics_periodic;
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
- iwl4965_irq_tasklet, (unsigned long)priv);
+ iwl_irq_tasklet, (unsigned long)priv);
}
static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -4121,13 +3711,9 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
del_timer_sync(&priv->statistics_periodic);
}
-static struct attribute *iwl4965_sysfs_entries[] = {
- &dev_attr_channels.attr,
+static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_flags.attr,
&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
- &dev_attr_measurement.attr,
-#endif
&dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
&dev_attr_statistics.attr,
@@ -4142,39 +3728,38 @@ static struct attribute *iwl4965_sysfs_entries[] = {
NULL
};
-static struct attribute_group iwl4965_attribute_group = {
+static struct attribute_group iwl_attribute_group = {
.name = NULL, /* put in device directory */
- .attrs = iwl4965_sysfs_entries,
+ .attrs = iwl_sysfs_entries,
};
-static struct ieee80211_ops iwl4965_hw_ops = {
- .tx = iwl4965_mac_tx,
- .start = iwl4965_mac_start,
- .stop = iwl4965_mac_stop,
- .add_interface = iwl4965_mac_add_interface,
- .remove_interface = iwl4965_mac_remove_interface,
- .config = iwl4965_mac_config,
- .config_interface = iwl4965_mac_config_interface,
- .configure_filter = iwl4965_configure_filter,
- .set_key = iwl4965_mac_set_key,
- .update_tkip_key = iwl4965_mac_update_tkip_key,
- .get_stats = iwl4965_mac_get_stats,
- .get_tx_stats = iwl4965_mac_get_tx_stats,
- .conf_tx = iwl4965_mac_conf_tx,
- .reset_tsf = iwl4965_mac_reset_tsf,
- .bss_info_changed = iwl4965_bss_info_changed,
- .ampdu_action = iwl4965_mac_ampdu_action,
+static struct ieee80211_ops iwl_hw_ops = {
+ .tx = iwl_mac_tx,
+ .start = iwl_mac_start,
+ .stop = iwl_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
+ .configure_filter = iwl_configure_filter,
+ .set_key = iwl_mac_set_key,
+ .update_tkip_key = iwl_mac_update_tkip_key,
+ .get_stats = iwl_mac_get_stats,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .bss_info_changed = iwl_bss_info_changed,
+ .ampdu_action = iwl_mac_ampdu_action,
.hw_scan = iwl_mac_hw_scan
};
-static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = 0;
struct iwl_priv *priv;
struct ieee80211_hw *hw;
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
unsigned long flags;
- DECLARE_MAC_BUF(mac);
/************************
* 1. Allocating HW data
@@ -4186,10 +3771,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (cfg->mod_params->debug & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n");
- iwl4965_hw_ops.hw_scan = NULL;
+ iwl_hw_ops.hw_scan = NULL;
}
- hw = iwl_alloc_all(cfg, &iwl4965_hw_ops);
+ hw = iwl_alloc_all(cfg, &iwl_hw_ops);
if (!hw) {
err = -ENOMEM;
goto out;
@@ -4283,7 +3868,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/* extract MAC Address */
iwl_eeprom_get_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+ IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
/************************
@@ -4317,10 +3902,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
* 8. Setup services
********************/
spin_lock_irqsave(&priv->lock, flags);
- iwl4965_disable_interrupts(priv);
+ iwl_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
if (err) {
IWL_ERROR("failed to create sysfs device attributes\n");
goto out_uninit_drv;
@@ -4356,7 +3941,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
return 0;
out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
out_uninit_drv:
iwl_uninit_drv(priv);
out_free_eeprom:
@@ -4374,7 +3959,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
return err;
}
-static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
+static void __devexit iwl_pci_remove(struct pci_dev *pdev)
{
struct iwl_priv *priv = pci_get_drvdata(pdev);
unsigned long flags;
@@ -4385,10 +3970,10 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
iwl_dbgfs_unregister(priv);
- sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
- /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
- * to be called and iwl4965_down since we are removing the device
+ /* ieee80211_unregister_hw call wil cause iwl_mac_stop to
+ * to be called and iwl_down since we are removing the device
* we need to set STATUS_EXIT_PENDING bit.
*/
set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -4396,20 +3981,20 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
} else {
- iwl4965_down(priv);
+ iwl_down(priv);
}
/* make sure we flush any pending irq or
* tasklet for the driver
*/
spin_lock_irqsave(&priv->lock, flags);
- iwl4965_disable_interrupts(priv);
+ iwl_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_synchronize_irq(priv);
iwl_rfkill_unregister(priv);
- iwl4965_dealloc_ucode_pci(priv);
+ iwl_dealloc_ucode_pci(priv);
if (priv->rxq.bd)
iwl_rx_queue_free(priv, &priv->rxq);
@@ -4422,7 +4007,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
- /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes
+ /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
* priv->workqueue... so we can't take down the workqueue
* until now... */
destroy_workqueue(priv->workqueue);
@@ -4443,13 +4028,13 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
-static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct iwl_priv *priv = pci_get_drvdata(pdev);
if (priv->is_open) {
set_bit(STATUS_IN_SUSPEND, &priv->status);
- iwl4965_mac_stop(priv->hw);
+ iwl_mac_stop(priv->hw);
priv->is_open = 1;
}
@@ -4458,14 +4043,14 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-static int iwl4965_pci_resume(struct pci_dev *pdev)
+static int iwl_pci_resume(struct pci_dev *pdev)
{
struct iwl_priv *priv = pci_get_drvdata(pdev);
pci_set_power_state(pdev, PCI_D0);
if (priv->is_open)
- iwl4965_mac_start(priv->hw);
+ iwl_mac_start(priv->hw);
clear_bit(STATUS_IN_SUSPEND, &priv->status);
return 0;
@@ -4500,7 +4085,11 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)},
{IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)},
{IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)},
+/* 5150 Wifi/WiMax */
+ {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
+ {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
#endif /* CONFIG_IWL5000 */
+
{0}
};
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
@@ -4508,15 +4097,15 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
static struct pci_driver iwl_driver = {
.name = DRV_NAME,
.id_table = iwl_hw_card_ids,
- .probe = iwl4965_pci_probe,
- .remove = __devexit_p(iwl4965_pci_remove),
+ .probe = iwl_pci_probe,
+ .remove = __devexit_p(iwl_pci_remove),
#ifdef CONFIG_PM
- .suspend = iwl4965_pci_suspend,
- .resume = iwl4965_pci_resume,
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
#endif
};
-static int __init iwl4965_init(void)
+static int __init iwl_init(void)
{
int ret;
@@ -4542,11 +4131,11 @@ error_register:
return ret;
}
-static void __exit iwl4965_exit(void)
+static void __exit iwl_exit(void)
{
pci_unregister_driver(&iwl_driver);
iwlagn_rate_control_unregister();
}
-module_exit(iwl4965_exit);
-module_init(iwl4965_init);
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 72fbf47229d..f836ecc5575 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -70,7 +70,16 @@
* INIT calibrations framework
*****************************************************************************/
- int iwl_send_calib_results(struct iwl_priv *priv)
+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)
{
int ret = 0;
int i = 0;
@@ -80,14 +89,16 @@
.meta.flags = CMD_SIZE_HUGE,
};
- for (i = 0; i < IWL_CALIB_MAX; i++)
- if (priv->calib_results[i].buf) {
+ for (i = 0; i < IWL_CALIB_MAX; i++) {
+ if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
+ priv->calib_results[i].buf) {
hcmd.len = priv->calib_results[i].buf_len;
hcmd.data = priv->calib_results[i].buf;
ret = iwl_send_cmd_sync(priv, &hcmd);
if (ret)
goto err;
}
+ }
return 0;
err:
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
index 94c8e316382..1abe84bb74a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 8d04e966ad4..52966ffbef6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -66,8 +66,14 @@
* Please use iwl-dev.h for driver implementation definitions.
*/
-#ifndef __iwl4965_commands_h__
-#define __iwl4965_commands_h__
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+/* uCode version contains 4 values: Major/Minor/API/Serial */
+#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24)
+#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16)
+#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8)
+#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF)
enum {
REPLY_ALIVE = 0x1,
@@ -88,6 +94,7 @@ enum {
REPLY_WEPKEY = 0x20,
/* RX, TX, LEDs */
+ REPLY_3945_RX = 0x1b, /* 3945 only */
REPLY_TX = 0x1c,
REPLY_RATE_SCALE = 0x47, /* 3945 only */
REPLY_LEDS_CMD = 0x48,
@@ -98,6 +105,11 @@ enum {
COEX_MEDIUM_NOTIFICATION = 0x5b,
COEX_EVENT_CMD = 0x5c,
+ /* Calibration */
+ CALIBRATION_CFG_CMD = 0x65,
+ CALIBRATION_RES_NOTIFICATION = 0x66,
+ CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
+
/* 802.11h related */
RADAR_NOTIFICATION = 0x70, /* not used */
REPLY_QUIET_CMD = 0x71, /* not used */
@@ -129,7 +141,7 @@ enum {
REPLY_TX_POWER_DBM_CMD = 0x98,
MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
- /* Bluetooth device coexistance config command */
+ /* Bluetooth device coexistence config command */
REPLY_BT_CONFIG = 0x9b,
/* Statistics */
@@ -167,8 +179,8 @@ enum {
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
#define SEQ_TO_INDEX(s) ((s) & 0xff)
#define INDEX_TO_SEQ(i) ((i) & 0xff)
-#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000)
-#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000)
+#define SEQ_HUGE_FRAME cpu_to_le16(0x4000)
+#define SEQ_RX_FRAME cpu_to_le16(0x8000)
/**
* struct iwl_cmd_header
@@ -180,7 +192,7 @@ struct iwl_cmd_header {
u8 cmd; /* Command ID: REPLY_RXON, etc. */
u8 flags; /* 0:5 reserved, 6 abort, 7 internal */
/*
- * The driver sets up the sequence number to values of its chosing.
+ * The driver sets up the sequence number to values of its choosing.
* uCode does not use this value, but passes it back to the driver
* when sending the response to each driver-originated command, so
* the driver can match the response to the command. Since the values
@@ -208,10 +220,11 @@ struct iwl_cmd_header {
} __attribute__ ((packed));
/**
- * 4965 rate_n_flags bit fields
+ * iwlagn rate_n_flags bit fields
*
- * rate_n_flags format is used in following 4965 commands:
+ * 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
*
@@ -225,8 +238,9 @@ struct iwl_cmd_header {
* 6) 54 Mbps
* 7) 60 Mbps
*
- * 3: 0) Single stream (SISO)
+ * 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 FAT duplicate data
*
@@ -247,8 +261,8 @@ struct iwl_cmd_header {
* 110) 11 Mbps
*/
#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_MIMO_POS 3
-#define RATE_MCS_MIMO_MSK 0x8
+#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
@@ -278,18 +292,20 @@ struct iwl_cmd_header {
#define RATE_MCS_SGI_MSK 0x2000
/**
- * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
- * bit14:15 01 B inactive, A active
- * 10 B active, A inactive
- * 11 Both active
+ * 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_ABC_MSK 0x1C000
-
-#define RATE_MCS_ANT_INIT_IND 1
+#define RATE_ANT_NUM 3
#define POWER_TABLE_NUM_ENTRIES 33
#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
@@ -340,7 +356,7 @@ struct iwl4965_tx_power_db {
} __attribute__ ((packed));
/**
- * Commad REPLY_TX_POWER_DBM_CMD = 0x98
+ * Command REPLY_TX_POWER_DBM_CMD = 0x98
* struct iwl5000_tx_power_dbm_cmd
*/
#define IWL50_TX_POWER_AUTO 0x7f
@@ -359,7 +375,7 @@ struct iwl5000_tx_power_dbm_cmd {
*
*****************************************************************************/
-#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
+#define UCODE_VALID_OK cpu_to_le32(0x1)
#define INITIALIZE_SUBTYPE (9)
/*
@@ -376,7 +392,7 @@ struct iwl5000_tx_power_dbm_cmd {
* calculating txpower settings:
*
* 1) Power supply voltage indication. The voltage sensor outputs higher
- * values for lower voltage, and vice versa.
+ * values for lower voltage, and vice verse.
*
* 2) Temperature measurement parameters, for each of two channel widths
* (20 MHz and 40 MHz) supported by the radios. Temperature sensing
@@ -477,11 +493,6 @@ struct iwl_alive_resp {
} __attribute__ ((packed));
-union tsf {
- u8 byte[8];
- __le16 word[4];
- __le32 dw[2];
-};
/*
* REPLY_ERROR = 0x2 (response only, not a command)
@@ -492,7 +503,7 @@ struct iwl_error_resp {
u8 reserved1;
__le16 bad_cmd_seq_num;
__le32 error_info;
- union tsf timestamp;
+ __le64 timestamp;
} __attribute__ ((packed));
/******************************************************************************
@@ -513,75 +524,75 @@ enum {
};
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0)
-#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK cpu_to_le16(0x1 << 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 __constant_cpu_to_le16(0x7 << 4)
+#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 __constant_cpu_to_le16(0x7 << 7)
+#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 __constant_cpu_to_le16(0x3 << 10)
+#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 __constant_cpu_to_le16(0x3 << 12)
+#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 __constant_cpu_to_le16(0x1 << 14)
+#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 __constant_cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1)
+#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 __constant_cpu_to_le32(1 << 2)
+#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2)
/* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3)
+#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3)
/* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5)
+#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 __constant_cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#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 __constant_cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13)
+#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 __constant_cpu_to_le32(1 << 15)
+#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 __constant_cpu_to_le32(0x1 << 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 __constant_cpu_to_le32(0x1 << 23)
-#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23)
+#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23)
+#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23)
#define RXON_FLG_CHANNEL_MODE_POS (25)
-#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25)
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25)
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25)
+#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25)
/* CTS to self (if spec allows) flag */
-#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30)
+#define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30)
/* rx_config filter flags */
/* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0)
+#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0)
/* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1)
+#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1)
/* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2)
+#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2)
/* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3)
+#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3)
/* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4)
/* STA is associated */
-#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5)
+#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 __constant_cpu_to_le32(1 << 6)
+#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6)
/**
* REPLY_RXON = 0x10 (command, has simple generic response)
@@ -620,7 +631,7 @@ struct iwl4965_rxon_cmd {
u8 ofdm_ht_dual_stream_basic_rates;
} __attribute__ ((packed));
-/* 5000 HW just extend this cmmand */
+/* 5000 HW just extend this command */
struct iwl_rxon_cmd {
u8 node_addr[6];
__le16 reserved1;
@@ -679,8 +690,8 @@ struct iwl4965_rxon_assoc_cmd {
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
*/
-struct iwl4965_rxon_time_cmd {
- union tsf timestamp;
+struct iwl_rxon_time_cmd {
+ __le64 timestamp;
__le16 beacon_interval;
__le16 atim_window;
__le32 beacon_init_val;
@@ -691,7 +702,7 @@ struct iwl4965_rxon_time_cmd {
/*
* REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
*/
-struct iwl4965_channel_switch_cmd {
+struct iwl_channel_switch_cmd {
u8 band;
u8 expect_beacon;
__le16 channel;
@@ -704,7 +715,7 @@ struct iwl4965_channel_switch_cmd {
/*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
*/
-struct iwl4965_csa_notification {
+struct iwl_csa_notification {
__le16 band;
__le16 channel;
__le32 status; /* 0 - OK, 1 - fail */
@@ -741,9 +752,9 @@ struct iwl_ac_qos {
} __attribute__ ((packed));
/* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10)
+#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
@@ -780,34 +791,34 @@ struct iwl_qosparam_cmd {
#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
#define IWL_INVALID_STATION 255
-#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8);
-#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18)
+#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8);
+#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 __constant_cpu_to_le32(3 << 19)
-#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22)
+#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_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 __constant_cpu_to_le32(7 << 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 __constant_cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x0003)
+#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 __constant_cpu_to_le16(0x0800)
+#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 __constant_cpu_to_le16(0x0008)
+#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 __constant_cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
+#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
/* Flags indicate whether to modify vs. don't change various station params */
@@ -1013,33 +1024,14 @@ struct iwl_wep_cmd {
*
*****************************************************************************/
-struct iwl4965_rx_frame_stats {
- u8 phy_count;
- u8 id;
- u8 rssi;
- u8 agc;
- __le16 sig_avg;
- __le16 noise_diff;
- u8 payload[0];
-} __attribute__ ((packed));
-
-struct iwl4965_rx_frame_hdr {
- __le16 channel;
- __le16 phy_flags;
- u8 reserved1;
- u8 rate;
- __le16 len;
- u8 payload[0];
-} __attribute__ ((packed));
-
-#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+#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 __constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+#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 cpu_to_le16(0xf0)
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
@@ -1062,26 +1054,6 @@ struct iwl4965_rx_frame_hdr {
#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7)
#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800)
-struct iwl4965_rx_frame_end {
- __le32 status;
- __le64 timestamp;
- __le32 beacon_timestamp;
-} __attribute__ ((packed));
-
-/*
- * REPLY_3945_RX = 0x1b (response only, not a command)
- *
- * NOTE: DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count
- */
-struct iwl4965_rx_frame {
- struct iwl4965_rx_frame_stats stats;
- struct iwl4965_rx_frame_hdr hdr;
- struct iwl4965_rx_frame_end end;
-} __attribute__ ((packed));
-
/* Fixed (non-configurable) rx data from phy */
#define IWL49_RX_RES_PHY_CNT 14
@@ -1111,7 +1083,7 @@ struct iwl4965_rx_non_cfg_phy {
#define IWL50_OFDM_RSSI_C_BIT_POS 0
struct iwl5000_non_cfg_phy {
- __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */
+ __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */
} __attribute__ ((packed));
@@ -1167,24 +1139,24 @@ struct iwl4965_rx_mpdu_res_start {
/* REPLY_TX Tx flags field */
-/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it
+/* 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_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0)
+#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0)
/* 1: Use Request-To-Send protocol before this frame.
* Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
-#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)
/* 1: Transmit Clear-To-Send to self before this frame.
* Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
* Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
-#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)
/* 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 __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
/* For 4965:
* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
@@ -1192,40 +1164,40 @@ struct iwl4965_rx_mpdu_res_start {
* 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 __constant_cpu_to_le32(1 << 4)
+#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 __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6)
/* 1: Frame requires full Tx-Op protection.
* Set this if either RTS or CTS Tx Flag gets set. */
-#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
* Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
-#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
-#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9)
/* 1: Ignore Bluetooth priority for this frame.
* 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+#define TX_CMD_FLG_BT_DIS_MSK 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 __constant_cpu_to_le32(1 << 13)
+#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 __constant_cpu_to_le32(1 << 14)
+#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 __constant_cpu_to_le32(1 << 16)
+#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.
@@ -1233,14 +1205,14 @@ struct iwl4965_rx_mpdu_res_start {
* 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 __constant_cpu_to_le32(1 << 20)
+#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 __constant_cpu_to_le32(1 << 22)
+#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22)
/* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25)
/*
@@ -1266,7 +1238,7 @@ struct iwl4965_rx_mpdu_res_start {
* Used for managing Tx retries when expecting block-acks.
* Driver should set these fields to 0.
*/
-struct iwl4965_dram_scratch {
+struct iwl_dram_scratch {
u8 try_cnt; /* Tx attempts */
u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */
__le16 reserved;
@@ -1297,9 +1269,9 @@ struct iwl_tx_cmd {
__le32 tx_flags; /* TX_CMD_FLG_* */
- /* 4965's uCode may modify this field of the Tx command (in host DRAM!).
+ /* 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 iwl4965_dram_scratch scratch;
+ 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_* */
@@ -1411,21 +1383,21 @@ enum {
};
enum {
- TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */
+ 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_RESERVED = 0x00780000, /* bits 19:22 */
TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
};
-static inline int iwl_is_tx_success(u32 status)
+static inline bool iwl_is_tx_success(u32 status)
{
status &= TX_STATUS_MSK;
- return (status == TX_STATUS_SUCCESS)
- || (status == TX_STATUS_DIRECT_DONE);
+ return (status == TX_STATUS_SUCCESS) ||
+ (status == TX_STATUS_DIRECT_DONE);
}
@@ -1450,10 +1422,9 @@ enum {
AGG_TX_STATE_DELAY_TX_MSK = 0x400
};
-#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)
+#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
@@ -1526,6 +1497,28 @@ struct iwl4965_tx_resp {
} u;
} __attribute__ ((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 IWL50_TX_RES_TID_POS 0
+#define IWL50_TX_RES_TID_MSK 0x0f
+#define IWL50_TX_RES_RA_POS 4
+#define IWL50_TX_RES_RA_MSK 0xf0
+
struct iwl5000_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
@@ -1540,14 +1533,17 @@ struct iwl5000_tx_resp {
* For agg: RTS + CTS + aggregation tx time + block-ack time. */
__le16 wireless_media_time; /* uSecs */
- __le16 reserved;
- __le32 pa_power1; /* RF power amplifier measurement (not used) */
- __le32 pa_power2;
+ 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;
- __le32 tlc_info;
+ 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
@@ -1742,7 +1738,7 @@ struct iwl_link_qual_agg_params {
* 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 acknowledgement from the destination
+ * 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.
@@ -1881,9 +1877,9 @@ struct iwl_link_quality_cmd {
*
* 3945 and 4965 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 accomodate.
+ * wireless device can delay or kill its own Tx to accommodate.
*/
-struct iwl4965_bt_cmd {
+struct iwl_bt_cmd {
u8 flags;
u8 lead_time;
u8 max_kill;
@@ -1909,18 +1905,18 @@ struct iwl4965_bt_cmd {
RXON_FILTER_ASSOC_MSK | \
RXON_FILTER_BCON_AWARE_MSK)
-struct iwl4965_measure_channel {
+struct iwl_measure_channel {
__le32 duration; /* measurement duration in extended beacon
* format */
u8 channel; /* channel to measure */
- u8 type; /* see enum iwl4965_measure_type */
+ u8 type; /* see enum iwl_measure_type */
__le16 reserved;
} __attribute__ ((packed));
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
*/
-struct iwl4965_spectrum_cmd {
+struct iwl_spectrum_cmd {
__le16 len; /* number of bytes starting from token */
u8 token; /* token id */
u8 id; /* measurement id -- 0 or 1 */
@@ -1933,13 +1929,13 @@ struct iwl4965_spectrum_cmd {
__le32 filter_flags; /* rxon filter flags */
__le16 channel_count; /* minimum 1, maximum 10 */
__le16 reserved3;
- struct iwl4965_measure_channel channels[10];
+ struct iwl_measure_channel channels[10];
} __attribute__ ((packed));
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
*/
-struct iwl4965_spectrum_resp {
+struct iwl_spectrum_resp {
u8 token;
u8 id; /* id of the prior command replaced, or 0xff */
__le16 status; /* 0 - command will be handled
@@ -1947,12 +1943,12 @@ struct iwl4965_spectrum_resp {
* measurement) */
} __attribute__ ((packed));
-enum iwl4965_measurement_state {
+enum iwl_measurement_state {
IWL_MEASUREMENT_START = 0,
IWL_MEASUREMENT_STOP = 1,
};
-enum iwl4965_measurement_status {
+enum iwl_measurement_status {
IWL_MEASUREMENT_OK = 0,
IWL_MEASUREMENT_CONCURRENT = 1,
IWL_MEASUREMENT_CSA_CONFLICT = 2,
@@ -1965,18 +1961,18 @@ enum iwl4965_measurement_status {
#define NUM_ELEMENTS_IN_HISTOGRAM 8
-struct iwl4965_measurement_histogram {
+struct iwl_measurement_histogram {
__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */
} __attribute__ ((packed));
/* clear channel availability counters */
-struct iwl4965_measurement_cca_counters {
+struct iwl_measurement_cca_counters {
__le32 ofdm;
__le32 cck;
} __attribute__ ((packed));
-enum iwl4965_measure_type {
+enum iwl_measure_type {
IWL_MEASURE_BASIC = (1 << 0),
IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
@@ -1989,7 +1985,7 @@ enum iwl4965_measure_type {
/*
* SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
*/
-struct iwl4965_spectrum_notification {
+struct iwl_spectrum_notification {
u8 id; /* measurement id -- 0 or 1 */
u8 token;
u8 channel_index; /* index in measurement channel list */
@@ -1997,7 +1993,7 @@ struct iwl4965_spectrum_notification {
__le32 start_time; /* lower 32-bits of TSF */
u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */
u8 channel;
- u8 type; /* see enum iwl4965_measurement_type */
+ 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. */
@@ -2007,9 +2003,9 @@ struct iwl4965_spectrum_notification {
u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 -
* unidentified */
u8 reserved2[3];
- struct iwl4965_measurement_histogram histogram;
+ struct iwl_measurement_histogram histogram;
__le32 stop_time; /* lower 32-bits of TSF */
- __le32 status; /* see iwl4965_measurement_status */
+ __le32 status; /* see iwl_measurement_status */
} __attribute__ ((packed));
/******************************************************************************
@@ -2043,15 +2039,15 @@ struct iwl4965_spectrum_notification {
* '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 wakeup
+ * 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 __constant_cpu_to_le16(1 << 0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2)
-#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3)
-#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4)
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(1 << 2)
+#define IWL_POWER_PCI_PM_MSK cpu_to_le16(1 << 3)
+#define IWL_POWER_FAST_PD cpu_to_le16(1 << 4)
struct iwl_powertable_cmd {
__le16 flags;
@@ -2067,7 +2063,7 @@ struct iwl_powertable_cmd {
* PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
* 3945 and 4965 identical.
*/
-struct iwl4965_sleep_notification {
+struct iwl_sleep_notification {
u8 pm_sleep_mode;
u8 pm_wakeup_src;
__le16 reserved;
@@ -2097,14 +2093,14 @@ enum {
#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 iwl4965_card_state_cmd {
+struct iwl_card_state_cmd {
__le32 status; /* CARD_STATE_CMD_* request new power state */
} __attribute__ ((packed));
/*
* CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
*/
-struct iwl4965_card_state_notif {
+struct iwl_card_state_notif {
__le32 flags;
} __attribute__ ((packed));
@@ -2125,8 +2121,8 @@ struct iwl_ct_kill_config {
*
*****************************************************************************/
-#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0)
-#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1)
+#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
@@ -2167,7 +2163,7 @@ struct iwl_scan_channel {
* struct iwl_ssid_ie - directed scan network information element
*
* Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
- * in struct iwl4965_scan_channel; each channel may select different ssids from
+ * in struct iwl_scan_channel; each channel may select different ssids from
* among the 4 entries. SSID IEs get transmitted in reverse order of entry.
*/
struct iwl_ssid_ie {
@@ -2177,8 +2173,8 @@ struct iwl_ssid_ie {
} __attribute__ ((packed));
#define PROBE_OPTION_MAX 0x14
-#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
+#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH cpu_to_le16(1)
#define IWL_MAX_SCAN_SIZE 1024
/*
@@ -2267,7 +2263,7 @@ struct iwl_scan_cmd {
* Number of channels in list is specified by channel_count.
* Each channel in list is of type:
*
- * struct iwl4965_scan_channel channels[0];
+ * 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
@@ -2278,7 +2274,7 @@ struct iwl_scan_cmd {
} __attribute__ ((packed));
/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1)
+#define CAN_ABORT_STATUS cpu_to_le32(0x1)
/* complete notification statuses */
#define ABORT_STATUS 0x2
@@ -2422,6 +2418,8 @@ struct statistics_rx_ht_phy {
__le32 reserved2;
} __attribute__ ((packed));
+#define INTERFERENCE_DATA_AVAILABLE __constant_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 */
@@ -2540,8 +2538,8 @@ struct statistics_general {
* 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 __constant_cpu_to_le32(0x1) /* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+#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_* */
} __attribute__ ((packed));
@@ -2561,8 +2559,8 @@ struct iwl_statistics_cmd {
* appropriately so that each notification contains statistics for only the
* one channel that has just been scanned.
*/
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8)
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8)
struct iwl_notif_statistics {
__le32 flag;
struct statistics_rx rx;
@@ -2578,7 +2576,7 @@ struct iwl_notif_statistics {
* then this notification will be sent. */
#define CONSECUTIVE_MISSED_BCONS_TH 20
-struct iwl4965_missed_beacon_notif {
+struct iwl_missed_beacon_notif {
__le32 consequtive_missed_beacons;
__le32 total_missed_becons;
__le32 num_expected_beacons;
@@ -2778,8 +2776,8 @@ struct iwl4965_missed_beacon_notif {
#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
/* Control field in struct iwl_sensitivity_cmd */
-#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0)
-#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1)
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1)
/**
* struct iwl_sensitivity_cmd
@@ -2849,56 +2847,26 @@ struct iwl_sensitivity_cmd {
* 1-0: amount of gain, units of 1.5 dB
*/
-/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
-#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
-
-struct iwl4965_calibration_cmd {
- u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
- u8 flags; /* not used */
- __le16 reserved;
- s8 diff_gain_a; /* see above */
- s8 diff_gain_b;
- s8 diff_gain_c;
- u8 reserved1;
-} __attribute__ ((packed));
-
-/* Phy calibration command for 5000 series */
-
-enum {
- IWL5000_PHY_CALIBRATE_DC_CMD = 8,
- IWL5000_PHY_CALIBRATE_LO_CMD = 9,
- IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10,
- IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11,
- IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12,
- IWL5000_PHY_CALIBRATION_NOISE_CMD = 13,
- IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
- IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
- IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
- IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
- IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
- IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
-};
+/* Phy calibration command for series */
enum {
- CALIBRATION_CFG_CMD = 0x65,
- CALIBRATION_RES_NOTIFICATION = 0x66,
- CALIBRATION_COMPLETE_NOTIFICATION = 0x67
+ IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7,
+ IWL_PHY_CALIBRATE_DC_CMD = 8,
+ IWL_PHY_CALIBRATE_LO_CMD = 9,
+ IWL_PHY_CALIBRATE_RX_BB_CMD = 10,
+ IWL_PHY_CALIBRATE_TX_IQ_CMD = 11,
+ IWL_PHY_CALIBRATE_RX_IQ_CMD = 12,
+ IWL_PHY_CALIBRATION_NOISE_CMD = 13,
+ IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
+ 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_CHAIN_NOISE_RESET_CMD = 18,
+ IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
};
-struct iwl_cal_crystal_freq_cmd {
- u8 cap_pin1;
- u8 cap_pin2;
-} __attribute__ ((packed));
-
-struct iwl5000_calibration {
- u8 op_code;
- u8 first_group;
- u8 num_groups;
- u8 all_data_valid;
- struct iwl_cal_crystal_freq_cmd data;
-} __attribute__ ((packed));
-#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff)
+#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff)
struct iwl_calib_cfg_elmnt_s {
__le32 is_enable;
@@ -2914,32 +2882,52 @@ struct iwl_calib_cfg_status_s {
__le32 flags;
} __attribute__ ((packed));
-struct iwl5000_calib_cfg_cmd {
+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;
} __attribute__ ((packed));
-struct iwl5000_calib_hdr {
+struct iwl_calib_hdr {
u8 op_code;
u8 first_group;
u8 groups_num;
u8 data_valid;
} __attribute__ ((packed));
-struct iwl5000_calibration_chain_noise_reset_cmd {
- u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
- u8 flags; /* not used */
- __le16 reserved;
+struct iwl_calib_cmd {
+ struct iwl_calib_hdr hdr;
+ u8 data[0];
} __attribute__ ((packed));
-struct iwl5000_calibration_chain_noise_gain_cmd {
- u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
- u8 flags; /* not used */
- __le16 reserved;
+/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
+struct iwl_calib_diff_gain_cmd {
+ struct iwl_calib_hdr hdr;
+ s8 diff_gain_a; /* see above */
+ s8 diff_gain_b;
+ s8 diff_gain_c;
+ u8 reserved1;
+} __attribute__ ((packed));
+
+struct iwl_calib_xtal_freq_cmd {
+ struct iwl_calib_hdr hdr;
+ u8 cap_pin1;
+ u8 cap_pin2;
+ u8 pad[2];
+} __attribute__ ((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;
- __le16 reserved1;
+ u8 pad[2];
} __attribute__ ((packed));
/******************************************************************************
@@ -2999,11 +2987,11 @@ struct iwl_wimax_coex_event_entry {
/* COEX flag masks */
-/* Staion table is valid */
+/* Station table is valid */
#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1)
-/* UnMask wakeup src at unassociated sleep */
+/* UnMask wake up src at unassociated sleep */
#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4)
-/* UnMask wakeup src at associated sleep */
+/* 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)
@@ -3025,26 +3013,22 @@ struct iwl_rx_packet {
struct iwl_cmd_header hdr;
union {
struct iwl_alive_resp alive_frame;
- struct iwl4965_rx_frame rx_frame;
- struct iwl4965_tx_resp tx_resp;
- struct iwl4965_spectrum_notification spectrum_notif;
- struct iwl4965_csa_notification csa_notif;
+ struct iwl_spectrum_notification spectrum_notif;
+ struct iwl_csa_notification csa_notif;
struct iwl_error_resp err_resp;
- struct iwl4965_card_state_notif card_state_notif;
- struct iwl4965_beacon_notif beacon_status;
+ struct iwl_card_state_notif card_state_notif;
struct iwl_add_sta_resp add_sta;
struct iwl_rem_sta_resp rem_sta;
- struct iwl4965_sleep_notification sleep_notif;
- struct iwl4965_spectrum_resp spectrum;
+ struct iwl_sleep_notification sleep_notif;
+ struct iwl_spectrum_resp spectrum;
struct iwl_notif_statistics stats;
struct iwl_compressed_ba_resp compressed_ba;
- struct iwl4965_missed_beacon_notif missed_beacon;
- struct iwl5000_calibration calib;
+ struct iwl_missed_beacon_notif missed_beacon;
__le32 status;
u8 raw[0];
} u;
} __attribute__ ((packed));
-#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame))
+int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon);
-#endif /* __iwl4965_commands_h__ */
+#endif /* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 4c312c55f90..73d7973707e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -22,7 +22,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
@@ -30,19 +30,19 @@
#include <linux/module.h>
#include <net/mac80211.h>
-struct iwl_priv; /* FIXME: remove */
-#include "iwl-debug.h"
#include "iwl-eeprom.h"
#include "iwl-dev.h" /* FIXME: remove */
+#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-rfkill.h"
#include "iwl-power.h"
+#include "iwl-sta.h"
MODULE_DESCRIPTION("iwl core");
MODULE_VERSION(IWLWIFI_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
@@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates);
* translate ucode response to mac80211 tx status control values
*/
void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
- struct ieee80211_tx_info *control)
+ struct ieee80211_tx_info *info)
{
int rate_index;
+ struct ieee80211_tx_rate *r = &info->control.rates[0];
- control->antenna_sel_tx =
+ info->antenna_sel_tx =
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
if (rate_n_flags & RATE_MCS_HT_MSK)
- control->flags |= IEEE80211_TX_CTL_OFDM_HT;
+ r->flags |= IEEE80211_TX_RC_MCS;
if (rate_n_flags & RATE_MCS_GF_MSK)
- control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
+ r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
if (rate_n_flags & RATE_MCS_FAT_MSK)
- control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
+ r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_n_flags & RATE_MCS_DUP_MSK)
- control->flags |= IEEE80211_TX_CTL_DUP_DATA;
+ r->flags |= IEEE80211_TX_RC_DUP_DATA;
if (rate_n_flags & RATE_MCS_SGI_MSK)
- control->flags |= IEEE80211_TX_CTL_SHORT_GI;
+ r->flags |= IEEE80211_TX_RC_SHORT_GI;
rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
- if (control->band == IEEE80211_BAND_5GHZ)
+ if (info->band == IEEE80211_BAND_5GHZ)
rate_index -= IWL_FIRST_OFDM_RATE;
- control->tx_rate_idx = rate_index;
+ r->idx = rate_index;
}
EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
@@ -119,7 +120,9 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
if (rate_n_flags & RATE_MCS_HT_MSK) {
idx = (rate_n_flags & 0xff);
- if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+ 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;
@@ -140,7 +143,17 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
}
EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
-
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
+{
+ int i;
+ u8 ind = ant;
+ for (i = 0; i < RATE_ANT_NUM - 1; i++) {
+ ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
+ if (priv->hw_params.valid_tx_ant & BIT(ind))
+ return ind;
+ }
+ return ant;
+}
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EXPORT_SYMBOL(iwl_bcast_addr);
@@ -177,52 +190,6 @@ void iwl_hw_detect(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_hw_detect);
-/* Tell nic where to find the "keep warm" buffer */
-int iwl_kw_init(struct iwl_priv *priv)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&priv->lock, flags);
- ret = iwl_grab_nic_access(priv);
- if (ret)
- goto out;
-
- iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
- priv->kw.dma_addr >> 4);
- iwl_release_nic_access(priv);
-out:
- spin_unlock_irqrestore(&priv->lock, flags);
- return ret;
-}
-
-int iwl_kw_alloc(struct iwl_priv *priv)
-{
- struct pci_dev *dev = priv->pci_dev;
- struct iwl_kw *kw = &priv->kw;
-
- kw->size = IWL_KW_SIZE;
- kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
- if (!kw->v_addr)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * iwl_kw_free - Free the "keep warm" buffer
- */
-void iwl_kw_free(struct iwl_priv *priv)
-{
- struct pci_dev *dev = priv->pci_dev;
- struct iwl_kw *kw = &priv->kw;
-
- if (kw->v_addr) {
- pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
- memset(kw, 0, sizeof(*kw));
- }
-}
-
int iwl_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
@@ -271,52 +238,30 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_hw_nic_init);
-/**
- * iwl_clear_stations_table - Clear the driver's station table
- *
- * NOTE: This does not clear or otherwise alter the device's station table.
- */
-void iwl_clear_stations_table(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- if (iwl_is_alive(priv) &&
- !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
- iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
- IWL_ERROR("Couldn't clear the station table\n");
-
- priv->num_stations = 0;
- memset(priv->stations, 0, sizeof(priv->stations));
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-EXPORT_SYMBOL(iwl_clear_stations_table);
-
void iwl_reset_qos(struct iwl_priv *priv)
{
u16 cw_min = 15;
u16 cw_max = 1023;
u8 aifs = 2;
- u8 is_legacy = 0;
+ bool is_legacy = false;
unsigned long flags;
int i;
spin_lock_irqsave(&priv->lock, flags);
- priv->qos_data.qos_active = 0;
+ /* QoS always active in AP and ADHOC mode
+ * In STA mode wait for association
+ */
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+ priv->iw_mode == NL80211_IFTYPE_AP)
+ priv->qos_data.qos_active = 1;
+ else
+ priv->qos_data.qos_active = 0;
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
- if (priv->qos_data.qos_enable)
- priv->qos_data.qos_active = 1;
- if (!(priv->active_rate & 0xfff0)) {
- cw_min = 31;
- is_legacy = 1;
- }
- } else if (priv->iw_mode == NL80211_IFTYPE_AP) {
- if (priv->qos_data.qos_enable)
- priv->qos_data.qos_active = 1;
- } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ /* check for legacy mode */
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+ (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
+ (priv->iw_mode == NL80211_IFTYPE_STATION &&
+ (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
cw_min = 31;
is_legacy = 1;
}
@@ -382,10 +327,10 @@ void iwl_reset_qos(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_reset_qos);
-#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */
-#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */
+#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
+#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
- struct ieee80211_ht_info *ht_info,
+ struct ieee80211_sta_ht_cap *ht_info,
enum ieee80211_band band)
{
u16 max_bit_rate = 0;
@@ -393,45 +338,46 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
u8 tx_chains_num = priv->hw_params.tx_chains_num;
ht_info->cap = 0;
- memset(ht_info->supp_mcs_set, 0, 16);
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- ht_info->ht_supported = 1;
+ ht_info->ht_supported = true;
- ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
- ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS &
+ ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
(WLAN_HT_CAP_SM_PS_DISABLED << 2));
max_bit_rate = MAX_BIT_RATE_20_MHZ;
if (priv->hw_params.fat_channel & BIT(band)) {
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
- ht_info->supp_mcs_set[4] = 0x01;
+ 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 (priv->cfg->mod_params->amsdu_size_8K)
- ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+ 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->supp_mcs_set[0] = 0xFF;
+ ht_info->mcs.rx_mask[0] = 0xFF;
if (rx_chains_num >= 2)
- ht_info->supp_mcs_set[1] = 0xFF;
+ ht_info->mcs.rx_mask[1] = 0xFF;
if (rx_chains_num >= 3)
- ht_info->supp_mcs_set[2] = 0xFF;
+ ht_info->mcs.rx_mask[2] = 0xFF;
/* Highest supported Rx data rate */
max_bit_rate *= rx_chains_num;
- ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
- ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
+ 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->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
if (tx_chains_num != rx_chains_num) {
- ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
- ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
+ 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);
}
}
@@ -495,7 +441,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv)
sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
if (priv->cfg->sku & IWL_SKU_N)
- iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
+ iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
IEEE80211_BAND_5GHZ);
sband = &priv->bands[IEEE80211_BAND_2GHZ];
@@ -505,7 +451,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv)
sband->n_bitrates = IWL_RATE_COUNT;
if (priv->cfg->sku & IWL_SKU_N)
- iwlcore_init_ht_hw_capab(priv, &sband->ht_info,
+ iwlcore_init_ht_hw_capab(priv, &sband->ht_cap,
IEEE80211_BAND_2GHZ);
priv->ieee_channels = channels;
@@ -595,8 +541,8 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
- ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
- (priv->current_ht_config.supp_mcs_set[2] == 0));
+ ((priv->current_ht_config.mcs.rx_mask[1] == 0) &&
+ (priv->current_ht_config.mcs.rx_mask[2] == 0));
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -609,10 +555,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
if (!is_channel_valid(ch_info))
return 0;
- if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE)
+ if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
return !(ch_info->fat_extension_channel &
IEEE80211_CHAN_NO_FAT_ABOVE);
- else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW)
+ else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
return !(ch_info->fat_extension_channel &
IEEE80211_CHAN_NO_FAT_BELOW);
@@ -620,24 +566,24 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
}
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
- struct ieee80211_ht_info *sta_ht_inf)
+ struct ieee80211_sta_ht_cap *sta_ht_inf)
{
struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
if ((!iwl_ht_conf->is_ht) ||
(iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
- (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE))
+ (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
return 0;
if (sta_ht_inf) {
if ((!sta_ht_inf->ht_supported) ||
- (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
+ (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
return 0;
}
return iwl_is_channel_extension(priv, priv->band,
- iwl_ht_conf->control_channel,
- iwl_ht_conf->extension_chan_offset);
+ le16_to_cpu(priv->staging_rxon.channel),
+ iwl_ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
@@ -662,22 +608,15 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
- if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
- IWL_DEBUG_ASSOC("control diff than current %d %d\n",
- le16_to_cpu(rxon->channel),
- ht_info->control_channel);
- return;
- }
-
/* Note: control channel is opposite of extension channel */
switch (ht_info->extension_chan_offset) {
- case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
break;
- case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
- case IEEE80211_HT_IE_CHA_SEC_NONE:
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
default:
rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
break;
@@ -691,14 +630,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
"rxon flags 0x%X operation mode :0x%X "
- "extension channel offset 0x%x "
- "control chan %d\n",
- ht_info->supp_mcs_set[0],
- ht_info->supp_mcs_set[1],
- ht_info->supp_mcs_set[2],
+ "extension channel offset 0x%x\n",
+ ht_info->mcs.rx_mask[0],
+ ht_info->mcs.rx_mask[1],
+ ht_info->mcs.rx_mask[2],
le32_to_cpu(rxon->flags), ht_info->ht_protection,
- ht_info->extension_chan_offset,
- ht_info->control_channel);
+ ht_info->extension_chan_offset);
return;
}
EXPORT_SYMBOL(iwl_set_rxon_ht);
@@ -742,7 +679,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
break;
case WLAN_HT_CAP_SM_PS_INVALID:
default:
- IWL_ERROR("invalide mimo ps mode %d\n",
+ IWL_ERROR("invalid mimo ps mode %d\n",
priv->current_ht_config.sm_ps);
WARN_ON(1);
idle_cnt = -1;
@@ -868,11 +805,14 @@ int iwl_setup_mac(struct iwl_priv *priv)
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
+ IEEE80211_HW_NOISE_DBM |
+ IEEE80211_HW_AMPDU_AGGREGATION;
hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
+
+ hw->wiphy->fw_handles_regulatory = true;
+
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
/* queues to support 11n aggregation */
@@ -945,16 +885,12 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->iw_mode = NL80211_IFTYPE_STATION;
- priv->use_ant_b_for_management_frame = 1; /* start with ant B */
priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
/* Choose which receivers/antennas to use */
iwl_set_rxon_chain(priv);
iwl_init_scan_params(priv);
- if (priv->cfg->mod_params->enable_qos)
- priv->qos_data.qos_enable = 1;
-
iwl_reset_qos(priv);
priv->qos_data.qos_active = 0;
@@ -1022,6 +958,30 @@ void iwl_uninit_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_uninit_drv);
+
+void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+EXPORT_SYMBOL(iwl_disable_interrupts);
+
+void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR("Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+EXPORT_SYMBOL(iwl_enable_interrupts);
+
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
{
u32 stat_flags = 0;
@@ -1169,24 +1129,47 @@ int iwl_verify_ucode(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_verify_ucode);
+
+static const char *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",
+ "UNKNOWN"
+};
+
static const char *desc_lookup(int i)
{
- switch (i) {
- case 1:
- return "FAIL";
- case 2:
- return "BAD_PARAM";
- case 3:
- return "BAD_CHECKSUM";
- case 4:
- return "NMI_INTERRUPT";
- case 5:
- return "SYSASSERT";
- case 6:
- return "FATAL_ERROR";
- }
+ int max = ARRAY_SIZE(desc_lookup_text) - 1;
- return "UNKNOWN";
+ if (i < 0 || i > max)
+ i = max;
+
+ return desc_lookup_text[i];
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
@@ -1232,9 +1215,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
- IWL_ERROR("Desc Time "
+ IWL_ERROR("Desc Time "
"data1 data2 line\n");
- IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+ IWL_ERROR("%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
desc_lookup(desc), desc, time, data1, data2, line);
IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
@@ -1374,6 +1357,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
+
/*
* CARD_STATE_CMD
*
@@ -1462,6 +1446,16 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
return 0;
}
+ /* when driver is up while rfkill is on, it wont receive
+ * any CARD_STATE_NOTIFICATION notifications so we have to
+ * restart it in here
+ */
+ if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) {
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+ if (!iwl_is_rfkill(priv))
+ queue_work(priv->workqueue, &priv->up);
+ }
+
/* If the driver is already loaded, it will receive
* CARD_STATE_NOTIFICATION notifications and the handler will
* call restart to reload the driver.
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 288b6a800e0..7c3a20a986b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -72,6 +72,7 @@ struct iwl_cmd;
#define IWLWIFI_VERSION "1.3.27k"
#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
+#define DRV_AUTHOR "<ilw@linux.intel.com>"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
@@ -100,12 +101,8 @@ struct iwl_hcmd_utils_ops {
};
struct iwl_lib_ops {
- /* set hw dependant perameters */
+ /* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
- /* ucode shared memory */
- int (*alloc_shared_mem)(struct iwl_priv *priv);
- void (*free_shared_mem)(struct iwl_priv *priv);
- int (*shared_mem_rx_idx)(struct iwl_priv *priv);
/* Handling TX */
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
@@ -157,22 +154,53 @@ struct iwl_ops {
struct iwl_mod_params {
int disable; /* def: 0 = enable radio */
int sw_crypto; /* def: 0 = using hardware encryption */
- int debug; /* def: 0 = minimal debug log messages */
+ u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
- int enable_qos; /* def: 1 = use quality of service */
int disable_11n; /* def: 0 = disable 11n capabilities */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */
int restart_fw; /* def: 1 = restart firmware */
};
+/**
+ * struct iwl_cfg
+ * @fw_name_pre: Firmware filename prefix. The api version and extension
+ * (.ucode) will be added to filename before loading from disk. The
+ * filename is constructed as fw_name_pre<api>.ucode.
+ * @ucode_api_max: Highest version of uCode API supported by driver.
+ * @ucode_api_min: Lowest version of uCode API supported by driver.
+ *
+ * We enable the driver to be backward compatible wrt API version. The
+ * driver specifies which APIs it supports (with @ucode_api_max being the
+ * highest and @ucode_api_min the lowest). Firmware will only be loaded if
+ * it has a supported API version. The firmware's API version will be
+ * stored in @iwl_priv, enabling the driver to make runtime changes based
+ * on firmware version used.
+ *
+ * For example,
+ * if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+ * Driver interacts with Firmware API version >= 2.
+ * } else {
+ * Driver interacts with Firmware API version 1.
+ * }
+ *
+ * The ideal usage of this infrastructure is to treat a new ucode API
+ * release as a new hardware revision. That is, through utilizing the
+ * iwl_hcmd_utils_ops etc. we accommodate different command structures
+ * and flows between hardware versions (4965/5000) as well as their API
+ * versions.
+ */
struct iwl_cfg {
const char *name;
- const char *fw_name;
+ const char *fw_name_pre;
+ const unsigned int ucode_api_max;
+ const unsigned int ucode_api_min;
unsigned int sku;
int eeprom_size;
+ u16 eeprom_ver;
+ u16 eeprom_calib_ver;
const struct iwl_ops *ops;
const struct iwl_mod_params *mod_params;
};
@@ -184,22 +212,17 @@ struct iwl_cfg {
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops);
void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_clear_stations_table(struct iwl_priv *priv);
void iwl_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
- struct ieee80211_ht_info *sta_ht_inf);
+ struct ieee80211_sta_ht_cap *sta_ht_inf);
int iwl_hw_nic_init(struct iwl_priv *priv);
int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv);
-/* "keep warm" functions */
-int iwl_kw_init(struct iwl_priv *priv);
-int iwl_kw_alloc(struct iwl_priv *priv);
-void iwl_kw_free(struct iwl_priv *priv);
/*****************************************************
* RX
@@ -212,8 +235,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn);
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv);
@@ -237,7 +258,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
-
/*****************************************************
* TX power
****************************************************/
@@ -259,6 +279,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
struct ieee80211_tx_info *info);
int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
+
+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) & 0xFF;
@@ -289,6 +316,14 @@ int iwl_send_calib_results(struct iwl_priv *priv);
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
void iwl_calib_free_results(struct iwl_priv *priv);
+/*******************************************************************************
+ * Spectrum Measureemtns in iwl-spectrum.c
+ ******************************************************************************/
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
+void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
+#else
+static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
+#endif
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
*****************************************************/
@@ -308,11 +343,18 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
/*****************************************************
+ * PCI *
+ *****************************************************/
+void iwl_disable_interrupts(struct iwl_priv *priv);
+void iwl_enable_interrupts(struct iwl_priv *priv);
+
+/*****************************************************
* Error Handling Debugging
******************************************************/
void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
+
/*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 662edf4f8d2..f34ede44ed1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -60,6 +60,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
+#ifndef __iwl_csr_h__
+#define __iwl_csr_h__
/*=== CSR (control and status registers) ===*/
#define CSR_BASE (0x000)
@@ -214,6 +216,8 @@
/* EEPROM REG */
#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
+#define CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC)
+#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000)
/* EEPROM GP */
#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
@@ -286,4 +290,4 @@
#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
-
+#endif /* !__iwl_csr_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index e548d67f87f..56c13b458de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -21,7 +21,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -40,6 +40,13 @@ do { if ((priv->debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
+#define iwl_print_hex_dump(priv, level, p, len) \
+do { \
+ if (priv->debug_level & level) \
+ print_hex_dump(KERN_DEBUG, "iwl data: ", \
+ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
+} while (0)
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_debugfs {
const char *name;
@@ -53,6 +60,7 @@ struct iwl_debugfs {
struct dentry *file_rx_statistics;
struct dentry *file_tx_statistics;
struct dentry *file_log_event;
+ struct dentry *file_channels;
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
@@ -70,6 +78,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else
#define IWL_DEBUG(level, fmt, args...)
#define IWL_DEBUG_LIMIT(level, fmt, args...)
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+ void *p, u32 len)
+{}
#endif /* CONFIG_IWLWIFI_DEBUG */
@@ -85,29 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#endif /* CONFIG_IWLWIFI_DEBUGFS */
/*
- * To use the debug system;
+ * To use the debug system:
*
* If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
+ * list here in the form of
*
* #define IWL_DL_xxxx VALUE
*
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
+ * where xxxx should be the name of the classification (for example, WEP).
*
* You then need to either add a IWL_xxxx_DEBUG() macro definition for your
* classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
* to send output to that classification.
*
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/iwl/debug_level
- *
- * you simply need to add your entry to the iwl_debug_levels array.
+ * The active debug levels can be accessed via files
*
- * If you do not see debug_level in /proc/net/iwl then you do not have
- * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
+ * /sys/module/iwlagn/parameters/debug{50}
+ * /sys/class/net/wlan0/device/debug_level
*
+ * when CONFIG_IWLWIFI_DEBUG=y.
*/
#define IWL_DL_INFO (1 << 0)
@@ -183,6 +190,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_STATS_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_STATS, f, ## a)
#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_TX_REPLY_LIMIT(f, a...) \
+ IWL_DEBUG_LIMIT(IWL_DL_TX_REPLY, f, ## a)
#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a)
#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a)
#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 20db0eb636a..d5253a179de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -22,7 +22,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
@@ -58,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
- if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \
+ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
+ || !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
} while (0)
@@ -228,7 +229,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
ssize_t ret;
/* Add 30 for initial string */
const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
- DECLARE_MAC_BUF(mac);
buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
@@ -242,7 +242,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
if (station->used) {
pos += scnprintf(buf + pos, bufsz - pos,
"station %d:\ngeneral data:\n", i+1);
- print_mac(mac, station->sta.sta.addr);
pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
station->sta.sta.sta_id);
pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
@@ -349,12 +348,86 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
return count;
}
+
+
+static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_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) {
+ IWL_ERROR("Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
+ 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",
+ ieee80211_frequency_to_channel(
+ channels[i].center_freq),
+ 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);
+ 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",
+ ieee80211_frequency_to_channel(
+ channels[i].center_freq),
+ 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;
+}
+
+
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(eeprom);
DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
+DEBUGFS_READ_FILE_OPS(channels);
/*
* Create the debugfs files and directories
@@ -388,6 +461,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(stations, data);
DEBUGFS_ADD_FILE(rx_statistics, data);
DEBUGFS_ADD_FILE(tx_statistics, data);
+ DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
@@ -416,6 +490,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 9966d4e384c..0468fcc1ea9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -54,6 +54,7 @@ extern struct iwl_cfg iwl5100_agn_cfg;
extern struct iwl_cfg iwl5350_agn_cfg;
extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
+extern struct iwl_cfg iwl5150_agn_cfg;
/* CT-KILL constants */
#define CT_KILL_THRESHOLD 110 /* in Celsius */
@@ -113,11 +114,9 @@ struct iwl_queue {
* space less than this */
} __attribute__ ((packed));
-#define MAX_NUM_OF_TBS (20)
-
/* One for each TFD */
struct iwl_tx_info {
- struct sk_buff *skb[MAX_NUM_OF_TBS];
+ struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
};
/**
@@ -135,12 +134,13 @@ struct iwl_tx_info {
*/
struct iwl_tx_queue {
struct iwl_queue q;
- struct iwl_tfd_frame *bd;
+ struct iwl_tfd *tfds;
struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
struct iwl_tx_info *txb;
- int need_update;
- int sched_retry;
- int active;
+ u8 need_update;
+ u8 sched_retry;
+ u8 active;
+ u8 swq_id;
};
#define IWL_NUM_SCAN_RATES (2)
@@ -186,12 +186,6 @@ struct iwl_channel_info {
u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
};
-struct iwl4965_clip_group {
- /* maximum power level to prevent clipping for each rate, derived by
- * us from this band's saturation power in EEPROM */
- const s8 clip_powers[IWL_MAX_RATES];
-};
-
#define IWL_TX_FIFO_AC0 0
#define IWL_TX_FIFO_AC1 1
@@ -253,7 +247,8 @@ struct iwl_cmd_meta {
/* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */
u32 flags;
-
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+ DECLARE_PCI_UNMAP_LEN(len)
} __attribute__ ((packed));
#define IWL_CMD_MAX_PAYLOAD 320
@@ -269,24 +264,16 @@ struct iwl_cmd {
struct iwl_cmd_meta meta; /* driver data */
struct iwl_cmd_header hdr; /* uCode API */
union {
- struct iwl_addsta_cmd addsta;
- struct iwl_led_cmd led;
u32 flags;
u8 val8;
u16 val16;
u32 val32;
- struct iwl4965_bt_cmd bt;
- struct iwl4965_rxon_time_cmd rxon_time;
- struct iwl_powertable_cmd powertable;
- struct iwl_qosparam_cmd qosparam;
struct iwl_tx_cmd tx;
- struct iwl4965_rxon_assoc_cmd rxon_assoc;
- struct iwl_rem_sta_cmd rm_sta;
- u8 *indirect;
u8 payload[IWL_CMD_MAX_PAYLOAD];
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
+
struct iwl_host_cmd {
u8 id;
u16 len;
@@ -309,7 +296,6 @@ struct iwl_host_cmd {
/**
* struct iwl_rx_queue - Rx queue
- * @processed: Internal index to last handled Rx packet
* @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
@@ -324,26 +310,19 @@ struct iwl_rx_queue {
dma_addr_t dma_addr;
struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
- u32 processed;
u32 read;
u32 write;
u32 free_count;
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;
};
#define IWL_SUPPORTED_RATES_IE_LEN 8
-#define SCAN_INTERVAL 100
-
-#define MAX_A_CHANNELS 252
-#define MIN_A_CHANNELS 7
-
-#define MAX_B_CHANNELS 14
-#define MIN_B_CHANNELS 1
-
#define MAX_TID_COUNT 9
#define IWL_INVALID_RATE 0xFF
@@ -413,9 +392,8 @@ struct iwl_ht_info {
u8 max_amsdu_size;
u8 ampdu_factor;
u8 mpdu_density;
- u8 supp_mcs_set[16];
+ struct ieee80211_mcs_info mcs;
/* BSS related data */
- u8 control_channel;
u8 extension_chan_offset;
u8 tx_chan_width;
u8 ht_protection;
@@ -444,7 +422,6 @@ union iwl_qos_capabity {
/* QoS structures */
struct iwl_qos_info {
- int qos_enable;
int qos_active;
union iwl_qos_capabity qos_cap;
struct iwl_qosparam_cmd def_qos_parm;
@@ -470,7 +447,7 @@ struct fw_desc {
/* uCode file layout */
struct iwl_ucode {
- __le32 ver; /* major/minor/subminor */
+ __le32 ver; /* major/minor/API/serial */
__le32 inst_size; /* bytes of runtime instructions */
__le32 data_size; /* bytes of runtime data */
__le32 init_size; /* bytes of initialization instructions */
@@ -511,11 +488,15 @@ struct iwl_sensitivity_ranges {
};
-#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
/**
* struct iwl_hw_params
* @max_txq_num: Max # Tx queues supported
+ * @dma_chnl_num: Number of Tx DMA/FIFO channels
+ * @scd_bc_tbls_size: size of scheduler byte count tables
* @tx/rx_chains_num: Number of TX/RX chains
* @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
@@ -528,11 +509,13 @@ struct iwl_sensitivity_ranges {
* @sw_crypto: 0 for hw, 1 for sw
* @max_xxx_size: for ucode uses
* @ct_kill_threshold: temperature threshold
+ * @calib_init_cfg: setup initial calibrations for the hw
* @struct iwl_sensitivity_ranges: range of sensitivity values
- * @first_ampdu_q: first HW queue available for ampdu
*/
struct iwl_hw_params {
- u16 max_txq_num;
+ u8 max_txq_num;
+ u8 dma_chnl_num;
+ u16 scd_bc_tbls_size;
u8 tx_chains_num;
u8 rx_chains_num;
u8 valid_tx_ant;
@@ -549,22 +532,10 @@ struct iwl_hw_params {
u32 max_data_size;
u32 max_bsm_size;
u32 ct_kill_threshold; /* value in hw-dependent units */
+ u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens;
- u8 first_ampdu_q;
};
-#define HT_SHORT_GI_20MHZ (1 << 0)
-#define HT_SHORT_GI_40MHZ (1 << 1)
-
-
-#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
- x->u.rx_frame.stats.payload + \
- x->u.rx_frame.stats.phy_count))
-#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
- IWL_RX_HDR(x)->payload + \
- le16_to_cpu(IWL_RX_HDR(x)->len)))
-#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
-#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
/******************************************************************************
*
@@ -581,13 +552,8 @@ struct iwl_hw_params {
* iwl4965_mac_ <-- mac80211 callback
*
****************************************************************************/
-struct iwl_addsta_cmd;
-extern int iwl_send_add_sta(struct iwl_priv *priv,
- struct iwl_addsta_cmd *sta, u8 flags);
-extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
- int is_ap, u8 flags, struct ieee80211_ht_info *ht_info);
-extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
-extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
extern const u8 iwl_bcast_addr[ETH_ALEN];
extern int iwl_rxq_stop(struct iwl_priv *priv);
extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
@@ -611,19 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
}
-struct iwl_priv;
-
-
-/* Structures, enum, and defines specific to the 4965 */
-
-#define IWL_KW_SIZE 0x1000 /*4k */
-
-struct iwl_kw {
- dma_addr_t dma_addr;
- void *v_addr;
+struct iwl_dma_ptr {
+ dma_addr_t dma;
+ void *addr;
size_t size;
};
+#define HT_SHORT_GI_20MHZ (1 << 0)
+#define HT_SHORT_GI_40MHZ (1 << 1)
+
#define IWL_CHANNEL_WIDTH_20MHZ 0
#define IWL_CHANNEL_WIDTH_40MHZ 1
@@ -638,7 +600,6 @@ struct iwl_kw {
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
/* Sensitivity and chain noise calibration */
-#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
#define INITIALIZATION_VALUE 0xFFFF
#define CAL_NUM_OF_BEACONS 20
#define MAXIMUM_ALLOWED_PATHLOSS 15
@@ -691,13 +652,20 @@ enum iwl4965_calib_enabled_state {
IWL_CALIB_ENABLED = 1,
};
-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;
+
+/*
+ * enum iwl_calib
+ * defines the order in which results of initial calibrations
+ * should be sent to the runtime uCode
+ */
+enum iwl_calib {
+ IWL_CALIB_XTAL,
+ IWL_CALIB_DC,
+ IWL_CALIB_LO,
+ IWL_CALIB_TX_IQ,
+ IWL_CALIB_TX_IQ_PERD,
+ IWL_CALIB_BASE_BAND,
+ IWL_CALIB_MAX
};
/* Opaque calibration results */
@@ -766,7 +734,6 @@ enum {
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
-#define IWL_CALIB_MAX 3
struct iwl_priv {
@@ -790,7 +757,7 @@ struct iwl_priv {
#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
/* spectrum measurement report caching */
- struct iwl4965_spectrum_notification measure_report;
+ struct iwl_spectrum_notification measure_report;
u8 measurement_status;
#endif
/* ucode beacon time */
@@ -801,10 +768,6 @@ struct iwl_priv {
struct iwl_channel_info *channel_info; /* channel info array */
u8 channel_count; /* # of channels */
- /* each calibration channel group in the EEPROM has a derived
- * clip setting for each rate. */
- const struct iwl4965_clip_group clip_groups[5];
-
/* thermal calibration */
s32 temperature; /* degrees Kelvin */
s32 last_temperature;
@@ -818,12 +781,13 @@ struct iwl_priv {
unsigned long scan_start;
unsigned long scan_pass_start;
unsigned long scan_start_tsf;
+ struct iwl_scan_cmd *scan;
int scan_bands;
int one_direct_scan;
u8 direct_ssid_len;
u8 direct_ssid[IW_ESSID_MAX_SIZE];
- struct iwl_scan_cmd *scan;
- u32 scan_tx_ant[IEEE80211_NUM_BANDS];
+ u8 scan_tx_ant[IEEE80211_NUM_BANDS];
+ u8 mgmt_tx_ant;
/* spinlock */
spinlock_t lock; /* protect general shared data */
@@ -840,6 +804,8 @@ struct iwl_priv {
u8 rev_id;
/* uCode images, save to reload in case of failure */
+ u32 ucode_ver; /* version of ucode, copy of
+ iwl_ucode.ver */
struct fw_desc ucode_code; /* runtime inst */
struct fw_desc ucode_data; /* runtime data original */
struct fw_desc ucode_data_backup; /* runtime data save/restore */
@@ -850,7 +816,7 @@ struct iwl_priv {
u8 ucode_write_complete; /* the image write is complete */
- struct iwl4965_rxon_time_cmd rxon_timing;
+ struct iwl_rxon_time_cmd rxon_timing;
/* We declare this const so it can only be
* changed via explicit cast within the
@@ -882,7 +848,6 @@ struct iwl_priv {
u16 active_rate_basic;
u8 assoc_station_added;
- u8 use_ant_b_for_management_frame; /* Tx antenna selection */
u8 start_calib;
struct iwl_sensitivity_data sensitivity_data;
struct iwl_chain_noise_data chain_noise_data;
@@ -903,12 +868,14 @@ struct iwl_priv {
struct iwl_rx_queue rxq;
struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
unsigned long txq_ctx_active_msk;
- struct iwl_kw kw; /* keep warm address */
+ struct iwl_dma_ptr kw; /* keep warm address */
+ struct iwl_dma_ptr scd_bc_tbls;
+
u32 scd_base_addr; /* scheduler sram base address */
unsigned long status;
- int last_rx_rssi; /* From Rx packet statisitics */
+ int last_rx_rssi; /* From Rx packet statistics */
int last_rx_noise; /* From beacon statistics */
/* counts mgmt, ctl, and data packets */
@@ -923,8 +890,6 @@ struct iwl_priv {
unsigned long last_statistics_time;
/* context information */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
u16 rates_mask;
u32 power_mode;
@@ -965,11 +930,7 @@ struct iwl_priv {
struct ieee80211_vif *vif;
struct iwl_hw_params hw_params;
- /* driver/uCode shared Tx Byte Counts and Rx status */
- void *shared_virt;
- int rb_closed_offset;
- /* Physical Pointer to Tx Byte Counts and Rx status */
- dma_addr_t shared_phys;
+
/* Current association information needed to configure the
* hardware */
@@ -992,7 +953,6 @@ struct iwl_priv {
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
- struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
@@ -1004,9 +964,6 @@ struct iwl_priv {
s8 tx_power_user_lmt;
s8 tx_power_channel_lmt;
-#ifdef CONFIG_PM
- u32 pm_state[16];
-#endif
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
@@ -1091,26 +1048,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- void *p, u32 len)
-{
- if (!(priv->debug_level & level))
- return;
-
- print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
- p, len, 1);
-}
-#else
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- void *p, u32 len)
-{
-}
-#endif
-
-extern const struct iwl_channel_info *iwl_get_channel_info(
- const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
-
-/* Requires full declaration of iwl_priv before including */
-
#endif /* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 37155755efc..ce2f47306ce 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -169,10 +169,9 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
/* See if we got it */
- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- EEPROM_SEM_TIMEOUT);
+ ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
if (ret >= 0) {
IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
count+1);
@@ -210,10 +209,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
{
u16 *e;
u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
- u32 r;
int sz = priv->cfg->eeprom_size;
int ret;
- int i;
u16 addr;
/* allocate eeprom */
@@ -241,22 +238,19 @@ int iwl_eeprom_init(struct iwl_priv *priv)
/* eeprom is an array of 16bit values */
for (addr = 0; addr < sz; addr += sizeof(u16)) {
- _iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
- _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
-
- for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
- i += IWL_EEPROM_ACCESS_DELAY) {
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
- if (r & CSR_EEPROM_REG_READ_VALID_MSK)
- break;
- udelay(IWL_EEPROM_ACCESS_DELAY);
- }
+ u32 r;
+
+ _iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
+ if (ret < 0) {
IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
- ret = -ETIMEDOUT;
goto done;
}
+ r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
ret = 0;
@@ -279,7 +273,23 @@ EXPORT_SYMBOL(iwl_eeprom_free);
int iwl_eeprom_check_version(struct iwl_priv *priv)
{
- return priv->cfg->ops->lib->eeprom_ops.check_version(priv);
+ u16 eeprom_ver;
+ u16 calib_ver;
+
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv);
+
+ if (eeprom_ver < priv->cfg->eeprom_ver ||
+ calib_ver < priv->cfg->eeprom_calib_ver)
+ goto err;
+
+ return 0;
+err:
+ IWL_ERROR("Unsupported 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;
+
}
EXPORT_SYMBOL(iwl_eeprom_check_version);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index d3a2a5b4ac5..603c84bed63 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -68,17 +68,14 @@ struct iwl_priv;
/*
* EEPROM access time values:
*
- * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
- * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
- * CSR_EEPROM_REG_BIT_CMD (0x2).
+ * 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_ACCESS_DELAY 10 /* uSec */
-#define IWL_EEPROM_SEM_TIMEOUT 10 /* milliseconds */
+#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */
#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
@@ -147,6 +144,7 @@ struct iwl_eeprom_channel {
/*5000 calibrations */
#define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL)
+#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL)
/* 5000 links */
#define EEPROM_5000_LINK_HOST (2*0x64)
@@ -174,6 +172,9 @@ struct iwl_eeprom_channel {
#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
+/* 5050 Specific */
+#define EEPROM_5050_TX_POWER_VERSION (4)
+#define EEPROM_5050_EEPROM_VERSION (0x21E)
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
@@ -371,7 +372,7 @@ struct iwl_eeprom_ops {
int (*verify_signature) (struct iwl_priv *priv);
int (*acquire_semaphore) (struct iwl_priv *priv);
void (*release_semaphore) (struct iwl_priv *priv);
- int (*check_version) (struct iwl_priv *priv);
+ u16 (*calib_version) (struct iwl_priv *priv);
const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index a72efdf6d1d..d7da1986455 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -60,6 +60,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
+#ifndef __iwl_fh_h__
+#define __iwl_fh_h__
/****************************/
/* Flow Handler Definitions */
@@ -70,7 +72,7 @@
* Addresses are offsets from device's PCI hardware base address.
*/
#define FH_MEM_LOWER_BOUND (0x1000)
-#define FH_MEM_UPPER_BOUND (0x1EF0)
+#define FH_MEM_UPPER_BOUND (0x2000)
/**
* Keep-Warm (KW) buffer base address.
@@ -264,6 +266,7 @@
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000)
#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000)
+#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
/**
* Rx Shared Status Registers (RSSR)
@@ -290,6 +293,13 @@
#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28
+/* TFDB Area - TFDs buffer table */
+#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF)
+#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900)
+#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958)
+#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
+#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+
/**
* Transmit DMA Channel Control/Status Registers (TCSR)
*
@@ -316,34 +326,41 @@
#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60)
/* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
- (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+#define FH49_TCSR_CHNL_NUM (7)
+#define FH50_TCSR_CHNL_NUM (8)
+
+/* TCSR: tx_config register values */
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+ (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
+#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
+ (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
+ (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8)
+
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
-#define FH_TCSR_CHNL_NUM (7)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12)
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
- (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
- (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
- (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12)
/**
* Tx Shared Status Registers (TSSR)
@@ -360,7 +377,7 @@
#define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0)
#define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0)
-#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010)
+#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010)
#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
@@ -369,25 +386,99 @@
(FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
-
-
-#define FH_REGS_LOWER_BOUND (0x1000)
-#define FH_REGS_UPPER_BOUND (0x2000)
-
/* Tx service channels */
-#define FH_SRVC_CHNL (9)
-#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8)
-#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0)
+#define FH_SRVC_CHNL (9)
+#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8)
+#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
(FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
-/* TFDB Area - TFDs buffer table */
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF)
-#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900)
-#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958)
-#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
-#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98)
+/* Instruct FH to increment the retry count of a packet when
+ * it is brought from the memory to TX-FIFO
+ */
+#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002)
-/* TCSR: tx_config register values */
-#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */
+/**
+ * struct iwl_rb_status - reseve buffer status
+ * host memory mapped FH registers
+ * @closed_rb_num [0:11] - Indicates the index of the RB which was closed
+ * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed
+ * @finished_rb_num [0:11] - Indicates the index of the current RB
+ * in which the last frame was written to
+ * @finished_fr_num [0:11] - Indicates the index of the RX Frame
+ * which was transfered
+ */
+struct iwl_rb_status {
+ __le16 closed_rb_num;
+ __le16 closed_fr_num;
+ __le16 finished_rb_num;
+ __le16 finished_fr_nam;
+} __attribute__ ((packed));
+
+
+#define TFD_QUEUE_SIZE_MAX (256)
+#define TFD_QUEUE_SIZE_BC_DUP (64)
+#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP)
+#define IWL_TX_DMA_MASK DMA_BIT_MASK(36)
+#define IWL_NUM_OF_TBS 20
+
+static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
+{
+ return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF;
+}
+/**
+ * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor
+ *
+ * This structure contains dma address and length of transmission address
+ *
+ * @lo: low [31:0] portion of the dma address of TX buffer
+ * every even is unaligned on 16 bit boundary
+ * @hi_n_len 0-3 [35:32] portion of dma
+ * 4-15 length of the tx buffer
+ */
+struct iwl_tfd_tb {
+ __le32 lo;
+ __le16 hi_n_len;
+} __attribute__((packed));
+
+/**
+ * struct iwl_tfd
+ *
+ * Transmit Frame Descriptor (TFD)
+ *
+ * @ __reserved1[3] reserved
+ * @ num_tbs 0-4 number of active tbs
+ * 5 reserved
+ * 6-7 padding (not used)
+ * @ tbs[20] transmit frame buffer descriptors
+ * @ __pad padding
+ *
+ * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
+ * Both driver and device share these circular buffers, each of which must be
+ * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes
+ *
+ * Driver must indicate the physical address of the base of each
+ * circular buffer via the FH_MEM_CBBC_QUEUE registers.
+ *
+ * Each TFD contains pointer/size information for up to 20 data buffers
+ * in host DRAM. These buffers collectively contain the (one) frame described
+ * by the TFD. Each buffer must be a single contiguous block of memory within
+ * itself, but buffers may be scattered in host DRAM. Each buffer has max size
+ * of (4K - 4). The concatenates all of a TFD's buffers into a single
+ * Tx frame, up to 8 KBytes in size.
+ *
+ * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
+ */
+struct iwl_tfd {
+ u8 __reserved1[3];
+ u8 num_tbs;
+ struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
+ __le32 __pad;
+} __attribute__ ((packed));
+
+
+/* Keep Warm Size */
+#define IWL_KW_SIZE 0x1000 /* 4k */
+#endif /* !__iwl_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 8300f3d00a0..01a2169cece 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -22,7 +22,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
@@ -36,7 +36,7 @@
#include "iwl-core.h"
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
const char *get_cmd_string(u8 cmd)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 41eed679332..ca4f638ab9d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -32,110 +32,6 @@
#include <linux/ctype.h>
-/*
- * The structures defined by the hardware/uCode interface
- * have bit-wise operations. For each bit-field there is
- * a data symbol in the structure, the start bit position
- * and the length of the bit-field.
- *
- * iwl_get_bits and iwl_set_bits will return or set the
- * appropriate bits on a 32-bit value.
- *
- * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to
- * expand out to the appropriate call to iwl_get_bits
- * and iwl_set_bits without having to reference all of the
- * numerical constants and defines provided in the hardware
- * definition
- */
-
-/**
- * iwl_get_bits - Extract a hardware bit-field value
- * @src: source hardware value (__le32)
- * @pos: bit-position (0-based) of first bit of value
- * @len: length of bit-field
- *
- * iwl_get_bits will return the bit-field in cpu endian ordering.
- *
- * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and
- * will collapse to minimal code by the compiler.
- */
-static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
-{
- u32 tmp = le32_to_cpu(src);
-
- tmp >>= pos;
- tmp &= (1UL << len) - 1;
- return tmp;
-}
-
-/**
- * iwl_set_bits - Set a hardware bit-field value
- * @dst: Address of __le32 hardware value
- * @pos: bit-position (0-based) of first bit of value
- * @len: length of bit-field
- * @val: cpu endian value to encode into the bit-field
- *
- * iwl_set_bits will encode val into dst, masked to be len bits long at bit
- * position pos.
- *
- * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and
- * will collapse to minimal code by the compiler.
- */
-static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
-{
- u32 tmp = le32_to_cpu(*dst);
-
- tmp &= ~(((1UL << len) - 1) << pos);
- tmp |= (val & ((1UL << len) - 1)) << pos;
- *dst = cpu_to_le32(tmp);
-}
-
-static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
-{
- u16 tmp = le16_to_cpu(*dst);
-
- tmp &= ~((1UL << (pos + len)) - (1UL << pos));
- tmp |= (val & ((1UL << len) - 1)) << pos;
- *dst = cpu_to_le16(tmp);
-}
-
-/*
- * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
- *
- * struct example {
- * __le32 val1;
- * #define IWL_name_POS 8
- * #define IWL_name_LEN 4
- * #define IWL_name_SYM val1
- * };
- *
- * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver
- * to call:
- *
- * struct example bar;
- * u32 val = IWL_GET_BITS(bar, name);
- * val = val * 2;
- * IWL_SET_BITS(bar, name, val);
- *
- * All cpu / host ordering, masking, and shifts are performed by the macros
- * and iwl_{get,set}_bits.
- *
- */
-#define IWL_SET_BITS(s, sym, v) \
- iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
- IWL_ ## sym ## _LEN, (v))
-
-#define IWL_SET_BITS16(s, sym, v) \
- iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
- IWL_ ## sym ## _LEN, (v))
-
-#define IWL_GET_BITS(s, sym) \
- iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
- IWL_ ## sym ## _LEN)
-
-
-#define KELVIN_TO_CELSIUS(x) ((x)-273)
-#define CELSIUS_TO_KELVIN(x) ((x)+273)
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
@@ -159,11 +55,6 @@ static inline unsigned long elapsed_jiffies(unsigned long start,
return end + (MAX_JIFFY_OFFSET - start) + 1;
}
-static inline u8 iwl_get_dma_hi_address(dma_addr_t addr)
-{
- return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
-}
-
/**
* iwl_queue_inc_wrap - increment queue index, wrap back to beginning
* @index -- current index
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 9740fcc1805..0a92e7431ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -21,7 +21,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -55,7 +55,7 @@
* _iwl_read32.)
*
* These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguring of the hardware I/O. In combination with
+ * which result in misconfiguration of the hardware I/O. In combination with
* git-bisect and the IO debug level you can quickly determine the specific
* commit which breaks the IO sequence to the hardware.
*
@@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
#define iwl_read32(p, o) _iwl_read32(p, o)
#endif
+#define IWL_POLL_INTERVAL 10 /* microseconds */
static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
u32 bits, u32 mask, int timeout)
{
- int i = 0;
+ int t = 0;
do {
if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
+ return t;
+ udelay(IWL_POLL_INTERVAL);
+ t += IWL_POLL_INTERVAL;
+ } while (t < timeout);
return -ETIMEDOUT;
}
@@ -109,7 +110,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l,
int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
addr, bits, mask,
- unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l);
+ unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
return ret;
}
#define iwl_poll_bit(priv, addr, bits, mask, timeout) \
@@ -269,19 +270,10 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv,
}
}
-static inline int _iwl_poll_direct_bit(struct iwl_priv *priv,
- u32 addr, u32 mask, int timeout)
+static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
+ u32 mask, int timeout)
{
- int i = 0;
-
- do {
- if ((_iwl_read_direct32(priv, addr) & mask) == mask)
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
-
- return -ETIMEDOUT;
+ return _iwl_poll_bit(priv, addr, mask, mask, timeout);
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -308,6 +300,7 @@ static inline int __iwl_poll_direct_bit(const char *f, u32 l,
static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg)
{
_iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ rmb();
return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -330,6 +323,7 @@ static inline void _iwl_write_prph(struct iwl_priv *priv,
{
_iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
((addr & 0x0000FFFF) | (3 << 24)));
+ wmb();
_iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
}
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -392,12 +386,14 @@ static inline void iwl_clear_bits_prph(struct iwl_priv
static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+ rmb();
return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
}
static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+ wmb();
iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
}
@@ -405,6 +401,7 @@ static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
u32 len, u32 *values)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+ wmb();
for (; 0 < len; len -= sizeof(u32), values++)
iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 4eee1b163cd..11eccd7d268 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -41,7 +41,6 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
-#include "iwl-helpers.h"
#ifdef CONFIG_IWLWIFI_DEBUG
static const char *led_type_str[] = {
@@ -278,7 +277,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
/* FIXME: + priv->rx_stats[2].bytes; */
s64 tpt = current_tpt - priv->led_tpt;
- if (tpt < 0) /* wrapparound */
+ if (tpt < 0) /* wraparound */
tpt = -tpt;
IWL_DEBUG_LED("tpt %lld current_tpt %llu\n",
@@ -293,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
break;
- IWL_DEBUG_LED("LED BLINK IDX=%d", i);
+ IWL_DEBUG_LED("LED BLINK IDX=%d\n", i);
return i;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 588c9ad20e8..021e00bcd1b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -19,7 +19,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 60a03d2d2d0..75ca6a54217 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
@@ -39,7 +39,6 @@
#include "iwl-commands.h"
#include "iwl-debug.h"
#include "iwl-power.h"
-#include "iwl-helpers.h"
/*
* Setting power level allow the card to go to sleep when not busy
@@ -80,7 +79,7 @@
#define IWL_REDUCED_POWER_TEMPERATURE 95
/* default power management (not Tx power) table values */
-/* for tim 0-10 */
+/* for TIM 0-10 */
static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
@@ -91,7 +90,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
};
-/* for tim = 3-10 */
+/* for TIM = 3-10 */
static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
@@ -101,7 +100,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
};
-/* for tim > 11 */
+/* for TIM > 11 */
static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
@@ -183,7 +182,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv)
return 0;
}
-/* adjust power command according to dtim period and power level*/
+/* adjust power command according to DTIM period and power level*/
static int iwl_update_power_command(struct iwl_priv *priv,
struct iwl_powertable_cmd *cmd,
u16 mode)
@@ -257,15 +256,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
struct iwl_power_mgr *setting = &(priv->power_data);
int ret = 0;
u16 uninitialized_var(final_mode);
+ bool update_chains;
/* Don't update the RX chain when chain noise calibration is running */
- if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
- priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
- IWL_DEBUG_POWER("Cannot update the power, chain noise "
- "calibration running: %d\n",
- priv->chain_noise_data.state);
- return -EAGAIN;
- }
+ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
+ priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
/* If on battery, set to 3,
* if plugged into AC power, set to CAM ("continuously aware mode"),
@@ -313,9 +308,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
else
set_bit(STATUS_POWER_PMI, &priv->status);
- if (priv->cfg->ops->lib->update_chain_flags)
+ if (priv->cfg->ops->lib->update_chain_flags && update_chains)
priv->cfg->ops->lib->update_chain_flags(priv);
-
+ else
+ IWL_DEBUG_POWER("Cannot update the power, chain noise "
+ "calibration running: %d\n",
+ priv->chain_noise_data.state);
if (!ret)
setting->power_mode = final_mode;
}
@@ -325,7 +323,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
EXPORT_SYMBOL(iwl_power_update_mode);
/* Allow other iwl code to disable/enable power management active
- * this will be usefull for rate scale to disable PM during heavy
+ * this will be useful for rate scale to disable PM during heavy
* Tx/Rx activities
*/
int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
@@ -352,8 +350,8 @@ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
EXPORT_SYMBOL(iwl_power_disable_management);
/* Allow other iwl code to disable/enable power management active
- * this will be usefull for rate scale to disable PM during hight
- * valume activities
+ * this will be useful for rate scale to disable PM during high
+ * volume activities
*/
int iwl_power_enable_management(struct iwl_priv *priv)
{
@@ -391,7 +389,7 @@ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
}
EXPORT_SYMBOL(iwl_power_set_system_mode);
-/* initilize to default */
+/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
@@ -443,7 +441,7 @@ static void iwl_bg_set_power_save(struct work_struct *work)
mutex_lock(&priv->mutex);
- /* on starting association we disable power managment
+ /* on starting association we disable power management
* until association, if association failed then this
* timer will expire and enable PM again.
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df484a90ae6..fa098d8975c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
#ifndef __iwl_power_setting_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index ee5afd48d3a..b7a5f23351c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -25,7 +25,7 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
@@ -158,9 +158,9 @@
*
* 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
* images in host DRAM. The last register loaded must be the instruction
- * bytecount register ("1" in MSbit tells initialization uCode to load
+ * byte count register ("1" in MSbit tells initialization uCode to load
* the runtime uCode):
- * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD
*
* 5) Wait for "alive" notification, then issue normal runtime commands.
*
@@ -244,7 +244,7 @@
/**
* Tx Scheduler
*
- * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
+ * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs
* (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
* host DRAM. It steers each frame's Tx command (which contains the frame
* data) into one of up to 7 prioritized Tx DMA FIFO channels within the
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index 5d642298f04..4b69da30665 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
#include <linux/kernel.h>
@@ -34,8 +34,6 @@
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
-#include "iwl-helpers.h"
-
/* software rf-kill from user */
static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
@@ -64,7 +62,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
iwl_radio_kill_sw_disable_radio(priv);
break;
default:
- IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+ IWL_WARNING("we received unexpected RFKILL state %d\n", state);
break;
}
out_unlock:
@@ -83,7 +81,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
if (!priv->rfkill) {
- IWL_ERROR("Unable to allocate rfkill device.\n");
+ IWL_ERROR("Unable to allocate RFKILL device.\n");
ret = -ENOMEM;
goto error;
}
@@ -99,7 +97,7 @@ int iwl_rfkill_init(struct iwl_priv *priv)
ret = rfkill_register(priv->rfkill);
if (ret) {
- IWL_ERROR("Unable to register rfkill: %d\n", ret);
+ IWL_ERROR("Unable to register RFKILL: %d\n", ret);
goto free_rfkill;
}
@@ -127,7 +125,7 @@ void iwl_rfkill_unregister(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_rfkill_unregister);
-/* set rf-kill to the right state. */
+/* set RFKILL to the right state. */
void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
{
if (!priv->rfkill)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
index 402fd4c781d..86dc055a2e9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
#ifndef __iwl_rf_kill_h__
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0509c16dbe7..c5f1aa0feac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -218,8 +218,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
- if ((write != (rxq->write & ~0x7))
- || (abs(rxq->write - rxq->read) > 7)) {
+ if (write != (rxq->write & ~0x7)) {
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
@@ -245,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv)
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
+
+ while (1) {
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ 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);
/* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
- __GFP_NOWARN | GFP_ATOMIC);
+ GFP_KERNEL);
if (!rxb->skb) {
- if (net_ratelimit())
- printk(KERN_CRIT DRV_NAME
- ": Can not allocate SKB buffers\n");
+ printk(KERN_CRIT DRV_NAME
+ "Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
- priv->alloc_rxb_skb++;
- list_del(element);
/* Get physical address of RB/SKB */
rxb->real_dma_addr = pci_map_single(
@@ -277,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv)
rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
+ spin_lock_irqsave(&rxq->lock, flags);
+
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
+ priv->alloc_rxb_skb++;
+
+ spin_unlock_irqrestore(&rxq->lock, flags);
}
- spin_unlock_irqrestore(&rxq->lock, flags);
}
-EXPORT_SYMBOL(iwl_rx_allocate);
void iwl_rx_replenish(struct iwl_priv *priv)
{
@@ -317,7 +325,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
+ pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status),
+ rxq->rb_stts, rxq->rb_stts_dma);
rxq->bd = NULL;
+ rxq->rb_stts = NULL;
}
EXPORT_SYMBOL(iwl_rx_queue_free);
@@ -334,7 +345,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
if (!rxq->bd)
- return -ENOMEM;
+ goto err_bd;
+
+ rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status),
+ &rxq->rb_stts_dma);
+ if (!rxq->rb_stts)
+ goto err_rb;
/* Fill the rx_used queue with _all_ of the Rx buffers */
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
@@ -346,6 +362,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
rxq->free_count = 0;
rxq->need_update = 0;
return 0;
+
+err_rb:
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+err_bd:
+ return -ENOMEM;
}
EXPORT_SYMBOL(iwl_rx_queue_alloc);
@@ -412,10 +434,10 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* Tell device where in DRAM to update its Rx status */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
- (priv->shared_phys + priv->rb_closed_offset) >> 4);
+ rxq->rb_stts_dma >> 4);
/* Enable Rx DMA
- * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in
+ * 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
@@ -426,6 +448,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
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 |
+ FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
rb_size|
(rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
@@ -453,10 +476,8 @@ int iwl_rxq_stop(struct iwl_priv *priv)
/* stop Rx DMA */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
- ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
- (1 << 24), 1000);
- if (ret < 0)
- IWL_ERROR("Can't stop Rx DMA.\n");
+ iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+ FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -470,7 +491,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl4965_missed_beacon_notif *missed_beacon;
+ struct iwl_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon;
if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
@@ -485,49 +506,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
-int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn)
-{
- unsigned long flags;
- int sta_id;
-
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- 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;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_start);
-
-int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
-{
- unsigned long flags;
- int sta_id;
-
- sta_id = iwl_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- 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;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
-}
-EXPORT_SYMBOL(iwl_rx_agg_stop);
-
/* Calculate noise level, based on measurements during network silence just
* before arriving beacon. This measurement can be done only if we know
@@ -651,20 +629,24 @@ static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
return sig_qual;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
+/* Calc max signal level (dBm) among 3 possible receivers */
+static inline int iwl_calc_rssi(struct iwl_priv *priv,
+ struct iwl_rx_phy_res *rx_resp)
+{
+ return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
/**
* iwl_dbg_report_frame - dump frame to syslog during debug sessions
*
* You may hack this function to show different aspects of received frames,
* including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- *
- * TODO: This was originally written for 3945, need to audit for
- * proper operation with 4965.
+ * group100 parameter selects whether to show 1 out of 100 good data frames.
+ * All beacon and probe response frames are printed.
*/
static void iwl_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
+ struct iwl_rx_phy_res *phy_res, u16 length,
struct ieee80211_hdr *header, int group100)
{
u32 to_us;
@@ -676,20 +658,9 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u16 seq_ctl;
u16 channel;
u16 phy_flags;
- int rate_sym;
- u16 length;
- u16 status;
- u16 bcn_tmr;
+ u32 rate_n_flags;
u32 tsf_low;
- u64 tsf;
- u8 rssi;
- u8 agc;
- u16 sig_avg;
- u16 noise_diff;
- struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
- struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
- struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
- u8 *data = IWL_RX_DATA(pkt);
+ int rssi;
if (likely(!(priv->debug_level & IWL_DL_RX)))
return;
@@ -699,22 +670,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
seq_ctl = le16_to_cpu(header->seq_ctrl);
/* metadata */
- channel = le16_to_cpu(rx_hdr->channel);
- phy_flags = le16_to_cpu(rx_hdr->phy_flags);
- rate_sym = rx_hdr->rate;
- length = le16_to_cpu(rx_hdr->len);
-
- /* end-of-frame status and timestamp */
- status = le32_to_cpu(rx_end->status);
- bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
- tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
- tsf = le64_to_cpu(rx_end->timestamp);
+ channel = le16_to_cpu(phy_res->channel);
+ phy_flags = le16_to_cpu(phy_res->phy_flags);
+ rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
/* signal statistics */
- rssi = rx_stats->rssi;
- agc = rx_stats->agc;
- sig_avg = le16_to_cpu(rx_stats->sig_avg);
- noise_diff = le16_to_cpu(rx_stats->noise_diff);
+ rssi = iwl_calc_rssi(priv, phy_res);
+ tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
@@ -768,11 +730,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
else
title = "Frame";
- rate_idx = iwl_hwrate_to_plcp_idx(rate_sym);
- if (unlikely(rate_idx == -1))
+ rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+ if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
bitrate = 0;
- else
+ WARN_ON_ONCE(1);
+ } else {
bitrate = iwl_rates[rate_idx].ieee / 2;
+ }
/* print frame summary.
* MAC addresses show just the last byte (for brevity),
@@ -784,24 +748,17 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
length, rssi, channel, bitrate);
else {
/* src/dst addresses assume managed mode */
- IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
- "src=0x%02x, rssi=%u, tim=%lu usec, "
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, src=0x%02x, "
+ "len=%u, rssi=%d, tim=%lu usec, "
"phy=0x%02x, chnl=%d\n",
title, le16_to_cpu(fc), header->addr1[5],
- header->addr3[5], rssi,
+ header->addr3[5], length, rssi,
tsf_low - priv->scan_start_tsf,
phy_flags, channel);
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
-}
-#else
-static inline void iwl_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header,
- int group100)
-{
+ iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
}
#endif
@@ -995,46 +952,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
rxb->skb = NULL;
}
-/* Calc max signal level (dBm) among 3 possible receivers */
-static inline int iwl_calc_rssi(struct iwl_priv *priv,
- struct iwl_rx_phy_res *rx_resp)
-{
- return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
-}
-
-
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
- priv->stations[sta_id].sta.sta.modify_mask = 0;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
-{
- /* FIXME: need locking over ps_status ??? */
- u8 sta_id = iwl_find_station(priv, addr);
-
- if (sta_id != IWL_INVALID_STATION) {
- u8 sta_awake = priv->stations[sta_id].
- ps_status == STA_PS_STATUS_WAKE;
-
- if (sta_awake && ps_bit)
- priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
- else if (!sta_awake && !ps_bit) {
- iwl_sta_modify_ps_wake(priv, sta_id);
- priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
- }
- }
-}
-
/* This is necessary only for a number of statistics, see the caller. */
static int iwl_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header)
@@ -1157,9 +1074,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
/* Set "1" to report good data frames in groups of 100 */
- /* FIXME: need to optimze the call: */
- iwl_dbg_report_frame(priv, pkt, header, 1);
-
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (unlikely(priv->debug_level & IWL_DL_RX))
+ iwl_dbg_report_frame(priv, rx_start, len, header, 1);
+#endif
IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n",
rx_status.signal, rx_status.noise, rx_status.signal,
(unsigned long long)rx_status.mactime);
@@ -1168,12 +1086,12 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
* "antenna number"
*
* It seems that the antenna field in the phy flags value
- * is actually a bitfield. This is undefined by radiotap,
+ * 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 favour of a
+ * I think this field should be removed in favor of a
* new 802.11n radiotap field "RX chains" that is defined
* as a bitmask.
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index c89365e2ca5..3c803f6922e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -22,11 +22,13 @@
* in the file called LICENSE.GPL.
*
* Contact Information:
- * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*****************************************************************************/
-#include <net/mac80211.h>
+#include <linux/types.h>
#include <linux/etherdevice.h>
+#include <net/lib80211.h>
+#include <net/mac80211.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
@@ -64,54 +66,6 @@
#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
-static int scan_tx_ant[3] = {
- RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
-};
-
-
-
-static int iwl_is_empty_essid(const char *essid, int essid_len)
-{
- /* Single white space is for Linksys APs */
- if (essid_len == 1 && essid[0] == ' ')
- return 1;
-
- /* Otherwise, if the entire essid is 0, we assume it is hidden */
- while (essid_len) {
- essid_len--;
- if (essid[essid_len] != '\0')
- return 0;
- }
-
- return 1;
-}
-
-
-
-static const char *iwl_escape_essid(const char *essid, u8 essid_len)
-{
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- const char *s = essid;
- char *d = escaped;
-
- if (iwl_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
- while (essid_len--) {
- if (*s == '\0') {
- *d++ = '\\';
- *d++ = '0';
- s++;
- } else
- *d++ = *s++;
- }
- *d = '\0';
- return escaped;
-}
-
/**
* iwl_scan_cancel - Cancel any currently executing HW scan
*
@@ -455,10 +409,11 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
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] = RATE_MCS_ANT_INIT_IND;
+ priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
- priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND;
+ priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
}
int iwl_scan_initiate(struct iwl_priv *priv)
@@ -550,7 +505,7 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
{
struct ieee80211_ht_cap *ht_cap;
- if (!sband || !sband->ht_info.ht_supported)
+ if (!sband || !sband->ht_cap.ht_supported)
return;
if (*left < sizeof(struct ieee80211_ht_cap))
@@ -559,12 +514,12 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
*pos++ = sizeof(struct ieee80211_ht_cap);
ht_cap = (struct ieee80211_ht_cap *) pos;
- ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
- memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
+ ht_cap->cap_info = cpu_to_le16(sband->ht_cap.cap);
+ memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 16);
ht_cap->ampdu_params_info =
- (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
- ((sband->ht_info.ampdu_density << 2) &
- IEEE80211_HT_CAP_AMPDU_DENSITY);
+ (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) |
+ ((sband->ht_cap.ampdu_density << 2) &
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
*left -= sizeof(struct ieee80211_ht_cap);
}
@@ -670,23 +625,6 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
return (u16)len;
}
-static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
-{
- int i, ind;
-
- ind = priv->scan_tx_ant[band];
- for (i = 0; i < priv->hw_params.tx_chains_num; i++) {
- ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1;
- if (priv->hw_params.valid_tx_ant & (1 << ind)) {
- priv->scan_tx_ant[band] = ind;
- break;
- }
- }
- IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
- return scan_tx_ant[ind];
-}
-
-
static void iwl_bg_request_scan(struct work_struct *data)
{
struct iwl_priv *priv =
@@ -699,11 +637,13 @@ static void iwl_bg_request_scan(struct work_struct *data)
struct iwl_scan_cmd *scan;
struct ieee80211_conf *conf = NULL;
int ret = 0;
- u32 tx_ant;
+ u32 rate_flags = 0;
u16 cmd_len;
enum ieee80211_band band;
u8 n_probes = 2;
u8 rx_chain = priv->hw_params.valid_rx_ant;
+ u8 rate;
+ DECLARE_SSID_BUF(ssid);
conf = ieee80211_get_hw_conf(priv->hw);
@@ -714,7 +654,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
goto done;
}
- /* Make sure the scan wasn't cancelled before this queued work
+ /* Make sure the scan wasn't canceled before this queued work
* was given the chance to run... */
if (!test_bit(STATUS_SCANNING, &priv->status))
goto done;
@@ -796,20 +736,13 @@ static void iwl_bg_request_scan(struct work_struct *data)
/* We should add the ability for user to lock to PASSIVE ONLY */
if (priv->one_direct_scan) {
IWL_DEBUG_SCAN("Start direct scan for '%s'\n",
- iwl_escape_essid(priv->direct_ssid,
- priv->direct_ssid_len));
+ print_ssid(ssid, priv->direct_ssid,
+ priv->direct_ssid_len));
scan->direct_scan[0].id = WLAN_EID_SSID;
scan->direct_scan[0].len = priv->direct_ssid_len;
memcpy(scan->direct_scan[0].ssid,
priv->direct_ssid, priv->direct_ssid_len);
n_probes++;
- } else if (!iwl_is_associated(priv) && priv->essid_len) {
- IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
- iwl_escape_essid(priv->essid, priv->essid_len));
- scan->direct_scan[0].id = WLAN_EID_SSID;
- scan->direct_scan[0].len = priv->essid_len;
- memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
- n_probes++;
} else {
IWL_DEBUG_SCAN("Start indirect scan.\n");
}
@@ -822,23 +755,16 @@ static void iwl_bg_request_scan(struct work_struct *data)
if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
band = IEEE80211_BAND_2GHZ;
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
- tx_ant = iwl_scan_tx_ant(priv, band);
- if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK)
- scan->tx_cmd.rate_n_flags =
- iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
- tx_ant);
- else
- scan->tx_cmd.rate_n_flags =
- iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
- tx_ant |
- RATE_MCS_CCK_MSK);
+ if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) {
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = IWL_RATE_1M_PLCP;
+ rate_flags = RATE_MCS_CCK_MSK;
+ }
scan->good_CRC_th = 0;
} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
band = IEEE80211_BAND_5GHZ;
- tx_ant = iwl_scan_tx_ant(priv, band);
- scan->tx_cmd.rate_n_flags =
- iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
- tx_ant);
+ rate = IWL_RATE_6M_PLCP;
scan->good_CRC_th = IWL_GOOD_CRC_TH;
/* Force use of chains B and C (0x6) for scan Rx for 4965
@@ -851,6 +777,11 @@ static void iwl_bg_request_scan(struct work_struct *data)
goto done;
}
+ priv->scan_tx_ant[band] =
+ iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+ 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);
+
/* MIMO is not used here, but value is required */
scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
new file mode 100644
index 00000000000..836c3c80b69
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
@@ -0,0 +1,198 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 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/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW 0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH 0xFF000000
+#define TIME_UNIT 1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+/* TOOD: was used in sysfs debug interface need to add to mac */
+#if 0
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * 1024;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+ rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+ return (quot << 24) + 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(u32 base, u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & BEACON_TIME_MASK_LOW;
+ u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & BEACON_TIME_MASK_HIGH) +
+ (addon & BEACON_TIME_MASK_HIGH);
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << 24);
+ } else
+ res += (1 << 24);
+
+ return cpu_to_le32(res);
+}
+static int iwl_get_measurement(struct iwl_priv *priv,
+ struct ieee80211_measurement_params *params,
+ u8 type)
+{
+ struct iwl4965_spectrum_cmd spectrum;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+ .data = (void *)&spectrum,
+ .meta.flags = CMD_WANT_SKB,
+ };
+ u32 add_time = le64_to_cpu(params->start_time);
+ int rc;
+ int spectrum_resp_status;
+ int duration = le16_to_cpu(params->duration);
+
+ if (iwl_is_associated(priv))
+ add_time =
+ iwl_usecs_to_beacons(
+ le64_to_cpu(params->start_time) - priv->last_tsf,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+ memset(&spectrum, 0, sizeof(spectrum));
+
+ spectrum.channel_count = cpu_to_le16(1);
+ spectrum.flags =
+ RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+ spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+ cmd.len = sizeof(spectrum);
+ spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+ if (iwl_is_associated(priv))
+ spectrum.start_time =
+ iwl_add_beacon_time(priv->last_beacon_time,
+ add_time,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ else
+ spectrum.start_time = 0;
+
+ spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+ spectrum.channels[0].channel = params->channel;
+ spectrum.channels[0].type = type;
+ if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+ RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ switch (spectrum_resp_status) {
+ case 0: /* Command will be handled */
+ if (res->u.spectrum.id != 0xff) {
+ IWL_DEBUG_INFO
+ ("Replaced existing measurement: %d\n",
+ res->u.spectrum.id);
+ priv->measurement_status &= ~MEASUREMENT_READY;
+ }
+ priv->measurement_status |= MEASUREMENT_ACTIVE;
+ rc = 0;
+ break;
+
+ case 1: /* Command will not be handled */
+ rc = -EAGAIN;
+ break;
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+#endif
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG(IWL_DL_11H,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+}
+
+void iwl_setup_spectrum_handlers(struct iwl_priv *priv)
+{
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
+}
+EXPORT_SYMBOL(iwl_setup_spectrum_handlers);
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index a40a2174df9..b7d7943e476 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -21,7 +21,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -88,4 +88,5 @@ struct ieee80211_measurement_report {
struct ieee80211_basic_report basic[0];
} u;
} __attribute__ ((packed));
+
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 61797f3f8d5..412f66bac1a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -33,8 +33,6 @@
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
-#include "iwl-helpers.h"
-
#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
@@ -45,7 +43,6 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
int start = 0;
int ret = IWL_INVALID_STATION;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
(priv->iw_mode == NL80211_IFTYPE_AP))
@@ -63,8 +60,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
goto out;
}
- IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
- print_mac(mac, addr), priv->num_stations);
+ IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n",
+ addr, priv->num_stations);
out:
spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -86,7 +83,6 @@ EXPORT_SYMBOL(iwl_get_ra_sta_id);
static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
{
unsigned long flags;
- DECLARE_MAC_BUF(mac);
spin_lock_irqsave(&priv->sta_lock, flags);
@@ -94,8 +90,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id);
priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
- IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n",
- print_mac(mac, priv->stations[sta_id].sta.sta.addr));
+ IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n",
+ priv->stations[sta_id].sta.sta.addr);
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
@@ -104,7 +100,9 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
- u8 sta_id = cmd->cmd.addsta.sta.sta_id;
+ struct iwl_addsta_cmd *addsta =
+ (struct iwl_addsta_cmd *)cmd->cmd.payload;
+ u8 sta_id = addsta->sta.sta_id;
if (!skb) {
IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
@@ -132,7 +130,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
return 1;
}
-int iwl_send_add_sta(struct iwl_priv *priv,
+static int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags)
{
struct iwl_rx_packet *res = NULL;
@@ -180,10 +178,9 @@ int iwl_send_add_sta(struct iwl_priv *priv,
return ret;
}
-EXPORT_SYMBOL(iwl_send_add_sta);
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
- struct ieee80211_ht_info *sta_ht_inf)
+ struct ieee80211_sta_ht_cap *sta_ht_inf)
{
__le32 sta_flags;
u8 mimo_ps_mode;
@@ -231,13 +228,12 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
* iwl_add_station_flags - Add station to tables in driver and device
*/
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
- u8 flags, struct ieee80211_ht_info *ht_info)
+ u8 flags, struct ieee80211_sta_ht_cap *ht_info)
{
int i;
int sta_id = IWL_INVALID_STATION;
struct iwl_station_entry *station;
unsigned long flags_spin;
- DECLARE_MAC_BUF(mac);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
if (is_ap)
@@ -273,8 +269,8 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
station = &priv->stations[sta_id];
station->used = IWL_STA_DRIVER_ACTIVE;
- IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n",
- sta_id, print_mac(mac, addr));
+ IWL_DEBUG_ASSOC("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 */
@@ -301,14 +297,11 @@ EXPORT_SYMBOL(iwl_add_station_flags);
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
{
unsigned long flags;
- DECLARE_MAC_BUF(mac);
-
u8 sta_id = iwl_find_station(priv, addr);
BUG_ON(sta_id == IWL_INVALID_STATION);
- IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
- print_mac(mac, addr));
+ IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr);
spin_lock_irqsave(&priv->sta_lock, flags);
@@ -326,7 +319,9 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
- const char *addr = cmd->cmd.rm_sta.addr;
+ struct iwl_rem_sta_cmd *rm_sta =
+ (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
+ const char *addr = rm_sta->addr;
if (!skb) {
IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
@@ -415,7 +410,6 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
int sta_id = IWL_INVALID_STATION;
int i, ret = -EINVAL;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
spin_lock_irqsave(&priv->sta_lock, flags);
@@ -435,18 +429,18 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
if (unlikely(sta_id == IWL_INVALID_STATION))
goto out;
- IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n",
- sta_id, print_mac(mac, addr));
+ IWL_DEBUG_ASSOC("Removing STA from driver:%d %pM\n",
+ sta_id, addr);
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
- IWL_ERROR("Removing %s but non DRIVER active\n",
- print_mac(mac, addr));
+ IWL_ERROR("Removing %pM but non DRIVER active\n",
+ addr);
goto out;
}
if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
- IWL_ERROR("Removing %s but non UCODE active\n",
- print_mac(mac, addr));
+ IWL_ERROR("Removing %pM but non UCODE active\n",
+ addr);
goto out;
}
@@ -467,6 +461,29 @@ out:
}
EXPORT_SYMBOL(iwl_remove_station);
+/**
+ * iwl_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE: This does not clear or otherwise alter the device's station table.
+ */
+void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (iwl_is_alive(priv) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
+ iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
+ IWL_ERROR("Couldn't clear the station table\n");
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+EXPORT_SYMBOL(iwl_clear_stations_table);
+
static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{
int i;
@@ -475,7 +492,7 @@ static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
if (!test_and_set_bit(i, &priv->ucode_key_table))
return i;
- return -1;
+ return WEP_INVALID_OFFSET;
}
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
@@ -620,6 +637,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
/* else, we are overriding an existing key => no need to allocated room
* in uCode. */
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for new kew");
+
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
@@ -637,6 +657,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
{
unsigned long flags;
__le16 key_flags = 0;
+ int ret;
key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -664,14 +685,18 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
/* else, we are overriding an existing key => no need to allocated room
* in uCode. */
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for new kew");
+
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
spin_unlock_irqrestore(&priv->sta_lock, flags);
- IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ return ret;
}
static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -696,6 +721,9 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
/* else, we are overriding an existing key => no need to allocated room
* in uCode. */
+ WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+ "no space for new kew");
+
/* This copy is acutally not needed: we get the key with each TX */
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
@@ -706,6 +734,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
return ret;
}
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ const u8 *addr, u32 iv32, u16 *phase1key)
+{
+ u8 sta_id = IWL_INVALID_STATION;
+ unsigned long flags;
+ __le16 key_flags = 0;
+ int i;
+ DECLARE_MAC_BUF(mac);
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+ addr);
+ return;
+ }
+
+ if (iwl_scan_cancel(priv)) {
+ /* cancel scan failed, just live w/ bad key and rely
+ briefly on SW decryption */
+ return;
+ }
+
+ key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == priv->hw_params.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+ for (i = 0; i < 5; i++)
+ priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+ cpu_to_le16(phase1key[i]);
+
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+}
+EXPORT_SYMBOL(iwl_update_tkip_key);
+
int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
@@ -734,6 +811,13 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
return 0;
}
+ if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
+ IWL_WARNING("Removing wrong key %d 0x%x\n",
+ keyconf->keyidx, key_flags);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+
if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
&priv->ucode_key_table))
IWL_ERROR("index %d not used in uCode key table.\n",
@@ -791,7 +875,7 @@ static void iwl_dump_lq_cmd(struct iwl_priv *priv,
{
int i;
IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
- IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+ IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n",
lq->general_params.single_stream_ant_msk,
lq->general_params.dual_stream_ant_msk);
@@ -852,7 +936,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
struct iwl_link_quality_cmd link_cmd = {
.reserved1 = 0,
};
- u16 rate_flags;
+ u32 rate_flags;
/* 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 */
@@ -868,15 +952,16 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
rate_flags |= RATE_MCS_CCK_MSK;
- /* Use Tx antenna B only */
- rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
+ rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
+ RATE_MCS_ANT_POS;
link_cmd.rs_table[i].rate_n_flags =
iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
- r = iwl4965_get_prev_ieee_rate(r);
+ r = iwl_get_prev_ieee_rate(r);
}
- link_cmd.general_params.single_stream_ant_msk = 2;
+ link_cmd.general_params.single_stream_ant_msk =
+ first_antenna(priv->hw_params.valid_tx_ant);
link_cmd.general_params.dual_stream_ant_msk = 3;
link_cmd.agg_params.agg_dis_start_th = 3;
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
@@ -892,24 +977,35 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
* iwl_rxon_add_station - add station into station table.
*
* there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling this fnction
+ * NOTE: mutex must be held before calling this function
*/
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
+ struct ieee80211_sta *sta;
+ struct ieee80211_sta_ht_cap ht_config;
+ struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
u8 sta_id;
/* Add station to device's station table */
- struct ieee80211_conf *conf = &priv->hw->conf;
- struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
-
- if ((is_ap) &&
- (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
- (priv->iw_mode == NL80211_IFTYPE_STATION))
- sta_id = iwl_add_station_flags(priv, addr, is_ap,
- 0, cur_ht_config);
- else
- sta_id = iwl_add_station_flags(priv, addr, is_ap,
- 0, NULL);
+
+ /*
+ * XXX: This check is definitely not correct, if we're an AP
+ * it'll always be false which is not what we want, but
+ * it doesn't look like iwlagn is prepared to be an HT
+ * AP anyway.
+ */
+ if (priv->current_ht_config.is_ht) {
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->hw, addr);
+ if (sta) {
+ memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
+ cur_ht_config = &ht_config;
+ }
+ rcu_read_unlock();
+ }
+
+ sta_id = iwl_add_station_flags(priv, addr, is_ap,
+ 0, cur_ht_config);
/* Set up default rate scaling table in device's station table */
iwl_sta_init_lq(priv, addr, is_ap);
@@ -927,7 +1023,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
u16 fc = le16_to_cpu(hdr->frame_control);
- DECLARE_MAC_BUF(mac);
/* If this frame is broadcast or management, use broadcast station id */
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
@@ -962,9 +1057,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
if (sta_id != IWL_INVALID_STATION)
return sta_id;
- IWL_DEBUG_DROP("Station %s not in station map. "
+ IWL_DEBUG_DROP("Station %pM not in station map. "
"Defaulting to broadcast...\n",
- print_mac(mac, hdr->addr1));
+ hdr->addr1);
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
@@ -981,9 +1076,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
EXPORT_SYMBOL(iwl_get_sta_id);
/**
- * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
*/
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
{
unsigned long flags;
@@ -996,5 +1091,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
-EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
+
+int iwl_sta_rx_agg_start(struct iwl_priv *priv,
+ const u8 *addr, int tid, u16 ssn)
+{
+ unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ 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;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_start);
+
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+{
+ unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ 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;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask = 0;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+ /* FIXME: need locking over ps_status ??? */
+ u8 sta_id = iwl_find_station(priv, addr);
+
+ if (sta_id != IWL_INVALID_STATION) {
+ u8 sta_awake = priv->stations[sta_id].
+ ps_status == STA_PS_STATUS_WAKE;
+
+ if (sta_awake && ps_bit)
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+ else if (!sta_awake && !ps_bit) {
+ iwl_sta_modify_ps_wake(priv, sta_id);
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+ }
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 221b93e670a..9bb7cefc1f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id);
int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id);
+void iwl_update_tkip_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ const u8 *addr, u32 iv32, u16 *phase1key);
+
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+void iwl_clear_stations_table(struct iwl_priv *priv);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
+ int is_ap, u8 flags,
+ struct ieee80211_sta_ht_cap *ht_info);
+void 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,
+ const u8 *addr, int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr);
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 907a53ebc6e..b0ee86c6268 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -56,96 +56,132 @@ static const u16 default_tid_to_tx_fifo[] = {
IWL_TX_FIFO_AC3
};
+static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
+ struct iwl_dma_ptr *ptr, size_t size)
+{
+ ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma);
+ if (!ptr->addr)
+ return -ENOMEM;
+ ptr->size = size;
+ return 0;
+}
+
+static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
+ struct iwl_dma_ptr *ptr)
+{
+ if (unlikely(!ptr->addr))
+ return;
+
+ pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma);
+ memset(ptr, 0, sizeof(*ptr));
+}
+
+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;
+}
/**
* iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @priv - driver private data
+ * @txq - tx queue
*
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
-static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
- struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
- struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
+ struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0];
+ struct iwl_tfd *tfd;
struct pci_dev *dev = priv->pci_dev;
+ int index = txq->q.read_ptr;
int i;
- int counter = 0;
- int index, is_odd;
+ int num_tbs;
- /* Host command buffers stay mapped in memory, nothing to clean */
- if (txq->q.id == IWL_CMD_QUEUE_NUM)
- return 0;
+ tfd = &tfd_tmp[index];
/* Sanity check on number of chunks */
- counter = IWL_GET_BITS(*bd, num_tbs);
- if (counter > MAX_NUM_OF_TBS) {
- IWL_ERROR("Too many chunks: %i\n", counter);
+ num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+ if (num_tbs >= IWL_NUM_OF_TBS) {
+ IWL_ERROR("Too many chunks: %i\n", num_tbs);
/* @todo issue fatal error, it is quite serious situation */
- return 0;
+ return;
}
- /* Unmap chunks, if any.
- * TFD info for odd chunks is different format than for even chunks. */
- for (i = 0; i < counter; i++) {
- index = i / 2;
- is_odd = i & 0x1;
-
- if (is_odd)
- pci_unmap_single(
- dev,
- IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
- (IWL_GET_BITS(bd->pa[index],
- tb2_addr_hi20) << 16),
- IWL_GET_BITS(bd->pa[index], tb2_len),
+ /* Unmap tx_cmd */
+ if (num_tbs)
+ pci_unmap_single(dev,
+ pci_unmap_addr(&txq->cmd[index]->meta, mapping),
+ pci_unmap_len(&txq->cmd[index]->meta, len),
PCI_DMA_TODEVICE);
- else if (i > 0)
- pci_unmap_single(dev,
- le32_to_cpu(bd->pa[index].tb1_addr),
- IWL_GET_BITS(bd->pa[index], tb1_len),
- PCI_DMA_TODEVICE);
+ /* Unmap chunks, if any. */
+ for (i = 1; i < num_tbs; i++) {
+ pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
+ iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
- /* Free SKB, if any, for this chunk */
- if (txq->txb[txq->q.read_ptr].skb[i]) {
- struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
-
- dev_kfree_skb(skb);
- txq->txb[txq->q.read_ptr].skb[i] = NULL;
+ if (txq->txb) {
+ dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]);
+ txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
}
}
- return 0;
}
-static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
- dma_addr_t addr, u16 len)
+static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+ struct iwl_tfd *tfd,
+ dma_addr_t addr, u16 len)
{
- int index, is_odd;
- struct iwl_tfd_frame *tfd = ptr;
- u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+ u32 num_tbs = iwl_tfd_get_num_tbs(tfd);
/* Each TFD can point to a maximum 20 Tx buffers */
- if (num_tbs >= MAX_NUM_OF_TBS) {
+ if (num_tbs >= IWL_NUM_OF_TBS) {
IWL_ERROR("Error can not send more than %d chunks\n",
- MAX_NUM_OF_TBS);
+ IWL_NUM_OF_TBS);
return -EINVAL;
}
- index = num_tbs / 2;
- is_odd = num_tbs & 0x1;
-
- if (!is_odd) {
- tfd->pa[index].tb1_addr = cpu_to_le32(addr);
- IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
- iwl_get_dma_hi_address(addr));
- IWL_SET_BITS(tfd->pa[index], tb1_len, len);
- } else {
- IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
- (u32) (addr & 0xffff));
- IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
- IWL_SET_BITS(tfd->pa[index], tb2_len, len);
- }
+ BUG_ON(addr & ~DMA_BIT_MASK(36));
+ if (unlikely(addr & ~IWL_TX_DMA_MASK))
+ IWL_ERROR("Unaligned address = %llx\n",
+ (unsigned long long)addr);
- IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+ iwl_tfd_set_tb(tfd, num_tbs, addr, len);
return 0;
}
@@ -210,7 +246,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int i, slots_num, len;
+ int i, len;
if (q->n_bd == 0)
return;
@@ -221,21 +257,15 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
iwl_hw_txq_free_tfd(priv, txq);
len = sizeof(struct iwl_cmd) * q->n_window;
- if (q->id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */
- slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
- TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- for (i = 0; i < slots_num; i++)
+ for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
- if (txq_id == IWL_CMD_QUEUE_NUM)
- kfree(txq->cmd[slots_num]);
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
- pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
- txq->q.n_bd, txq->bd, txq->q.dma_addr);
+ pci_free_consistent(dev, sizeof(struct iwl_tfd) *
+ txq->q.n_bd, txq->tfds, txq->q.dma_addr);
/* De-alloc array of per-TFD driver data */
kfree(txq->txb);
@@ -245,6 +275,40 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
memset(txq, 0, sizeof(*txq));
}
+
+/**
+ * iwl_cmd_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_cmd_queue_free(struct iwl_priv *priv)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int i, len;
+
+ if (q->n_bd == 0)
+ return;
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ len += IWL_MAX_SCAN_SIZE;
+
+ /* De-alloc array of command/tx buffers */
+ for (i = 0; i <= TFD_CMD_SLOTS; i++)
+ kfree(txq->cmd[i]);
+
+ /* De-alloc circular buffer of TFDs */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd) *
+ txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+
+ /* 0-fill queue descriptor structure */
+ memset(txq, 0, sizeof(*txq));
+}
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
* DMA services
*
@@ -340,13 +404,13 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Circular buffer of transmit frame descriptors (TFDs),
* shared with device */
- txq->bd = pci_alloc_consistent(dev,
- sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ txq->tfds = pci_alloc_consistent(dev,
+ sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX,
&txq->q.dma_addr);
- if (!txq->bd) {
+ if (!txq->tfds) {
IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
- sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX);
goto error;
}
txq->q.id = id;
@@ -370,26 +434,21 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
- int rc;
+ int ret;
unsigned long flags;
int txq_id = txq->q.id;
spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
+ return ret;
}
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
- /* Enable DMA channel, using same id as for TFD queue */
- iwl_write_direct32(
- priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -468,16 +527,20 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
/* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- iwl_tx_queue_free(priv, txq_id);
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ iwl_cmd_queue_free(priv);
+ else
+ iwl_tx_queue_free(priv, txq_id);
- /* Keep-warm buffer */
- iwl_kw_free(priv);
+ iwl_free_dma_ptr(priv, &priv->kw);
+
+ iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
}
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
/**
* iwl_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialise them again
+ * Destroys all DMA structures and initialize them again
*
* @param priv
* @return error code
@@ -488,13 +551,17 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
int txq_id, slots_num;
unsigned long flags;
- iwl_kw_free(priv);
-
/* Free all tx/cmd queues and keep-warm buffer */
iwl_hw_txq_ctx_free(priv);
+ ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+ priv->hw_params.scd_bc_tbls_size);
+ if (ret) {
+ IWL_ERROR("Scheduler BC Table allocation failed\n");
+ goto error_bc_tbls;
+ }
/* Alloc keep-warm buffer */
- ret = iwl_kw_alloc(priv);
+ ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
if (ret) {
IWL_ERROR("Keep Warm allocation failed\n");
goto error_kw;
@@ -509,17 +576,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
/* Turn off all Tx DMA fifos */
priv->cfg->ops->lib->txq_set_sched(priv, 0);
+ /* Tell NIC where to find the "keep warm" buffer */
+ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Tell nic where to find the keep-warm buffer */
- ret = iwl_kw_init(priv);
- if (ret) {
- IWL_ERROR("kw_init failed\n");
- goto error_reset;
- }
-
/* Alloc and init all Tx queues, including the command queue (#4) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
@@ -537,8 +599,10 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
error:
iwl_hw_txq_ctx_free(priv);
error_reset:
- iwl_kw_free(priv);
+ iwl_free_dma_ptr(priv, &priv->kw);
error_kw:
+ iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+ error_bc_tbls:
return ret;
}
@@ -547,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
*/
void iwl_txq_ctx_stop(struct iwl_priv *priv)
{
-
- int txq_id;
+ int ch;
unsigned long flags;
-
/* Turn off all Tx DMA fifos */
spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) {
@@ -562,12 +624,11 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
priv->cfg->ops->lib->txq_set_sched(priv, 0);
/* Stop each Tx DMA channel, and wait for it to be idle */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- iwl_write_direct32(priv,
- FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
+ for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
+ iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
- FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
- (txq_id), 200);
+ FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+ 1000);
}
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -584,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
- int is_unicast, u8 std_id)
+ u8 std_id)
{
__le16 fc = hdr->frame_control;
__le32 tx_flags = tx_cmd->tx_flags;
@@ -647,11 +708,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
__le16 fc, int sta_id,
int is_hcca)
{
+ u32 rate_flags = 0;
+ int rate_idx;
u8 rts_retry_limit = 0;
u8 data_retry_limit = 0;
u8 rate_plcp;
- u16 rate_flags = 0;
- int rate_idx;
rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff,
IWL_RATE_COUNT - 1);
@@ -694,14 +755,8 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
break;
}
- /* Alternate between antenna A and B for successive frames */
- if (priv->use_ant_b_for_management_frame) {
- priv->use_ant_b_for_management_frame = 0;
- rate_flags |= RATE_MCS_ANT_B_MSK;
- } else {
- priv->use_ant_b_for_management_frame = 1;
- rate_flags |= RATE_MCS_ANT_A_MSK;
- }
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
}
tx_cmd->rts_retry_limit = rts_retry_limit;
@@ -723,7 +778,7 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
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("tx_cmd with aes hwcrypto\n");
+ IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n");
break;
case ALG_TKIP:
@@ -767,7 +822,7 @@ int iwl_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_tfd_frame *tfd;
+ struct iwl_tfd *tfd;
struct iwl_tx_queue *txq;
struct iwl_queue *q;
struct iwl_cmd *out_cmd;
@@ -776,10 +831,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
- u16 len, idx, len_org;
+ u16 len, len_org;
u16 seq_number = 0;
__le16 fc;
- u8 hdr_len, unicast;
+ u8 hdr_len;
u8 sta_id;
u8 wait_write_ptr = 0;
u8 tid = 0;
@@ -799,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock;
}
- unicast = !is_multicast_ether_addr(hdr->addr1);
-
fc = hdr->frame_control;
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -830,10 +883,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Find (or create) index into station table for destination station */
sta_id = iwl_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
- print_mac(mac, hdr->addr1));
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n",
+ hdr->addr1);
goto drop;
}
@@ -856,23 +907,22 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
priv->stations[sta_id].tid[tid].tfds_in_queue++;
}
- /* Descriptor for chosen Tx queue */
txq = &priv->txq[txq_id];
q = &txq->q;
+ txq->swq_id = swq_id;
spin_lock_irqsave(&priv->lock, flags);
/* Set up first empty TFD within this queue's circular TFD buffer */
- tfd = &txq->bd[q->write_ptr];
+ tfd = &txq->tfds[q->write_ptr];
memset(tfd, 0, sizeof(*tfd));
- idx = get_cmd_index(q, q->write_ptr, 0);
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
txq->txb[q->write_ptr].skb[0] = skb;
/* Set up first empty entry in queue's array of Tx/cmd buffers */
- out_cmd = txq->cmd[idx];
+ out_cmd = txq->cmd[q->write_ptr];
tx_cmd = &out_cmd->cmd.tx;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -912,12 +962,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
- txcmd_phys = pci_map_single(priv->pci_dev, out_cmd,
- sizeof(struct iwl_cmd), PCI_DMA_TODEVICE);
- txcmd_phys += offsetof(struct iwl_cmd, hdr);
-
+ txcmd_phys = pci_map_single(priv->pci_dev,
+ out_cmd, sizeof(struct iwl_cmd),
+ PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
+ pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
+ txcmd_phys += offsetof(struct iwl_cmd, hdr);
iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
if (info->control.hw_key)
@@ -940,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len = (u16)skb->len;
tx_cmd->len = cpu_to_le16(len);
/* TODO need this for burst mode later on */
- iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+ iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
/* set is_hcca to 0; it probably will never be implemented */
iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
@@ -950,7 +1002,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
- tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+ tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -983,7 +1035,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
} else {
- ieee80211_stop_queue(priv->hw, swq_id);
+ ieee80211_stop_queue(priv->hw, txq->swq_id);
}
}
@@ -1011,7 +1063,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
- struct iwl_tfd_frame *tfd;
+ struct iwl_tfd *tfd;
struct iwl_cmd *out_cmd;
dma_addr_t phys_addr;
unsigned long flags;
@@ -1040,7 +1092,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
spin_lock_irqsave(&priv->hcmd_lock, flags);
- tfd = &txq->bd[q->write_ptr];
+ tfd = &txq->tfds[q->write_ptr];
memset(tfd, 0, sizeof(*tfd));
@@ -1061,9 +1113,13 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
len = (idx == TFD_CMD_SLOTS) ?
IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
- phys_addr = pci_map_single(priv->pci_dev, out_cmd, len,
- PCI_DMA_TODEVICE);
+
+ phys_addr = pci_map_single(priv->pci_dev, out_cmd,
+ len, PCI_DMA_TODEVICE);
+ pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
+ pci_unmap_len_set(&out_cmd->meta, len, len);
phys_addr += offsetof(struct iwl_cmd, hdr);
+
iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
#ifdef CONFIG_IWLWIFI_DEBUG
@@ -1113,8 +1169,9 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
return 0;
}
- for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
+ q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
@@ -1138,44 +1195,34 @@ EXPORT_SYMBOL(iwl_tx_queue_reclaim);
* 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_priv *priv, int txq_id, int index)
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
+ int idx, int cmd_idx)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
- struct iwl_tfd_frame *bd = &txq->bd[index];
- dma_addr_t dma_addr;
- int is_odd, buf_len;
int nfreed = 0;
- if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+ if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
"is out of range [0-%d] %d %d.\n", txq_id,
- index, q->n_bd, q->write_ptr, q->read_ptr);
+ idx, q->n_bd, q->write_ptr, q->read_ptr);
return;
}
- for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ pci_unmap_single(priv->pci_dev,
+ pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
+ pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
+ PCI_DMA_TODEVICE);
+
+ 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 > 1) {
- IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ if (nfreed++ > 0) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", idx,
q->write_ptr, q->read_ptr);
queue_work(priv->workqueue, &priv->restart);
}
- is_odd = (index/2) & 0x1;
- if (is_odd) {
- dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
- (IWL_GET_BITS(bd->pa[index],
- tb2_addr_hi20) << 16);
- buf_len = IWL_GET_BITS(bd->pa[index], tb2_len);
- } else {
- dma_addr = le32_to_cpu(bd->pa[index].tb1_addr);
- buf_len = IWL_GET_BITS(bd->pa[index], tb1_len);
- }
- pci_unmap_single(priv->pci_dev, dma_addr, buf_len,
- PCI_DMA_TODEVICE);
- nfreed++;
}
}
@@ -1201,8 +1248,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
* command queue then there a command routing bug has been introduced
* in the queue management code. */
if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
- "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd))
+ "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
+ txq_id, sequence,
+ priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
+ priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+ iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
return;
+ }
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
@@ -1215,7 +1267,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
!cmd->meta.u.callback(priv, cmd, rxb->skb))
rxb->skb = NULL;
- iwl_hcmd_queue_reclaim(priv, txq_id, index);
+ iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
if (!(cmd->meta.flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -1248,15 +1300,14 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
int ret;
unsigned long flags;
struct iwl_tid_data *tid_data;
- DECLARE_MAC_BUF(mac);
if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
tx_fifo = default_tid_to_tx_fifo[tid];
else
return -EINVAL;
- IWL_WARNING("%s on ra = %s tid = %d\n",
- __func__, print_mac(mac, ra), tid);
+ IWL_WARNING("%s on ra = %pM tid = %d\n",
+ __func__, ra, tid);
sta_id = iwl_find_station(priv, ra);
if (sta_id == IWL_INVALID_STATION)
@@ -1301,7 +1352,6 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
struct iwl_tid_data *tid_data;
int ret, write_ptr, read_ptr;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
if (!ra) {
IWL_ERROR("ra = NULL\n");
@@ -1362,8 +1412,8 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
case IWL_EMPTYING_HW_QUEUE_DELBA:
/* We are reclaiming the last packet of the */
/* aggregated HW queue */
- if (txq_id == tid_data->agg.txq_id &&
- q->read_ptr == q->write_ptr) {
+ if ((txq_id == tid_data->agg.txq_id) &&
+ (q->read_ptr == q->write_ptr)) {
u16 ssn = SEQ_TO_SN(tid_data->seq_number);
int tx_fifo = default_tid_to_tx_fifo[tid];
IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
@@ -1414,7 +1464,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
/* Calculate shift to align block-ack bits with our Tx window bits */
- sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4);
+ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
if (sh < 0) /* tbw something is wrong with indices */
sh += 0x100;
@@ -1436,7 +1486,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
ack = bitmap & (1ULL << i);
successes += !!ack;
IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
- ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
+ ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
agg->start_idx + i);
}
@@ -1464,10 +1514,11 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
- int index;
struct iwl_tx_queue *txq = NULL;
struct iwl_ht_agg *agg;
- DECLARE_MAC_BUF(mac);
+ int index;
+ int sta_id;
+ int tid;
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1482,17 +1533,19 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
}
txq = &priv->txq[scd_flow];
- agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+ sta_id = ba_resp->sta_id;
+ tid = ba_resp->tid;
+ agg = &priv->stations[sta_id].tid[tid].agg;
/* Find index just before block-ack window */
index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
/* TODO: Need to get this copy more safely - now good for debug */
- IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+ IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d] Received from %pM, "
"sta_id = %d\n",
agg->wait_for_ba,
- print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32),
+ (u8 *) &ba_resp->sta_addr_lo32,
ba_resp->sta_id);
IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
"%d, scd_ssn = %d\n",
@@ -1513,18 +1566,15 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
* transmitted ... if not, it's too late anyway). */
if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
/* calculate mac80211 ampdu sw queue to wake */
- int ampdu_q =
- scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues;
int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
- priv->stations[ba_resp->sta_id].
- tid[ba_resp->tid].tfds_in_queue -= freed;
- if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
- priv->mac80211_registered &&
- agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
- ieee80211_wake_queue(priv->hw, ampdu_q);
-
- iwl_txq_check_empty(priv, ba_resp->sta_id,
- ba_resp->tid, scd_flow);
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+ if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+ priv->mac80211_registered &&
+ (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+ ieee80211_wake_queue(priv->hw, txq->swq_id);
+
+ iwl_txq_check_empty(priv, sta_id, tid, scd_flow);
}
}
EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 45a6b0c3569..d64580805d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -22,7 +22,7 @@
* file called LICENSE.
*
* Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
@@ -41,6 +41,7 @@
#include <linux/if_arp.h>
#include <net/ieee80211_radiotap.h>
+#include <net/lib80211.h>
#include <net/mac80211.h>
#include <asm/div64.h>
@@ -64,11 +65,10 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
/* module parameters */
static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
-static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */
+static u32 iwl3945_param_debug; /* def: 0 = minimal debug log messages */
static int iwl3945_param_disable; /* def: 0 = enable radio */
static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */
int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */
-static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
/*
@@ -93,12 +93,13 @@ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
#define IWLWIFI_VERSION "1.2.26k" VD VS
#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
+#define DRV_AUTHOR "<ilw@linux.intel.com>"
#define DRV_VERSION IWLWIFI_VERSION
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
static const struct ieee80211_supported_band *iwl3945_get_band(
@@ -107,46 +108,6 @@ static const struct ieee80211_supported_band *iwl3945_get_band(
return priv->hw->wiphy->bands[band];
}
-static int iwl3945_is_empty_essid(const char *essid, int essid_len)
-{
- /* Single white space is for Linksys APs */
- if (essid_len == 1 && essid[0] == ' ')
- return 1;
-
- /* Otherwise, if the entire essid is 0, we assume it is hidden */
- while (essid_len) {
- essid_len--;
- if (essid[essid_len] != '\0')
- return 0;
- }
-
- return 1;
-}
-
-static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
-{
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- const char *s = essid;
- char *d = escaped;
-
- if (iwl3945_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
- while (essid_len--) {
- if (*s == '\0') {
- *d++ = '\\';
- *d++ = '0';
- s++;
- } else
- *d++ = *s++;
- }
- *d = '\0';
- return escaped;
-}
-
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
* DMA services
*
@@ -446,7 +407,6 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8
int index = IWL_INVALID_STATION;
struct iwl3945_station_entry *station;
unsigned long flags_spin;
- DECLARE_MAC_BUF(mac);
u8 rate;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
@@ -480,7 +440,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8
return index;
}
- IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ IWL_DEBUG_ASSOC("Add STA ID %d: %pM\n", index, addr);
station = &priv->stations[index];
station->used = 1;
priv->num_stations++;
@@ -559,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
-#define IWL_CMD(x) case x : return #x
+#define IWL_CMD(x) case x: return #x
static const char *get_cmd_string(u8 cmd)
{
@@ -1063,7 +1023,6 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
/* cast away the const for active_rxon in this function */
struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
int rc = 0;
- DECLARE_MAC_BUF(mac);
if (!iwl3945_is_alive(priv))
return -1;
@@ -1124,11 +1083,11 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
IWL_DEBUG_INFO("Sending RXON\n"
"* with%s RXON_FILTER_ASSOC_MSK\n"
"* channel = %d\n"
- "* bssid = %s\n",
+ "* bssid = %pM\n",
((priv->staging_rxon.filter_flags &
RXON_FILTER_ASSOC_MSK) ? "" : "out"),
le16_to_cpu(priv->staging_rxon.channel),
- print_mac(mac, priv->staging_rxon.bssid_addr));
+ priv->staging_rxon.bssid_addr);
/* Apply the new configuration */
rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
@@ -1443,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *
unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
struct ieee80211_hdr *hdr,
- const u8 *dest, int left)
+ int left)
{
if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
@@ -1459,9 +1418,16 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
return priv->ibss_beacon->len;
}
-static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv)
{
u8 i;
+ int rate_mask;
+
+ /* Set rate mask*/
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
+ else
+ rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
i = iwl3945_rates[i].next_ieee) {
@@ -1469,7 +1435,11 @@ static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
return iwl3945_rates[i].plcp;
}
- return IWL_RATE_INVALID;
+ /* No valid rate was found. Assign the lowest one */
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ return IWL_RATE_1M_PLCP;
+ else
+ return IWL_RATE_6M_PLCP;
}
static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv)
@@ -1487,16 +1457,7 @@ static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv)
return -ENOMEM;
}
- if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
- rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic &
- 0xFF0);
- if (rate == IWL_INVALID_RATE)
- rate = IWL_RATE_6M_PLCP;
- } else {
- rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
- if (rate == IWL_INVALID_RATE)
- rate = IWL_RATE_1M_PLCP;
- }
+ rate = iwl3945_rate_get_lowest_plcp(priv);
frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
@@ -1544,10 +1505,8 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
{
u16 *e = (u16 *)&priv->eeprom;
u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
- u32 r;
int sz = sizeof(priv->eeprom);
- int rc;
- int i;
+ int ret;
u16 addr;
/* The EEPROM structure has several padding buffers within it
@@ -1562,29 +1521,28 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
- rc = iwl3945_eeprom_acquire_semaphore(priv);
- if (rc < 0) {
+ ret = iwl3945_eeprom_acquire_semaphore(priv);
+ if (ret < 0) {
IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
return -ENOENT;
}
/* eeprom is an array of 16bit values */
for (addr = 0; addr < sz; addr += sizeof(u16)) {
- _iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1);
- _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
-
- for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
- i += IWL_EEPROM_ACCESS_DELAY) {
- r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
- if (r & CSR_EEPROM_REG_READ_VALID_MSK)
- break;
- udelay(IWL_EEPROM_ACCESS_DELAY);
- }
+ u32 r;
- if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ _iwl3945_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+ ret = iwl3945_poll_direct_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
+ if (ret < 0) {
IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
- return -ETIMEDOUT;
+ return ret;
}
+
+ r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
@@ -1634,7 +1592,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate,
*/
static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
struct ieee80211_mgmt *frame,
- int left, int is_direct)
+ int left)
{
int len = 0;
u8 *pos = NULL;
@@ -1664,20 +1622,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
*pos++ = WLAN_EID_SSID;
*pos++ = 0;
- /* fill in our direct SSID IE... */
- if (is_direct) {
- /* ...next IE... */
- left -= 2 + priv->essid_len;
- if (left < 0)
- return 0;
- /* ... fill it in... */
- *pos++ = WLAN_EID_SSID;
- *pos++ = priv->essid_len;
- memcpy(pos, priv->essid, priv->essid_len);
- pos += priv->essid_len;
- len += 2 + priv->essid_len;
- }
-
/* fill in supported rate */
/* ...next IE... */
left -= 2;
@@ -1746,17 +1690,21 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
priv->qos_data.qos_active = 0;
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
- if (priv->qos_data.qos_enable)
- priv->qos_data.qos_active = 1;
- if (!(priv->active_rate & 0xfff0)) {
- cw_min = 31;
- is_legacy = 1;
- }
- } else if (priv->iw_mode == NL80211_IFTYPE_AP) {
- if (priv->qos_data.qos_enable)
- priv->qos_data.qos_active = 1;
- } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ /* QoS always active in AP and ADHOC mode
+ * In STA mode wait for association
+ */
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
+ priv->iw_mode == NL80211_IFTYPE_AP)
+ priv->qos_data.qos_active = 1;
+ else
+ priv->qos_data.qos_active = 0;
+
+
+ /* check for legacy mode */
+ if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+ (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
+ (priv->iw_mode == NL80211_IFTYPE_STATION &&
+ (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
cw_min = 31;
is_legacy = 1;
}
@@ -1828,9 +1776,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- if (!priv->qos_data.qos_enable)
- return;
-
spin_lock_irqsave(&priv->lock, flags);
priv->qos_data.def_qos_parm.qos_flags = 0;
@@ -1846,7 +1791,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force)
spin_unlock_irqrestore(&priv->lock, flags);
if (force || iwl3945_is_associated(priv)) {
- IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+ IWL_DEBUG_QOS("send QoS cmd with QoS active %d \n",
priv->qos_data.qos_active);
iwl3945_send_qos_params_command(priv,
@@ -1870,7 +1815,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force)
/* default power management (not Tx power) table values */
-/* for tim 0-10 */
+/* for TIM 0-10 */
static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = {
{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
@@ -1880,7 +1825,7 @@ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = {
{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
};
-/* for tim > 10 */
+/* for TIM > 10 */
static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = {
{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
@@ -2156,11 +2101,6 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv)
static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
{
- if (priv->iw_mode == NL80211_IFTYPE_AP) {
- IWL_ERROR("APs don't scan.\n");
- return 0;
- }
-
if (!iwl3945_is_ready_rf(priv)) {
IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
return -EIO;
@@ -2230,13 +2170,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv,
/*
* initialize rxon structure with default values from eeprom
*/
-static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv,
+ int mode)
{
const struct iwl3945_channel_info *ch_info;
memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
- switch (priv->iw_mode) {
+ switch (mode) {
case NL80211_IFTYPE_AP:
priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
break;
@@ -2259,7 +2200,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
break;
default:
- IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+ IWL_ERROR("Unsupported interface type %d\n", mode);
break;
}
@@ -2282,8 +2223,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
* in some case A channels are all non IBSS
* in this case force B/G channel
*/
- if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
- !(is_channel_ibss(ch_info)))
+ if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info)))
ch_info = &priv->channel_info[0];
priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
@@ -2316,14 +2256,12 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
}
}
- priv->iw_mode = mode;
-
- iwl3945_connection_init_rx_config(priv);
+ iwl3945_connection_init_rx_config(priv, mode);
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
iwl3945_clear_stations_table(priv);
- /* dont commit rxon if rf-kill is on*/
+ /* don't commit rxon if rf-kill is on*/
if (!iwl3945_is_ready_rf(priv))
return -EAGAIN;
@@ -2352,7 +2290,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
case ALG_CCMP:
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
- IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n");
break;
case ALG_TKIP:
@@ -2397,6 +2335,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
{
__le16 fc = hdr->frame_control;
__le32 tx_flags = cmd->cmd.tx.tx_flags;
+ u8 rc_flags = info->control.rates[0].flags;
cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
@@ -2423,10 +2362,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
tx_flags |= TX_CMD_FLG_RTS_MSK;
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
tx_flags |= TX_CMD_FLG_CTS_MSK;
}
@@ -2482,8 +2421,6 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
case NL80211_IFTYPE_ADHOC: {
- DECLARE_MAC_BUF(mac);
-
/* Create new station table entry */
sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
@@ -2494,9 +2431,9 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
if (sta_id != IWL_INVALID_STATION)
return sta_id;
- IWL_DEBUG_DROP("Station %s not in station map. "
+ IWL_DEBUG_DROP("Station %pM not in station map. "
"Defaulting to broadcast...\n",
- print_mac(mac, hdr->addr1));
+ hdr->addr1);
iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_setting.bcast_sta_id;
}
@@ -2579,10 +2516,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
/* Find (or create) index into station table for destination station */
sta_id = iwl3945_get_sta_id(priv, hdr);
if (sta_id == IWL_INVALID_STATION) {
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
- print_mac(mac, hdr->addr1));
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n",
+ hdr->addr1);
goto drop;
}
@@ -4019,8 +3954,6 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
#ifdef CONFIG_IWL3945_DEBUG
static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon)
{
- DECLARE_MAC_BUF(mac);
-
IWL_DEBUG_RADIO("RX CONFIG:\n");
iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
@@ -4031,10 +3964,8 @@ static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon)
IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
rxon->ofdm_basic_rates);
IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
- IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
- print_mac(mac, rxon->node_addr));
- IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
- print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr);
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
#endif
@@ -4050,7 +3981,7 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
/* call this function to flush any scheduled tasklet */
static inline void iwl_synchronize_irq(struct iwl3945_priv *priv)
{
- /* wait to make sure we flush pedding tasklet*/
+ /* wait to make sure we flush pending tasklet*/
synchronize_irq(priv->pci_dev->irq);
tasklet_kill(&priv->irq_tasklet);
}
@@ -4373,35 +4304,6 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
/* Safely ignore these bits for debug checks below */
inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
- /* HW RF KILL switch toggled (4965 only) */
- if (inta & CSR_INT_BIT_RF_KILL) {
- int hw_rf_kill = 0;
- if (!(iwl3945_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
- hw_rf_kill = 1;
-
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
- "RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio":"enable radio");
-
- /* Queue restart only if RF_KILL switch was set to "kill"
- * when we loaded driver, and is now set to "enable".
- * After we're Alive, RF_KILL gets handled by
- * iwl3945_rx_card_state_notif() */
- if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- queue_work(priv->workqueue, &priv->restart);
- }
-
- handled |= CSR_INT_BIT_RF_KILL;
- }
-
- /* Chip got too hot and stopped itself (4965 only) */
- if (inta & CSR_INT_BIT_CT_KILL) {
- IWL_ERROR("Microcode CT kill error detected.\n");
- handled |= CSR_INT_BIT_CT_KILL;
- }
-
/* Error detected by uCode */
if (inta & CSR_INT_BIT_SW_ERR) {
IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
@@ -4502,7 +4404,7 @@ static irqreturn_t iwl3945_isr(int irq, void *data)
if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
/* Hardware disappeared */
- IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta);
goto unplugged;
}
@@ -4805,7 +4707,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
-#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+#define IWL_SCAN_PROBE_MASK(n) (BIT(n) | (BIT(n) - BIT(1)))
static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv,
enum ieee80211_band band,
@@ -4876,17 +4778,33 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
continue;
}
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+ /* If passive , set up for auto-switch
+ * and use long active_dwell time.
+ */
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
scan_ch->type = 0; /* passive */
- else
+ if (IWL_UCODE_API(priv->ucode_ver) == 1)
+ scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
+ } else {
scan_ch->type = 1; /* active */
+ }
- if ((scan_ch->type & 1) && 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 direct probe bits. These may be used both for active
+ * scan channels (probes gets sent right away),
+ * or for passive channels (probes get se sent only after
+ * hearing clear Rx packet).*/
+ if (IWL_UCODE_API(priv->ucode_ver) >= 2) {
+ if (n_probes)
+ scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+ } else {
+ /* uCode v1 does not allow setting direct probe bits on
+ * passive channel. */
+ if ((scan_ch->type & 1) && n_probes)
+ scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+ }
/* Set txpower levels to defaults */
scan_ch->tpc.dsp_atten = 110;
@@ -5387,25 +5305,41 @@ static void iwl3945_nic_start(struct iwl3945_priv *priv)
static int iwl3945_read_ucode(struct iwl3945_priv *priv)
{
struct iwl3945_ucode *ucode;
- int ret = 0;
+ int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
- const char *name = priv->cfg->fw_name;
+ const char *name_pre = priv->cfg->fw_name_pre;
+ const unsigned int api_max = priv->cfg->ucode_api_max;
+ const unsigned int api_min = priv->cfg->ucode_api_min;
+ char buf[25];
u8 *src;
size_t len;
- u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
- ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
- if (ret < 0) {
- IWL_ERROR("%s firmware file req failed: Reason %d\n",
- name, ret);
- goto error;
+ for (index = api_max; index >= api_min; index--) {
+ sprintf(buf, "%s%u%s", name_pre, index, ".ucode");
+ ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev);
+ if (ret < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n",
+ buf, ret);
+ if (ret == -ENOENT)
+ continue;
+ else
+ goto error;
+ } else {
+ if (index < api_max)
+ IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n",
+ buf, api_max);
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ buf, ucode_raw->size);
+ break;
+ }
}
- IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
- name, ucode_raw->size);
+ if (ret < 0)
+ goto error;
/* Make sure that we got at least our header! */
if (ucode_raw->size < sizeof(*ucode)) {
@@ -5417,20 +5351,46 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv)
/* Data from ucode file: header followed by uCode images */
ucode = (void *)ucode_raw->data;
- ver = le32_to_cpu(ucode->ver);
+ priv->ucode_ver = le32_to_cpu(ucode->ver);
+ api_ver = IWL_UCODE_API(priv->ucode_ver);
inst_size = le32_to_cpu(ucode->inst_size);
data_size = le32_to_cpu(ucode->data_size);
init_size = le32_to_cpu(ucode->init_size);
init_data_size = le32_to_cpu(ucode->init_data_size);
boot_size = le32_to_cpu(ucode->boot_size);
- IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ /* api_ver should match the api version forming part of the
+ * firmware filename ... but we don't check for that and only rely
+ * on the API version read from firware header from here on forward */
+
+ if (api_ver < api_min || api_ver > api_max) {
+ IWL_ERROR("Driver unable to support your firmware API. "
+ "Driver supports v%u, firmware is v%u.\n",
+ api_max, api_ver);
+ priv->ucode_ver = 0;
+ ret = -EINVAL;
+ goto err_release;
+ }
+ if (api_ver != api_max)
+ IWL_ERROR("Firmware has old API version. Expected %u, "
+ "got %u. New firmware can be obtained "
+ "from http://www.intellinuxwireless.org.\n",
+ api_max, api_ver);
+
+ printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n",
+ IWL_UCODE_MAJOR(priv->ucode_ver),
+ IWL_UCODE_MINOR(priv->ucode_ver),
+ IWL_UCODE_API(priv->ucode_ver),
+ IWL_UCODE_SERIAL(priv->ucode_ver));
+ IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n",
+ priv->ucode_ver);
IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size);
IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size);
IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size);
IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size);
IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size);
+
/* Verify size of file vs. image size info in file's header */
if (ucode_raw->size < sizeof(*ucode) +
inst_size + data_size + init_size +
@@ -5607,7 +5567,7 @@ static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv)
iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
priv->ucode_data.len);
- /* Inst bytecount must be last to set up, bit 31 signals uCode
+ /* Inst byte count must be last to set up, bit 31 signals uCode
* that all new ptr/size info is in place */
iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
priv->ucode_code.len | BSM_DRAM_INST_LOAD);
@@ -5665,6 +5625,10 @@ static void iwl3945_init_alive_start(struct iwl3945_priv *priv)
}
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *skb);
+
/**
* iwl3945_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
@@ -5699,7 +5663,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
rc = iwl3945_grab_nic_access(priv);
if (rc) {
- IWL_WARNING("Can not read rfkill status from adapter\n");
+ IWL_WARNING("Can not read RFKILL status from adapter\n");
return;
}
@@ -5709,7 +5673,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
if (rfkill & 0x1) {
clear_bit(STATUS_RF_KILL_HW, &priv->status);
- /* if rfkill is not on, then wait for thermal
+ /* if RFKILL is not on, then wait for thermal
* sensor in adapter to kick in */
while (iwl3945_hw_get_temperature(priv) == 0) {
thermal_spin++;
@@ -5747,7 +5711,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
} else {
/* Initialize our rx_config data */
- iwl3945_connection_init_rx_config(priv);
+ iwl3945_connection_init_rx_config(priv, priv->iw_mode);
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
@@ -5768,6 +5732,14 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
if (priv->error_recovering)
iwl3945_error_recovery(priv);
+ /* reassociate for ADHOC mode */
+ if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
+ struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
+ priv->vif);
+ if (beacon)
+ iwl3945_mac_beacon_update(priv->hw, beacon);
+ }
+
return;
restart:
@@ -5902,7 +5874,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
}
if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
- IWL_ERROR("ucode not available for device bringup\n");
+ IWL_ERROR("ucode not available for device bring up\n");
return -EIO;
}
@@ -6046,24 +6018,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
iwl3945_rfkill_set_hw_state(priv);
}
-static void iwl3945_bg_set_monitor(struct work_struct *work)
-{
- struct iwl3945_priv *priv = container_of(work,
- struct iwl3945_priv, set_monitor);
-
- IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
-
- mutex_lock(&priv->mutex);
-
- if (!iwl3945_is_ready(priv))
- IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
- else
- if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0)
- IWL_ERROR("iwl3945_set_mode() failed\n");
-
- mutex_unlock(&priv->mutex);
-}
-
#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6101,6 +6055,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
struct ieee80211_conf *conf = NULL;
u8 n_probes = 2;
enum ieee80211_band band;
+ DECLARE_SSID_BUF(ssid);
conf = ieee80211_get_hw_conf(priv->hw);
@@ -6111,7 +6066,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
goto done;
}
- /* Make sure the scan wasn't cancelled before this queued work
+ /* Make sure the scan wasn't canceled before this queued work
* was given the chance to run... */
if (!test_bit(STATUS_SCANNING, &priv->status))
goto done;
@@ -6201,21 +6156,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
if (priv->one_direct_scan) {
IWL_DEBUG_SCAN
("Kicking off one direct scan for '%s'\n",
- iwl3945_escape_essid(priv->direct_ssid,
- priv->direct_ssid_len));
+ print_ssid(ssid, priv->direct_ssid,
+ priv->direct_ssid_len));
scan->direct_scan[0].id = WLAN_EID_SSID;
scan->direct_scan[0].len = priv->direct_ssid_len;
memcpy(scan->direct_scan[0].ssid,
priv->direct_ssid, priv->direct_ssid_len);
n_probes++;
- } else if (!iwl3945_is_associated(priv) && priv->essid_len) {
- IWL_DEBUG_SCAN
- ("Kicking off one direct scan for '%s' when not associated\n",
- iwl3945_escape_essid(priv->essid, priv->essid_len));
- scan->direct_scan[0].id = WLAN_EID_SSID;
- scan->direct_scan[0].len = priv->essid_len;
- memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
- n_probes++;
} else
IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
@@ -6223,7 +6170,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
* that based on the direct_mask added to each channel entry */
scan->tx_cmd.len = cpu_to_le16(
iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
- IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
+ IWL_MAX_SCAN_SIZE - sizeof(*scan)));
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -6333,7 +6280,6 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
{
int rc = 0;
struct ieee80211_conf *conf = NULL;
- DECLARE_MAC_BUF(mac);
if (priv->iw_mode == NL80211_IFTYPE_AP) {
IWL_ERROR("%s Should not be called in AP mode\n", __func__);
@@ -6341,9 +6287,8 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
}
- IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
- priv->assoc_id,
- print_mac(mac, priv->active_rxon.bssid_addr));
+ IWL_DEBUG_ASSOC("Associated as %d to: %pM\n",
+ priv->assoc_id, priv->active_rxon.bssid_addr);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -6398,10 +6343,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv)
case NL80211_IFTYPE_ADHOC:
- /* clear out the station table */
- iwl3945_clear_stations_table(priv);
-
- iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+ priv->assoc_id = 1;
iwl3945_add_station(priv, priv->bssid, 0, 0);
iwl3945_sync_sta(priv, IWL_STA_ID,
(priv->band == IEEE80211_BAND_5GHZ) ?
@@ -6439,7 +6381,7 @@ static void iwl3945_bg_abort_scan(struct work_struct *work)
mutex_unlock(&priv->mutex);
}
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed);
static void iwl3945_bg_scan_completed(struct work_struct *work)
{
@@ -6452,7 +6394,7 @@ static void iwl3945_bg_scan_completed(struct work_struct *work)
return;
if (test_bit(STATUS_CONF_PENDING, &priv->status))
- iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+ iwl3945_mac_config(priv->hw, 0);
ieee80211_scan_completed(priv->hw);
@@ -6604,7 +6546,6 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
{
struct iwl3945_priv *priv = hw->priv;
unsigned long flags;
- DECLARE_MAC_BUF(mac);
IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
@@ -6615,13 +6556,14 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
spin_lock_irqsave(&priv->lock, flags);
priv->vif = conf->vif;
+ priv->iw_mode = conf->type;
spin_unlock_irqrestore(&priv->lock, flags);
mutex_lock(&priv->mutex);
if (conf->mac_addr) {
- IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr));
+ IWL_DEBUG_MAC80211("Set: %pM\n", conf->mac_addr);
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
}
@@ -6641,10 +6583,11 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
* be set inappropriately and the driver currently sets the hardware up to
* use it whenever needed.
*/
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
{
struct iwl3945_priv *priv = hw->priv;
const struct iwl3945_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
unsigned long flags;
int ret = 0;
@@ -6782,16 +6725,11 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
* clear sta table, add BCAST sta... */
}
-/* temporary */
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
-
static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct iwl3945_priv *priv = hw->priv;
- DECLARE_MAC_BUF(mac);
- unsigned long flags;
int rc;
if (conf == NULL)
@@ -6808,28 +6746,20 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (!beacon)
return -ENOMEM;
+ mutex_lock(&priv->mutex);
rc = iwl3945_mac_beacon_update(hw, beacon);
+ mutex_unlock(&priv->mutex);
if (rc)
return rc;
}
- /* XXX: this MUST use conf->mac_addr */
-
- if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
- (!conf->ssid_len)) {
- IWL_DEBUG_MAC80211
- ("Leaving in AP mode because HostAPD is not ready.\n");
- return 0;
- }
-
if (!iwl3945_is_alive(priv))
return -EAGAIN;
mutex_lock(&priv->mutex);
if (conf->bssid)
- IWL_DEBUG_MAC80211("bssid: %s\n",
- print_mac(mac, conf->bssid));
+ IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid);
/*
* very dubious code was here; the probe filtering flag is never set:
@@ -6842,8 +6772,8 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
if (!conf->bssid) {
conf->bssid = priv->mac_addr;
memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
- IWL_DEBUG_MAC80211("bssid was set to: %s\n",
- print_mac(mac, conf->bssid));
+ IWL_DEBUG_MAC80211("bssid was set to: %pM\n",
+ conf->bssid);
}
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
@@ -6889,15 +6819,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
}
done:
- spin_lock_irqsave(&priv->lock, flags);
- if (!conf->ssid_len)
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
- else
- memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
- priv->essid_len = conf->ssid_len;
- spin_unlock_irqrestore(&priv->lock, flags);
-
IWL_DEBUG_MAC80211("leave\n");
mutex_unlock(&priv->mutex);
@@ -6910,16 +6831,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
int mc_count, struct dev_addr_list *mc_list)
{
struct iwl3945_priv *priv = hw->priv;
+ __le32 *filter_flags = &priv->staging_rxon.filter_flags;
- if (changed_flags & (*total_flags) & FIF_OTHER_BSS) {
- IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
- NL80211_IFTYPE_MONITOR,
- changed_flags, *total_flags);
- /* queue work 'cuz mac80211 is holding a lock which
- * prevents us from issuing (synchronous) f/w cmds */
- queue_work(priv->workqueue, &priv->set_monitor);
+ IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n",
+ changed_flags, *total_flags);
+
+ if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
+ if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
+ *filter_flags |= RXON_FILTER_PROMISC_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
}
- *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
+ if (changed_flags & FIF_ALLMULTI) {
+ if (*total_flags & FIF_ALLMULTI)
+ *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
+ }
+ if (changed_flags & FIF_CONTROL) {
+ if (*total_flags & FIF_CONTROL)
+ *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
+ }
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
+ else
+ *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
+ }
+
+ /* We avoid iwl_commit_rxon here to commit the new filter flags
+ * since mac80211 will call ieee80211_hw_config immediately.
+ * (mc_list is not supported at this time). Otherwise, we need to
+ * queue a background iwl_commit_rxon work.
+ */
+
+ *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
@@ -6940,8 +6888,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
if (priv->vif == conf->vif) {
priv->vif = NULL;
memset(priv->bssid, 0, ETH_ALEN);
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
- priv->essid_len = 0;
}
mutex_unlock(&priv->mutex);
@@ -7010,6 +6956,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
int rc = 0;
unsigned long flags;
struct iwl3945_priv *priv = hw->priv;
+ DECLARE_SSID_BUF(ssid_buf);
IWL_DEBUG_MAC80211("enter\n");
@@ -7022,12 +6969,6 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
goto out_unlock;
}
- if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */
- rc = -EIO;
- IWL_ERROR("ERROR: APs don't scan\n");
- goto out_unlock;
- }
-
/* we don't schedule scan within next_scan_jiffies period */
if (priv->next_scan_jiffies &&
time_after(priv->next_scan_jiffies, jiffies)) {
@@ -7043,7 +6984,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
}
if (len) {
IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
- iwl3945_escape_essid(ssid, len), (int)len);
+ print_ssid(ssid_buf, ssid, len), (int)len);
priv->one_direct_scan = 1;
priv->direct_ssid_len = (u8)
@@ -7084,10 +7025,8 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
sta_id = iwl3945_hw_find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
+ IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
+ addr);
return -EINVAL;
}
@@ -7143,11 +7082,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
- if (!priv->qos_data.qos_enable) {
- priv->qos_data.qos_active = 0;
- IWL_DEBUG_MAC80211("leave - qos not enabled\n");
- return 0;
- }
q = AC_NUM - 1 - queue;
spin_lock_irqsave(&priv->lock, flags);
@@ -7219,14 +7153,6 @@ static int iwl3945_mac_get_stats(struct ieee80211_hw *hw,
return 0;
}
-static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw)
-{
- IWL_DEBUG_MAC80211("enter\n");
- IWL_DEBUG_MAC80211("leave\n");
-
- return 0;
-}
-
static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
{
struct iwl3945_priv *priv = hw->priv;
@@ -7292,18 +7218,15 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
struct iwl3945_priv *priv = hw->priv;
unsigned long flags;
- mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter\n");
if (!iwl3945_is_ready_rf(priv)) {
IWL_DEBUG_MAC80211("leave - RF not ready\n");
- mutex_unlock(&priv->mutex);
return -EIO;
}
if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
IWL_DEBUG_MAC80211("leave - not IBSS\n");
- mutex_unlock(&priv->mutex);
return -EIO;
}
@@ -7323,7 +7246,6 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
iwl3945_post_associate(priv);
- mutex_unlock(&priv->mutex);
return 0;
}
@@ -7792,7 +7714,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
/*****************************************************************************
*
- * driver setup and teardown
+ * driver setup and tear down
*
*****************************************************************************/
@@ -7810,7 +7732,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
- INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
@@ -7869,7 +7790,6 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.get_stats = iwl3945_mac_get_stats,
.get_tx_stats = iwl3945_mac_get_tx_stats,
.conf_tx = iwl3945_mac_conf_tx,
- .get_tsf = iwl3945_mac_get_tsf,
.reset_tsf = iwl3945_mac_reset_tsf,
.bss_info_changed = iwl3945_bss_info_changed,
.hw_scan = iwl3945_mac_hw_scan
@@ -7882,7 +7802,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
struct ieee80211_hw *hw;
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
unsigned long flags;
- DECLARE_MAC_BUF(mac);
+
+ /***********************
+ * 1. Allocating HW data
+ * ********************/
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
@@ -7907,48 +7830,41 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
err = -ENOMEM;
goto out;
}
- SET_IEEE80211_DEV(hw, &pdev->dev);
- hw->rate_control_algorithm = "iwl-3945-rs";
- hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+ SET_IEEE80211_DEV(hw, &pdev->dev);
- IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
priv = hw->priv;
priv->hw = hw;
-
priv->pci_dev = pdev;
priv->cfg = cfg;
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ hw->rate_control_algorithm = "iwl-3945-rs";
+ hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+
/* Select antenna (may be helpful if only one antenna is connected) */
priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
#ifdef CONFIG_IWL3945_DEBUG
iwl3945_debug_level = iwl3945_param_debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
- priv->retry_rate = 1;
-
- priv->ibss_beacon = NULL;
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
+ hw->wiphy->fw_handles_regulatory = true;
+
/* 4 EDCA QOS priorities */
hw->queues = 4;
- spin_lock_init(&priv->lock);
- spin_lock_init(&priv->power_data.lock);
- spin_lock_init(&priv->sta_lock);
- spin_lock_init(&priv->hcmd_lock);
-
- INIT_LIST_HEAD(&priv->free_frames);
-
- mutex_init(&priv->mutex);
+ /***************************
+ * 2. Initializing PCI bus
+ * *************************/
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_ieee80211_free_hw;
@@ -7956,14 +7872,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_set_master(pdev);
- /* Clear the driver's (not device's) station table */
- iwl3945_clear_stations_table(priv);
-
- priv->data_retry_limit = -1;
- priv->ieee_channels = NULL;
- priv->ieee_rates = NULL;
- priv->band = IEEE80211_BAND_2GHZ;
-
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (!err)
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
@@ -7977,10 +7885,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if (err)
goto out_pci_disable_device;
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_write_config_byte(pdev, 0x41, 0x00);
-
+ /***********************
+ * 3. Read REV Register
+ * ********************/
priv->hw_base = pci_iomap(pdev, 0, 0);
if (!priv->hw_base) {
err = -ENODEV;
@@ -7991,97 +7898,144 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
(unsigned long long) pci_resource_len(pdev, 0));
IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
- /* Initialize module parameter values here */
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
- /* Disable radio (SW RF KILL) via parameter when loading driver */
- if (iwl3945_param_disable) {
- set_bit(STATUS_RF_KILL_SW, &priv->status);
- IWL_DEBUG_INFO("Radio disabled.\n");
- }
+ /* nic init */
+ iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
- priv->iw_mode = NL80211_IFTYPE_STATION;
+ iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ err = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (err < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ goto out_remove_sysfs;
+ }
- printk(KERN_INFO DRV_NAME
- ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+ /***********************
+ * 4. Read EEPROM
+ * ********************/
+ /* Read the EEPROM */
+ err = iwl3945_eeprom_init(priv);
+ if (err) {
+ IWL_ERROR("Unable to init EEPROM\n");
+ goto out_remove_sysfs;
+ }
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr);
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ /***********************
+ * 5. Setup HW Constants
+ * ********************/
/* Device-specific setup */
if (iwl3945_hw_set_hw_setting(priv)) {
IWL_ERROR("failed to set hw settings\n");
goto out_iounmap;
}
- if (iwl3945_param_qos_enable)
- priv->qos_data.qos_enable = 1;
+ /***********************
+ * 6. Setup priv
+ * ********************/
+ priv->retry_rate = 1;
+ priv->ibss_beacon = NULL;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+ mutex_init(&priv->mutex);
+
+ /* Clear the driver's (not device's) station table */
+ iwl3945_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->band = IEEE80211_BAND_2GHZ;
+
+ priv->iw_mode = NL80211_IFTYPE_STATION;
iwl3945_reset_qos(priv);
priv->qos_data.qos_active = 0;
priv->qos_data.qos_cap.val = 0;
- iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
- iwl3945_setup_deferred_work(priv);
- iwl3945_setup_rx_handlers(priv);
priv->rates_mask = IWL_RATES_MASK;
/* If power management is turned on, default to AC mode */
priv->power_mode = IWL_POWER_AC;
priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
- spin_lock_irqsave(&priv->lock, flags);
- iwl3945_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+ err = iwl3945_init_channel_map(priv);
if (err) {
- IWL_ERROR("failed to create sysfs device attributes\n");
+ IWL_ERROR("initializing regulatory failed: %d\n", err);
goto out_release_irq;
}
- /* nic init */
- iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (err < 0) {
- IWL_DEBUG_INFO("Failed to init the card\n");
- goto out_remove_sysfs;
- }
- /* Read the EEPROM */
- err = iwl3945_eeprom_init(priv);
+ err = iwl3945_init_geos(priv);
if (err) {
- IWL_ERROR("Unable to init EEPROM\n");
- goto out_remove_sysfs;
+ IWL_ERROR("initializing geos failed: %d\n", err);
+ goto out_free_channel_map;
}
- /* MAC Address location in EEPROM same for 3945/4965 */
- get_eeprom_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
- err = iwl3945_init_channel_map(priv);
- if (err) {
- IWL_ERROR("initializing regulatory failed: %d\n", err);
- goto out_remove_sysfs;
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+
+ /***********************************
+ * 7. Initialize Module Parameters
+ * **********************************/
+
+ /* Initialize module parameter values here */
+ /* Disable radio (SW RF KILL) via parameter when loading driver */
+ if (iwl3945_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
}
- err = iwl3945_init_geos(priv);
+
+ /***********************
+ * 8. Setup Services
+ * ********************/
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl3945_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
if (err) {
- IWL_ERROR("initializing geos failed: %d\n", err);
- goto out_free_channel_map;
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ goto out_free_geos;
}
+ iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+ iwl3945_setup_deferred_work(priv);
+ iwl3945_setup_rx_handlers(priv);
+
+ /***********************
+ * 9. Conclude
+ * ********************/
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ /*********************************
+ * 10. Setup and Register mac80211
+ * *******************************/
+
err = ieee80211_register_hw(priv->hw);
if (err) {
IWL_ERROR("Failed to register network device (error %d)\n", err);
- goto out_free_geos;
+ goto out_remove_sysfs;
}
priv->hw->conf.beacon_int = 100;
priv->mac80211_registered = 1;
- pci_save_state(pdev);
- pci_disable_device(pdev);
+
err = iwl3945_rfkill_init(priv);
if (err)
@@ -8090,12 +8044,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
return 0;
+ out_remove_sysfs:
+ sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
out_free_geos:
iwl3945_free_geos(priv);
out_free_channel_map:
iwl3945_free_channel_map(priv);
- out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
out_release_irq:
destroy_workqueue(priv->workqueue);
@@ -8222,7 +8177,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0;
- IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
+ IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state);
mutex_lock(&priv->mutex);
switch (state) {
@@ -8237,7 +8192,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
iwl3945_radio_kill_sw(priv, 1);
break;
default:
- IWL_WARNING("we recieved unexpected RFKILL state %d\n", state);
+ IWL_WARNING("we received unexpected RFKILL state %d\n", state);
break;
}
out_unlock:
@@ -8379,7 +8334,7 @@ static void __exit iwl3945_exit(void)
iwl3945_rate_control_unregister();
}
-MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode");
+MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
module_param_named(antenna, iwl3945_param_antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
@@ -8388,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
MODULE_PARM_DESC(hwcrypto,
"using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, iwl3945_param_debug, int, 0444);
+module_param_named(debug, iwl3945_param_debug, uint, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
@@ -8396,9 +8351,5 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
module_param_named(queues_num, iwl3945_param_queues_num, int, 0444);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
-/* QoS */
-module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
-
module_exit(iwl3945_exit);
module_init(iwl3945_init);
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 92be60415d0..a0e440cd896 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,10 @@
/* Copyright (C) 2006, Red Hat, Inc. */
+#include <linux/types.h>
#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
+#include <net/lib80211.h>
#include "assoc.h"
#include "decl.h"
@@ -151,18 +155,18 @@ static int lbs_adhoc_join(struct lbs_private *priv,
struct cmd_ds_802_11_ad_hoc_join cmd;
struct bss_descriptor *bss = &assoc_req->bss;
u8 preamble = RADIO_PREAMBLE_LONG;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
u16 ratesize = 0;
int ret = 0;
lbs_deb_enter(LBS_DEB_ASSOC);
lbs_deb_join("current SSID '%s', ssid length %u\n",
- escape_essid(priv->curbssparams.ssid,
+ print_ssid(ssid, priv->curbssparams.ssid,
priv->curbssparams.ssid_len),
priv->curbssparams.ssid_len);
lbs_deb_join("requested ssid '%s', ssid length %u\n",
- escape_essid(bss->ssid, bss->ssid_len),
+ print_ssid(ssid, bss->ssid, bss->ssid_len),
bss->ssid_len);
/* check if the requested SSID is already joined */
@@ -226,8 +230,8 @@ static int lbs_adhoc_join(struct lbs_private *priv,
bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
- lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
- print_mac(mac, cmd.bss.bssid), cmd.bss.ssid);
+ lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
+ cmd.bss.bssid, cmd.bss.ssid);
/* Only v8 and below support setting these */
if (priv->fwrelease < 0x09000000) {
@@ -307,6 +311,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
size_t ratesize = 0;
u16 tmpcap = 0;
int ret = 0;
+ DECLARE_SSID_BUF(ssid);
lbs_deb_enter(LBS_DEB_ASSOC);
@@ -326,7 +331,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
- escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+ print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
cmd.bsstype = CMD_BSS_TYPE_IBSS;
@@ -338,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv,
WARN_ON(!assoc_req->channel);
/* set Physical parameter set */
- cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
+ cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
cmd.phyparamset.dsparamset.len = 1;
cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
/* set IBSS parameter set */
- cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
+ cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
cmd.ssparamset.ibssparamset.len = 2;
cmd.ssparamset.ibssparamset.atimwindow = 0;
@@ -427,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
{
if (!secinfo->wep_enabled && !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
- && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+ && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
+ && match_bss->rsn_ie[0] != WLAN_EID_RSN
&& !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
else
@@ -450,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
if (!secinfo->wep_enabled && secinfo->WPAenabled
- && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+ && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
&& (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
)
@@ -463,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
struct bss_descriptor *match_bss)
{
if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
- (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+ (match_bss->rsn_ie[0] == WLAN_EID_RSN)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
(match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
)
@@ -477,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
{
if (!secinfo->wep_enabled && !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
- && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+ && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
+ && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
&& (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
return 1;
else
@@ -694,6 +699,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
int ret = 0;
struct bss_descriptor * bss;
int channel = -1;
+ DECLARE_SSID_BUF(ssid);
lbs_deb_enter(LBS_DEB_ASSOC);
@@ -705,7 +711,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
channel = assoc_req->channel;
lbs_deb_assoc("SSID '%s' requested\n",
- escape_essid(assoc_req->ssid, assoc_req->ssid_len));
+ print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
if (assoc_req->mode == IW_MODE_INFRA) {
lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
assoc_req->ssid_len);
@@ -752,17 +758,15 @@ static int assoc_helper_bssid(struct lbs_private *priv,
{
int ret = 0;
struct bss_descriptor * bss;
- DECLARE_MAC_BUF(mac);
- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
- print_mac(mac, assoc_req->bssid));
+ lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
/* Search for index position in list for requested MAC */
bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
assoc_req->mode);
if (bss == NULL) {
- lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
- "cannot associate.\n", print_mac(mac, assoc_req->bssid));
+ lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
+ "cannot associate.\n", assoc_req->bssid);
goto out;
}
@@ -1208,7 +1212,7 @@ void lbs_association_worker(struct work_struct *work)
struct assoc_request * assoc_req = NULL;
int ret = 0;
int find_any_ssid = 0;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
lbs_deb_enter(LBS_DEB_ASSOC);
@@ -1228,13 +1232,13 @@ void lbs_association_worker(struct work_struct *work)
" chann: %d\n"
" band: %d\n"
" mode: %d\n"
- " BSSID: %s\n"
+ " BSSID: %pM\n"
" secinfo: %s%s%s\n"
" auth_mode: %d\n",
assoc_req->flags,
- escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+ print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
assoc_req->channel, assoc_req->band, assoc_req->mode,
- print_mac(mac, assoc_req->bssid),
+ assoc_req->bssid,
assoc_req->secinfo.WPAenabled ? " WPA" : "",
assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
assoc_req->secinfo.wep_enabled ? " WEP" : "",
@@ -1357,8 +1361,8 @@ void lbs_association_worker(struct work_struct *work)
}
if (success) {
- lbs_deb_assoc("associated to %s\n",
- print_mac(mac, priv->curbssparams.bssid));
+ lbs_deb_assoc("associated to %pM\n",
+ priv->curbssparams.bssid);
lbs_prepare_and_send_command(priv,
CMD_802_11_RSSI,
0, CMD_OPTION_WAITFORRSP, 0, NULL);
@@ -1478,7 +1482,6 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv,
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
int ret = -1;
u8 *bssid = pdata_buf;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -1505,8 +1508,8 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv,
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bssid), pauthenticate->authtype);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+ bssid, pauthenticate->authtype);
ret = 0;
out:
@@ -1770,7 +1773,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
union iwreq_data wrqu;
struct bss_descriptor *bss;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -1819,9 +1822,9 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
- lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n",
- escape_essid(bss->ssid, bss->ssid_len),
- print_mac(mac, priv->curbssparams.bssid),
+ lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
+ print_ssid(ssid, bss->ssid, bss->ssid_len),
+ priv->curbssparams.bssid,
priv->curbssparams.channel);
done:
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 8265c7d25ed..639dd02d3d3 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -4,7 +4,7 @@
*/
#include <net/iw_handler.h>
-#include <net/ieee80211.h>
+#include <net/lib80211.h>
#include <linux/kfifo.h>
#include "host.h"
#include "hostcmd.h"
@@ -87,7 +87,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
struct cmd_ds_get_hw_spec cmd;
int ret = -1;
u32 i;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_CMD);
@@ -110,8 +109,8 @@ int lbs_update_hw_spec(struct lbs_private *priv)
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
- print_mac(mac, cmd.permanentaddr),
+ lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
priv->fwrelease >> 8 & 0xff,
@@ -160,7 +159,8 @@ out:
return ret;
}
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+ struct wol_config *p_wol_config)
{
struct cmd_ds_host_sleep cmd_config;
int ret;
@@ -170,10 +170,21 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
cmd_config.gpio = priv->wol_gpio;
cmd_config.gap = priv->wol_gap;
+ if (p_wol_config != NULL)
+ memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
+ sizeof(struct wol_config));
+ else
+ cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
+
ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
if (!ret) {
- lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
- priv->wol_criteria = criteria;
+ if (criteria) {
+ lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
+ priv->wol_criteria = criteria;
+ } else
+ memcpy((uint8_t *) p_wol_config,
+ (uint8_t *)&cmd_config.wol_conf,
+ sizeof(struct wol_config));
} else {
lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
}
@@ -1063,6 +1074,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_meshie *ie;
+ DECLARE_SSID_BUF(ssid);
memset(&cmd, 0, sizeof(cmd));
cmd.channel = cpu_to_le16(chan);
@@ -1070,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
switch (action) {
case CMD_ACT_MESH_CONFIG_START:
- ie->hdr.id = MFIE_TYPE_GENERIC;
+ ie->id = WLAN_EID_GENERIC;
ie->val.oui[0] = 0x00;
ie->val.oui[1] = 0x50;
ie->val.oui[2] = 0x43;
@@ -1082,7 +1094,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
- ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+ ie->len = sizeof(struct mrvl_meshie_val) -
IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
@@ -1093,7 +1105,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
}
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
action, priv->mesh_tlv, chan,
- escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
+ print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 36be4c9703e..392e578ca09 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -56,7 +56,8 @@ int lbs_mesh_config_send(struct lbs_private *priv,
uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
-int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
+ struct wol_config *p_wol_config);
int lbs_suspend(struct lbs_private *priv);
void lbs_resume(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 0aa0ce3b2c4..ec4efd7ff3c 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -5,6 +5,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <net/iw_handler.h>
+#include <net/lib80211.h>
#include "dev.h"
#include "decl.h"
@@ -65,7 +66,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
int numscansdone = 0, res;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
struct bss_descriptor * iter_bss;
pos += snprintf(buf+pos, len-pos,
@@ -77,17 +78,17 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
- pos += snprintf(buf+pos, len-pos,
- "%02u| %03d | %04d | %s |",
+ pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |",
numscansdone, iter_bss->channel, iter_bss->rssi,
- print_mac(mac, iter_bss->bssid));
+ iter_bss->bssid);
pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
pos += snprintf(buf+pos, len-pos, "%c%c%c |",
ibss ? 'A' : 'I', privacy ? 'P' : ' ',
spectrum_mgmt ? 'S' : ' ');
pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
pos += snprintf(buf+pos, len-pos, " %s\n",
- escape_essid(iter_bss->ssid, iter_bss->ssid_len));
+ print_ssid(ssid, iter_bss->ssid,
+ iter_bss->ssid_len));
numscansdone++;
}
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 1a8888ccead..0b84bdca072 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -74,8 +74,4 @@ void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv);
-#ifndef CONFIG_IEEE80211
-const char *escape_essid(const char *essid, u8 essid_len);
-#endif
-
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 076a636e8f6..c364e4c01d1 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -79,7 +79,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
@@ -149,6 +149,18 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define EHS_WAKE_ON_MAC_EVENT 0x0004
#define EHS_WAKE_ON_MULTICAST_DATA 0x0008
#define EHS_REMOVE_WAKEUP 0xFFFFFFFF
+/* Wake rules for Host_Sleep_CFG command */
+#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS 0x00
+#define WOL_RULE_NET_TYPE_MESH 0x10
+#define WOL_RULE_ADDR_TYPE_BCAST 0x01
+#define WOL_RULE_ADDR_TYPE_MCAST 0x08
+#define WOL_RULE_ADDR_TYPE_UCAST 0x02
+#define WOL_RULE_OP_AND 0x01
+#define WOL_RULE_OP_OR 0x02
+#define WOL_RULE_OP_INVALID 0xFF
+#define WOL_RESULT_VALID_CMD 0
+#define WOL_RESULT_NOSPC_ERR 1
+#define WOL_RESULT_EEXIST_ERR 2
/** Misc constants */
/* This section defines 802.11 specific contants */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f6f3753da30..dd682c4cfde 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -10,7 +10,6 @@
#include <linux/wireless.h>
#include <linux/ethtool.h>
#include <linux/debugfs.h>
-#include <net/ieee80211.h>
#include "defs.h"
#include "hostcmd.h"
@@ -278,6 +277,12 @@ struct lbs_private {
struct enc_key wpa_mcast_key;
struct enc_key wpa_unicast_key;
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 688d60de55c..61d2f50470c 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -23,7 +23,7 @@ static const char * mesh_stat_strings[]= {
static void lbs_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
priv->fwrelease >> 24 & 0xff,
@@ -47,7 +47,7 @@ static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
static int lbs_ethtool_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 * bytes)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct cmd_ds_802_11_eeprom_access cmd;
int ret;
@@ -76,7 +76,7 @@ out:
static void lbs_ethtool_get_stats(struct net_device *dev,
struct ethtool_stats *stats, uint64_t *data)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct cmd_ds_mesh_access mesh_access;
int ret;
@@ -113,7 +113,7 @@ static void lbs_ethtool_get_stats(struct net_device *dev,
static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
return MESH_STATS_NUM;
@@ -143,7 +143,7 @@ static void lbs_ethtool_get_strings(struct net_device *dev,
static void lbs_ethtool_get_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
if (priv->wol_criteria == 0xffffffff) {
/* Interface driver didn't configure wake */
@@ -166,7 +166,7 @@ static void lbs_ethtool_get_wol(struct net_device *dev,
static int lbs_ethtool_set_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
uint32_t criteria = 0;
if (priv->wol_criteria == 0xffffffff && wol->wolopts)
@@ -180,7 +180,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev,
if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA;
if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT;
- return lbs_host_sleep_cfg(priv, criteria);
+ return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
}
struct ethtool_ops lbs_ethtool_ops = {
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 5004d7679c0..277ff1975bd 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -220,6 +220,14 @@ enum cmd_fwt_access_opts {
CMD_ACT_FWT_ACCESS_TIME,
};
+/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */
+enum cmd_wol_cfg_opts {
+ CMD_ACT_ACTION_NONE = 0,
+ CMD_ACT_SET_WOL_RULE,
+ CMD_ACT_GET_WOL_RULE,
+ CMD_ACT_RESET_WOL_RULE,
+};
+
/* Define action or option for CMD_MESH_ACCESS */
enum cmd_mesh_access_opts {
CMD_ACT_MESH_GET_TTL = 1,
@@ -237,6 +245,7 @@ enum cmd_mesh_access_opts {
CMD_ACT_MESH_GET_ROUTE_EXP,
CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+ CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17,
};
/* Define actions and types for CMD_MESH_CONFIG */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index d9f9a12a739..e173b1b46c2 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -580,13 +580,37 @@ struct MrvlIEtype_keyParamSet {
u8 key[32];
};
+#define MAX_WOL_RULES 16
+
+struct host_wol_rule {
+ uint8_t rule_no;
+ uint8_t rule_ops;
+ __le16 sig_offset;
+ __le16 sig_length;
+ __le16 reserve;
+ __be32 sig_mask;
+ __be32 signature;
+};
+
+struct wol_config {
+ uint8_t action;
+ uint8_t pattern;
+ uint8_t no_rules_in_cmd;
+ uint8_t result;
+ struct host_wol_rule rule[MAX_WOL_RULES];
+};
+
+
struct cmd_ds_host_sleep {
struct cmd_header hdr;
__le32 criteria;
uint8_t gpio;
- uint8_t gap;
+ uint16_t gap;
+ struct wol_config wol_conf;
} __attribute__ ((packed));
+
+
struct cmd_ds_802_11_key_material {
struct cmd_header hdr;
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index b54e2ea8346..4519d7314f4 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -26,6 +26,7 @@
* if_sdio_card_to_host() to pad the data.
*/
+#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/netdevice.h>
@@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
chunk_size, (chunk_size + 31) / 32 * 32);
*/
ret = sdio_writesb(card->func, card->ioport,
- chunk_buffer, (chunk_size + 31) / 32 * 32);
+ chunk_buffer, roundup(chunk_size, 32));
if (ret)
goto release;
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index cafbccb7414..2fc637ad85c 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -59,7 +59,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
static ssize_t if_usb_firmware_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct if_usb_card *cardp = priv->card;
char fwname[FIRMWARE_NAME_MAX];
int ret;
@@ -86,7 +86,7 @@ static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
static ssize_t if_usb_boot2_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct if_usb_card *cardp = priv->card;
char fwname[FIRMWARE_NAME_MAX];
int ret;
@@ -178,7 +178,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
priv->wol_gpio = 2; /* Wake via GPIO2... */
priv->wol_gap = 20; /* ... after 20ms */
- lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
+ lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA,
+ (struct wol_config *) NULL);
wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
wake_method.action = cpu_to_le16(CMD_ACT_GET);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 73dc8c72402..3dba8367944 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -12,9 +12,8 @@
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include <linux/stddef.h>
-
+#include <linux/ieee80211.h>
#include <net/iw_handler.h>
-#include <net/ieee80211.h>
#include "host.h"
#include "decl.h"
@@ -223,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
static ssize_t lbs_anycast_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_access mesh_access;
int ret;
@@ -242,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev,
static ssize_t lbs_anycast_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_access mesh_access;
uint32_t datum;
int ret;
@@ -258,6 +257,58 @@ static ssize_t lbs_anycast_set(struct device *dev,
return strlen(buf);
}
+/**
+ * @brief Get function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+ u32 retry_limit;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+ &mesh_access);
+ if (ret)
+ return ret;
+
+ retry_limit = le32_to_cpu(mesh_access.data[1]);
+ return snprintf(buf, 10, "%d\n", retry_limit);
+}
+
+/**
+ * @brief Set function for sysfs attribute prb_rsp_limit
+ */
+static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+ unsigned long retry_limit;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
+
+ if (!strict_strtoul(buf, 10, &retry_limit))
+ return -ENOTSUPP;
+ if (retry_limit > 15)
+ return -ENOTSUPP;
+
+ mesh_access.data[1] = cpu_to_le32(retry_limit);
+
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
+ &mesh_access);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
static int lbs_add_rtap(struct lbs_private *priv);
static void lbs_remove_rtap(struct lbs_private *priv);
static int lbs_add_mesh(struct lbs_private *priv);
@@ -270,7 +321,7 @@ static void lbs_remove_mesh(struct lbs_private *priv);
static ssize_t lbs_rtap_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
return snprintf(buf, 5, "0x%X\n", priv->monitormode);
}
@@ -281,7 +332,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
int monitor_mode;
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
sscanf(buf, "%x", &monitor_mode);
if (monitor_mode) {
@@ -332,7 +383,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
static ssize_t lbs_mesh_get(struct device *dev,
struct device_attribute *attr, char * buf)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
}
@@ -342,7 +393,7 @@ static ssize_t lbs_mesh_get(struct device *dev,
static ssize_t lbs_mesh_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
int enable;
int ret, action = CMD_ACT_MESH_CONFIG_STOP;
@@ -376,8 +427,16 @@ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
*/
static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
+/**
+ * prb_rsp_limit attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
+ */
+static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
+ lbs_prb_rsp_limit_set);
+
static struct attribute *lbs_mesh_sysfs_entries[] = {
&dev_attr_anycast_mask.attr,
+ &dev_attr_prb_rsp_limit.attr,
NULL,
};
@@ -393,7 +452,7 @@ static struct attribute_group lbs_mesh_attr_group = {
*/
static int lbs_dev_open(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+ struct lbs_private *priv = netdev_priv(dev) ;
int ret = 0;
lbs_deb_enter(LBS_DEB_NET);
@@ -435,7 +494,7 @@ static int lbs_dev_open(struct net_device *dev)
*/
static int lbs_mesh_stop(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+ struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_MESH);
spin_lock_irq(&priv->driver_lock);
@@ -462,7 +521,7 @@ static int lbs_mesh_stop(struct net_device *dev)
*/
static int lbs_eth_stop(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_NET);
@@ -479,7 +538,7 @@ static int lbs_eth_stop(struct net_device *dev)
static void lbs_tx_timeout(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_TX);
@@ -531,7 +590,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
*/
static struct net_device_stats *lbs_get_stats(struct net_device *dev)
{
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_NET);
return &priv->stats;
@@ -540,7 +599,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev)
static int lbs_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
- struct lbs_private *priv = (struct lbs_private *) dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct sockaddr *phwaddr = addr;
struct cmd_ds_802_11_mac_address cmd;
@@ -588,7 +647,6 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
{
int i = nr_addrs;
struct dev_mc_list *mc_list;
- DECLARE_MAC_BUF(mac);
if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
return nr_addrs;
@@ -596,16 +654,16 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
netif_addr_lock_bh(dev);
for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
- lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
- print_mac(mac, mc_list->dmi_addr));
+ lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
+ mc_list->dmi_addr);
continue;
}
if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
break;
memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
- lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
- print_mac(mac, mc_list->dmi_addr));
+ lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
+ mc_list->dmi_addr);
i++;
}
netif_addr_unlock_bh(dev);
@@ -674,7 +732,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
static void lbs_set_multicast_list(struct net_device *dev)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
schedule_work(&priv->mcast_work);
}
@@ -690,7 +748,7 @@ static void lbs_set_multicast_list(struct net_device *dev)
static int lbs_thread(void *data)
{
struct net_device *dev = data;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
wait_queue_t wait;
lbs_deb_enter(LBS_DEB_THREAD);
@@ -1125,7 +1183,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
lbs_pr_err("init ethX device failed\n");
goto done;
}
- priv = dev->priv;
+ priv = netdev_priv(dev);
if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
@@ -1378,7 +1436,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
ret = -ENOMEM;
goto done;
}
- mesh_dev->priv = priv;
+ mesh_dev->ml_priv = priv;
priv->mesh_dev = mesh_dev;
mesh_dev->open = lbs_dev_open;
@@ -1591,7 +1649,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = dev->ml_priv;
lbs_deb_enter(LBS_DEB_NET);
return &priv->stats;
}
@@ -1632,7 +1690,7 @@ static int lbs_add_rtap(struct lbs_private *priv)
rtap_dev->stop = lbs_rtap_stop;
rtap_dev->get_stats = lbs_rtap_get_stats;
rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
- rtap_dev->priv = priv;
+ rtap_dev->ml_priv = priv;
SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
ret = register_netdev(rtap_dev);
@@ -1647,33 +1705,6 @@ out:
return ret;
}
-#ifndef CONFIG_IEEE80211
-const char *escape_essid(const char *essid, u8 essid_len)
-{
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
- const char *s = essid;
- char *d = escaped;
-
- if (ieee80211_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
- while (essid_len--) {
- if (*s == '\0') {
- *d++ = '\\';
- *d++ = '0';
- s++;
- } else {
- *d++ = *s++;
- }
- }
- *d = '\0';
- return escaped;
-}
-#endif
-
module_init(lbs_init_module);
module_exit(lbs_exit_module);
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
index 3309a9c3cfe..d42b7a5a1b3 100644
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -18,7 +18,7 @@
static int mesh_get_default_parameters(struct device *dev,
struct mrvl_mesh_defaults *defs)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_config cmd;
int ret;
@@ -57,7 +57,7 @@ static ssize_t bootflag_get(struct device *dev,
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
@@ -100,7 +100,7 @@ static ssize_t boottime_get(struct device *dev,
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
@@ -152,7 +152,7 @@ static ssize_t channel_get(struct device *dev,
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
@@ -210,7 +210,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
int len;
int ret;
@@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
- ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+ ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
@@ -269,7 +269,7 @@ static ssize_t protocol_id_set(struct device *dev,
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
uint32_t datum;
int ret;
@@ -323,7 +323,7 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
uint32_t datum;
int ret;
@@ -377,7 +377,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
- struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct lbs_private *priv = netdev_priv(to_net_dev(dev));
uint32_t datum;
int ret;
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
index 5d118f40cfb..f8eb9097ff0 100644
--- a/drivers/net/wireless/libertas/radiotap.h
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -6,9 +6,6 @@ struct tx_radiotap_hdr {
u8 txpower;
u8 rts_retries;
u8 data_retries;
-#if 0
- u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
-#endif
} __attribute__ ((packed));
#define TX_RADIOTAP_PRESENT ( \
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 22c4c611052..57f6c12cda2 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -4,8 +4,11 @@
* IOCTL handlers as well as command preperation and response routines
* for sending scan commands to the firmware.
*/
+#include <linux/types.h>
#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
#include <asm/unaligned.h>
+#include <net/lib80211.h>
#include "host.h"
#include "decl.h"
@@ -52,6 +55,8 @@
//! Scan time specified in the channel TLV for each channel for active scans
#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+
static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
struct cmd_header *resp);
@@ -359,7 +364,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan)
#ifdef CONFIG_LIBERTAS_DEBUG
struct bss_descriptor *iter;
int i = 0;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
#endif
lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
@@ -451,9 +456,9 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan)
mutex_lock(&priv->lock);
lbs_deb_scan("scan table:\n");
list_for_each_entry(iter, &priv->network_list, list)
- lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
- i++, print_mac(mac, iter->bssid), iter->rssi,
- escape_essid(iter->ssid, iter->ssid_len));
+ lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
+ i++, iter->bssid, iter->rssi,
+ print_ssid(ssid, iter->ssid, iter->ssid_len));
mutex_unlock(&priv->lock);
#endif
@@ -512,7 +517,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
struct ieeetypes_dsparamset *pDS;
struct ieeetypes_cfparamset *pCF;
struct ieeetypes_ibssparamset *pibss;
- DECLARE_MAC_BUF(mac);
+ DECLARE_SSID_BUF(ssid);
struct ieeetypes_countryinfoset *pcountryinfo;
uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
@@ -544,7 +549,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
*bytesleft -= beaconsize;
memcpy(bss->bssid, pos, ETH_ALEN);
- lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
+ lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
pos += ETH_ALEN;
if ((end - pos) < 12) {
@@ -588,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss,
/* process variable IE */
while (pos <= end - 2) {
- struct ieee80211_info_element * elem = (void *)pos;
-
- if (pos + elem->len > end) {
+ if (pos + pos[1] > end) {
lbs_deb_scan("process_bss: error in processing IE, "
"bytes left < IE length\n");
break;
}
- switch (elem->id) {
- case MFIE_TYPE_SSID:
- bss->ssid_len = min_t(int, 32, elem->len);
- memcpy(bss->ssid, elem->data, bss->ssid_len);
+ switch (pos[0]) {
+ case WLAN_EID_SSID:
+ bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
+ memcpy(bss->ssid, pos + 2, bss->ssid_len);
lbs_deb_scan("got SSID IE: '%s', len %u\n",
- escape_essid(bss->ssid, bss->ssid_len),
+ print_ssid(ssid, bss->ssid, bss->ssid_len),
bss->ssid_len);
break;
- case MFIE_TYPE_RATES:
- n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len);
- memcpy(bss->rates, elem->data, n_basic_rates);
+ case WLAN_EID_SUPP_RATES:
+ n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
+ memcpy(bss->rates, pos + 2, n_basic_rates);
got_basic_rates = 1;
lbs_deb_scan("got RATES IE\n");
break;
- case MFIE_TYPE_FH_SET:
+ case WLAN_EID_FH_PARAMS:
pFH = (struct ieeetypes_fhparamset *) pos;
memmove(&bss->phyparamset.fhparamset, pFH,
sizeof(struct ieeetypes_fhparamset));
lbs_deb_scan("got FH IE\n");
break;
- case MFIE_TYPE_DS_SET:
+ case WLAN_EID_DS_PARAMS:
pDS = (struct ieeetypes_dsparamset *) pos;
bss->channel = pDS->currentchan;
memcpy(&bss->phyparamset.dsparamset, pDS,
@@ -627,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
break;
- case MFIE_TYPE_CF_SET:
+ case WLAN_EID_CF_PARAMS:
pCF = (struct ieeetypes_cfparamset *) pos;
memcpy(&bss->ssparamset.cfparamset, pCF,
sizeof(struct ieeetypes_cfparamset));
lbs_deb_scan("got CF IE\n");
break;
- case MFIE_TYPE_IBSS_SET:
+ case WLAN_EID_IBSS_PARAMS:
pibss = (struct ieeetypes_ibssparamset *) pos;
bss->atimwindow = le16_to_cpu(pibss->atimwindow);
memmove(&bss->ssparamset.ibssparamset, pibss,
@@ -642,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got IBSS IE\n");
break;
- case MFIE_TYPE_COUNTRY:
+ case WLAN_EID_COUNTRY:
pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
lbs_deb_scan("got COUNTRY IE\n");
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
@@ -659,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
(int) (pcountryinfo->len + 2));
break;
- case MFIE_TYPE_RATES_EX:
+ case WLAN_EID_EXT_SUPP_RATES:
/* only process extended supported rate if data rate is
* already found. Data rate IE should come before
* extended supported rate IE
@@ -670,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss,
break;
}
- n_ex_rates = elem->len;
+ n_ex_rates = pos[1];
if (n_basic_rates + n_ex_rates > MAX_RATES)
n_ex_rates = MAX_RATES - n_basic_rates;
p = bss->rates + n_basic_rates;
- memcpy(p, elem->data, n_ex_rates);
+ memcpy(p, pos + 2, n_ex_rates);
break;
- case MFIE_TYPE_GENERIC:
- if (elem->len >= 4 &&
- elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
- elem->data[2] == 0xf2 && elem->data[3] == 0x01) {
- bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
- memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+ case WLAN_EID_GENERIC:
+ if (pos[1] >= 4 &&
+ pos[2] == 0x00 && pos[3] == 0x50 &&
+ pos[4] == 0xf2 && pos[5] == 0x01) {
+ bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+ memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
lbs_deb_scan("got WPA IE\n");
- lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len);
- } else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
- elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
- elem->data[2] == 0x43 && elem->data[3] == 0x04) {
+ lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
+ bss->wpa_ie_len);
+ } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
+ pos[2] == 0x00 && pos[3] == 0x50 &&
+ pos[4] == 0x43 && pos[4] == 0x04) {
lbs_deb_scan("got mesh IE\n");
bss->mesh = 1;
} else {
lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
- elem->data[0], elem->data[1],
- elem->data[2], elem->data[3],
- elem->len);
+ pos[2], pos[3],
+ pos[4], pos[5],
+ pos[1]);
}
break;
- case MFIE_TYPE_RSN:
+ case WLAN_EID_RSN:
lbs_deb_scan("got RSN IE\n");
- bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
- memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+ bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+ memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
- bss->rsn_ie, elem->len);
+ bss->rsn_ie, bss->rsn_ie_len);
break;
default:
lbs_deb_scan("got IE 0x%04x, len %d\n",
- elem->id, elem->len);
+ pos[0], pos[1]);
break;
}
- pos += elem->len + 2;
+ pos += pos[1] + 2;
}
/* Timestamp */
@@ -741,10 +745,11 @@ done:
int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
uint8_t ssid_len)
{
+ DECLARE_SSID_BUF(ssid_buf);
int ret = 0;
lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
- escape_essid(ssid, ssid_len));
+ print_ssid(ssid_buf, ssid, ssid_len));
if (!ssid_len)
goto out;
@@ -939,7 +944,8 @@ out:
int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ DECLARE_SSID_BUF(ssid);
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -968,7 +974,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
priv->scan_ssid_len = req->essid_len;
memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
lbs_deb_wext("set_scan, essid '%s'\n",
- escape_essid(priv->scan_ssid, priv->scan_ssid_len));
+ print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
} else {
priv->scan_ssid_len = 0;
}
@@ -1002,7 +1008,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
#define SCAN_ITEM_SIZE 128
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int err = 0;
char *ev = extra;
char *stop = ev + dwrq->length;
@@ -1151,7 +1157,6 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
struct bss_descriptor new;
struct bss_descriptor *found = NULL;
struct bss_descriptor *oldest = NULL;
- DECLARE_MAC_BUF(mac);
/* Process the data fields and IEs returned for this BSS */
memset(&new, 0, sizeof (struct bss_descriptor));
@@ -1190,7 +1195,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
continue;
}
- lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid));
+ lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
/* Copy the locally created newbssentry to the scan table */
memcpy(found, &new, offsetof(struct bss_descriptor, list));
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index 9e07b0464a8..fab7d5d097f 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -7,6 +7,10 @@
#ifndef _LBS_SCAN_H
#define _LBS_SCAN_H
+#include <net/iw_handler.h>
+
+#define MAX_NETWORK_COUNT 128
+
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
*/
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index a4972fed294..dac46264117 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -60,7 +60,7 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct txpd *txpd;
char *p802x_hdr;
uint16_t pkt_len;
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index e0c2599da92..fb7a2d1a252 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -7,7 +7,6 @@
#include <linux/if_ether.h>
#include <asm/byteorder.h>
#include <linux/wireless.h>
-#include <net/ieee80211.h>
struct ieeetypes_cfparamset {
u8 elementid;
@@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv {
* Note that the len member of the ieee80211_info_element varies depending on
* the mesh_id_len */
struct mrvl_meshie_val {
- uint8_t oui[P80211_OUI_LEN];
+ uint8_t oui[3];
uint8_t type;
uint8_t subtype;
uint8_t version;
@@ -270,7 +269,7 @@ struct mrvl_meshie_val {
} __attribute__ ((packed));
struct mrvl_meshie {
- struct ieee80211_info_element hdr;
+ u8 id, len;
struct mrvl_meshie_val val;
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 82c3e5a50ea..c6102e08179 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -8,7 +8,7 @@
#include <linux/wireless.h>
#include <linux/bitops.h>
-#include <net/ieee80211.h>
+#include <net/lib80211.h>
#include <net/iw_handler.h>
#include "host.h"
@@ -163,7 +163,7 @@ static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct chan_freq_power *cfp;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -189,7 +189,7 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -207,7 +207,7 @@ static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -231,7 +231,7 @@ static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -248,7 +248,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -273,7 +273,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
u32 val = vwrq->value;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -293,7 +293,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u16 val = 0;
@@ -315,7 +315,7 @@ out:
static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u32 val = vwrq->value;
@@ -336,7 +336,7 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u16 val = 0;
@@ -359,7 +359,7 @@ out:
static int lbs_get_mode(struct net_device *dev,
struct iw_request_info *info, u32 * uwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -385,7 +385,7 @@ static int lbs_get_txpow(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
s16 curlevel = 0;
int ret = 0;
@@ -418,7 +418,7 @@ out:
static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u16 slimit = 0, llimit = 0;
@@ -466,7 +466,7 @@ out:
static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u16 val = 0;
@@ -542,7 +542,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
int i, j;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct iw_range *range = (struct iw_range *)extra;
struct chan_freq_power *cfp;
u8 rates[MAX_RATES + 1];
@@ -708,7 +708,7 @@ out:
static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -758,7 +758,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -781,7 +781,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
EXCELLENT = 95,
PERFECT = 100
};
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
u32 rssi_qual;
u32 tx_qual;
u32 quality = 0;
@@ -886,7 +886,7 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
int ret = -EINVAL;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct chan_freq_power *cfp;
struct assoc_request * assoc_req;
@@ -943,7 +943,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct chan_freq_power *cfp;
int ret = -EINVAL;
@@ -994,7 +994,7 @@ out:
static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
u8 new_rate = 0;
int ret = -EINVAL;
u8 rates[MAX_RATES + 1];
@@ -1054,7 +1054,7 @@ out:
static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1079,7 +1079,7 @@ static int lbs_set_mode(struct net_device *dev,
struct iw_request_info *info, u32 * uwrq, char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct assoc_request * assoc_req;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1124,7 +1124,7 @@ static int lbs_get_encode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq, u8 * extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1319,7 +1319,7 @@ static int lbs_set_encode(struct net_device *dev,
struct iw_point *dwrq, char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct assoc_request * assoc_req;
u16 is_default = 0, index = 0, set_tx_key = 0;
@@ -1395,7 +1395,7 @@ static int lbs_get_encodeext(struct net_device *dev,
char *extra)
{
int ret = -EINVAL;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int index, max_key_len;
@@ -1501,7 +1501,7 @@ static int lbs_set_encodeext(struct net_device *dev,
char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int alg = ext->alg;
struct assoc_request * assoc_req;
@@ -1639,7 +1639,7 @@ static int lbs_set_genie(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
struct assoc_request * assoc_req;
@@ -1685,7 +1685,7 @@ static int lbs_get_genie(struct net_device *dev,
char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1713,7 +1713,7 @@ static int lbs_set_auth(struct net_device *dev,
struct iw_param *dwrq,
char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct assoc_request * assoc_req;
int ret = 0;
int updated = 0;
@@ -1816,7 +1816,7 @@ static int lbs_get_auth(struct net_device *dev,
char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1857,7 +1857,7 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
int ret = 0;
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
s16 dbm = (s16) vwrq->value;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1936,7 +1936,7 @@ out:
static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1971,12 +1971,13 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
u8 ssid[IW_ESSID_MAX_SIZE];
u8 ssid_len = 0;
struct assoc_request * assoc_req;
int in_ssid_len = dwrq->length;
+ DECLARE_SSID_BUF(ssid_buf);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -2005,7 +2006,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_wext("requested any SSID\n");
} else {
lbs_deb_wext("requested SSID '%s'\n",
- escape_essid(ssid, ssid_len));
+ print_ssid(ssid_buf, ssid, ssid_len));
}
out:
@@ -2039,7 +2040,7 @@ static int lbs_mesh_get_essid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -2057,7 +2058,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -2101,10 +2102,9 @@ static int lbs_mesh_set_essid(struct net_device *dev,
static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
- struct lbs_private *priv = dev->priv;
+ struct lbs_private *priv = netdev_priv(dev);
struct assoc_request * assoc_req;
int ret = 0;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_WEXT);
@@ -2114,7 +2114,7 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;
- lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
+ lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);
mutex_lock(&priv->lock);
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
index fdbcf8ba3e8..3d3914c83b1 100644
--- a/drivers/net/wireless/libertas_tf/cmd.c
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -79,7 +79,6 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
struct cmd_ds_get_hw_spec cmd;
int ret = -1;
u32 i;
- DECLARE_MAC_BUF(mac);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
@@ -96,8 +95,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
priv->fwrelease = (priv->fwrelease << 8) |
(priv->fwrelease >> 24 & 0xff);
- printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n",
- print_mac(mac, cmd.permanentaddr),
+ printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
priv->fwrelease >> 8 & 0xff,
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index feff945ad85..d1fc305de5f 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -354,9 +354,11 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
priv->vif = NULL;
}
-static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct lbtf_private *priv = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+
if (conf->channel->center_freq != priv->cur_freq) {
priv->cur_freq = conf->channel->center_freq;
lbtf_set_channel(priv, conf->channel->hw_value);
@@ -590,14 +592,14 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card);
void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
- memset(&info->status, 0, sizeof(info->status));
+
+ ieee80211_tx_info_clear_status(info);
/*
* Commented out, otherwise we never go beyond 1Mbit/s using mac80211
* default pid rc algorithm.
*
* info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
*/
- info->status.excessive_retries = fail ? 1 : 0;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
info->flags |= IEEE80211_TX_STAT_ACK;
skb_pull(priv->tx_skb, sizeof(struct txpd));
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 1a019e98dac..f83d69e813d 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -21,6 +21,7 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
@@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios");
struct hwsim_vif_priv {
u32 magic;
+ u8 bssid[ETH_ALEN];
+ bool assoc;
+ u16 aid;
};
#define HWSIM_VIF_MAGIC 0x69537748
@@ -63,13 +67,13 @@ struct hwsim_sta_priv {
static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
{
struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
- WARN_ON(sp->magic != HWSIM_VIF_MAGIC);
+ WARN_ON(sp->magic != HWSIM_STA_MAGIC);
}
static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta)
{
struct hwsim_sta_priv *sp = (void *)sta->drv_priv;
- sp->magic = HWSIM_VIF_MAGIC;
+ sp->magic = HWSIM_STA_MAGIC;
}
static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
@@ -132,6 +136,12 @@ struct mac80211_hwsim_data {
unsigned int rx_filter;
int started;
struct timer_list beacon_timer;
+ enum ps_mode {
+ PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
+ } ps;
+ bool ps_poll_pending;
+ struct dentry *debugfs;
+ struct dentry *debugfs_ps;
};
@@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
}
+static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
+ struct sk_buff *skb)
+{
+ switch (data->ps) {
+ case PS_DISABLED:
+ return true;
+ case PS_ENABLED:
+ return false;
+ case PS_AUTO_POLL:
+ /* TODO: accept (some) Beacons by default and other frames only
+ * if pending PS-Poll has been sent */
+ return true;
+ case PS_MANUAL_POLL:
+ /* Allow unicast frames to own address if there is a pending
+ * PS-Poll */
+ if (data->ps_poll_pending &&
+ memcmp(data->hw->wiphy->perm_addr, skb->data + 4,
+ ETH_ALEN) == 0) {
+ data->ps_poll_pending = false;
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
@@ -209,9 +247,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
/* TODO: set mactime */
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
- rx_status.rate_idx = info->tx_rate_idx;
+ rx_status.rate_idx = info->control.rates[0].idx;
/* TODO: simulate signal strength (and optional packet drop) */
+ if (data->ps != PS_DISABLED)
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
continue;
if (!data2->started || !data2->radio_enabled ||
+ !hwsim_ps_rx_ok(data2, skb) ||
data->channel->center_freq != data2->channel->center_freq)
continue;
@@ -269,13 +311,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (txi->control.sta)
hwsim_check_sta_magic(txi->control.sta);
- memset(&txi->status, 0, sizeof(txi->status));
- if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
- if (ack)
- txi->flags |= IEEE80211_TX_STAT_ACK;
- else
- txi->status.excessive_retries = 1;
- }
+ ieee80211_tx_info_clear_status(txi);
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
+ txi->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);
return NETDEV_TX_OK;
}
@@ -294,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;
data->started = 0;
+ del_timer(&data->beacon_timer);
printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
}
@@ -301,10 +340,9 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+ printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
- print_mac(mac, conf->mac_addr));
+ conf->mac_addr);
hwsim_set_magic(conf->vif);
return 0;
}
@@ -313,10 +351,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
static void mac80211_hwsim_remove_interface(
struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
{
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n",
+ printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
wiphy_name(hw->wiphy), __func__, conf->type,
- print_mac(mac, conf->mac_addr));
+ conf->mac_addr);
hwsim_check_magic(conf->vif);
hwsim_clear_magic(conf->vif);
}
@@ -331,7 +368,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
hwsim_check_magic(vif);
- if (vif->type != NL80211_IFTYPE_AP)
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_MESH_POINT)
return;
skb = ieee80211_beacon_get(hw, vif);
@@ -361,10 +399,10 @@ static void mac80211_hwsim_beacon(unsigned long arg)
}
-static int mac80211_hwsim_config(struct ieee80211_hw *hw,
- struct ieee80211_conf *conf)
+static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
wiphy_name(hw->wiphy), __func__,
@@ -409,7 +447,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
hwsim_check_magic(vif);
+ if (conf->changed & IEEE80211_IFCC_BSSID) {
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n",
+ wiphy_name(hw->wiphy), __func__,
+ conf->bssid);
+ memcpy(vp->bssid, conf->bssid, ETH_ALEN);
+ }
return 0;
}
@@ -418,7 +465,46 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *info,
u32 changed)
{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
hwsim_check_magic(vif);
+
+ printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
+ wiphy_name(hw->wiphy), __func__, changed);
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n",
+ wiphy_name(hw->wiphy), info->assoc, info->aid);
+ vp->assoc = info->assoc;
+ vp->aid = info->aid;
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n",
+ wiphy_name(hw->wiphy), info->use_cts_prot);
+ }
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n",
+ wiphy_name(hw->wiphy), info->use_short_preamble);
+ }
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ printk(KERN_DEBUG " %s: ERP_SLOT: %d\n",
+ wiphy_name(hw->wiphy), info->use_short_slot);
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
+ wiphy_name(hw->wiphy),
+ info->ht.operation_mode);
+ }
+
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n",
+ wiphy_name(hw->wiphy),
+ (unsigned long long) info->basic_rates);
+ }
}
static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
@@ -434,6 +520,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
case STA_NOTIFY_REMOVE:
hwsim_clear_sta_magic(sta);
break;
+ case STA_NOTIFY_SLEEP:
+ case STA_NOTIFY_AWAKE:
+ /* TODO: make good use of these flags */
+ break;
}
}
@@ -445,6 +535,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
return 0;
}
+static int mac80211_hwsim_conf_tx(
+ struct ieee80211_hw *hw, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d "
+ "aifs=%d)\n",
+ wiphy_name(hw->wiphy), __func__, queue,
+ params->txop, params->cw_min, params->cw_max, params->aifs);
+ return 0;
+}
+
static const struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@@ -458,6 +559,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.bss_info_changed = mac80211_hwsim_bss_info_changed,
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
+ .conf_tx = mac80211_hwsim_conf_tx,
};
@@ -474,6 +576,8 @@ static void mac80211_hwsim_free(void)
spin_unlock_bh(&hwsim_radio_lock);
list_for_each_entry(data, &tmplist, list) {
+ debugfs_remove(data->debugfs_ps);
+ debugfs_remove(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_unregister(data->dev);
ieee80211_free_hw(data->hw);
@@ -499,13 +603,131 @@ static void hwsim_mon_setup(struct net_device *dev)
}
+static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct mac80211_hwsim_data *data = dat;
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+ DECLARE_MAC_BUF(buf);
+ struct sk_buff *skb;
+ struct ieee80211_pspoll *pspoll;
+
+ if (!vp->assoc)
+ return;
+
+ printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n",
+ wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid);
+
+ skb = dev_alloc_skb(sizeof(*pspoll));
+ if (!skb)
+ return;
+ pspoll = (void *) skb_put(skb, sizeof(*pspoll));
+ pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+ IEEE80211_STYPE_PSPOLL |
+ IEEE80211_FCTL_PM);
+ pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
+ memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
+ memcpy(pspoll->ta, mac, ETH_ALEN);
+ if (data->radio_enabled &&
+ !mac80211_hwsim_tx_frame(data->hw, skb))
+ printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
+ dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
+ struct ieee80211_vif *vif, int ps)
+{
+ struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+ DECLARE_MAC_BUF(buf);
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+
+ if (!vp->assoc)
+ return;
+
+ printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n",
+ wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps);
+
+ skb = dev_alloc_skb(sizeof(*hdr));
+ if (!skb)
+ return;
+ hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC |
+ (ps ? IEEE80211_FCTL_PM : 0));
+ hdr->duration_id = cpu_to_le16(0);
+ memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
+ memcpy(hdr->addr2, mac, ETH_ALEN);
+ memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+ if (data->radio_enabled &&
+ !mac80211_hwsim_tx_frame(data->hw, skb))
+ printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
+ dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mac80211_hwsim_data *data = dat;
+ hwsim_send_nullfunc(data, mac, vif, 1);
+}
+
+
+static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct mac80211_hwsim_data *data = dat;
+ hwsim_send_nullfunc(data, mac, vif, 0);
+}
+
+
+static int hwsim_fops_ps_read(void *dat, u64 *val)
+{
+ struct mac80211_hwsim_data *data = dat;
+ *val = data->ps;
+ return 0;
+}
+
+static int hwsim_fops_ps_write(void *dat, u64 val)
+{
+ struct mac80211_hwsim_data *data = dat;
+ enum ps_mode old_ps;
+
+ if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
+ val != PS_MANUAL_POLL)
+ return -EINVAL;
+
+ old_ps = data->ps;
+ data->ps = val;
+
+ if (val == PS_MANUAL_POLL) {
+ ieee80211_iterate_active_interfaces(data->hw,
+ hwsim_send_ps_poll, data);
+ data->ps_poll_pending = true;
+ } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+ ieee80211_iterate_active_interfaces(data->hw,
+ hwsim_send_nullfunc_ps,
+ data);
+ } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
+ ieee80211_iterate_active_interfaces(data->hw,
+ hwsim_send_nullfunc_no_ps,
+ data);
+ }
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
+ "%llu\n");
+
+
static int __init init_mac80211_hwsim(void)
{
int i, err = 0;
u8 addr[ETH_ALEN];
struct mac80211_hwsim_data *data;
struct ieee80211_hw *hw;
- DECLARE_MAC_BUF(mac);
if (radios < 1 || radios > 100)
return -EINVAL;
@@ -553,7 +775,8 @@ static int __init init_mac80211_hwsim(void)
hw->queues = 4;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
hw->ampdu_queues = 1;
/* ask mac80211 to reserve space for magic */
@@ -566,19 +789,18 @@ static int __init init_mac80211_hwsim(void)
data->band.n_channels = ARRAY_SIZE(hwsim_channels);
data->band.bitrates = data->rates;
data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
- data->band.ht_info.ht_supported = 1;
- data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH |
+ data->band.ht_cap.ht_supported = true;
+ data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
- data->band.ht_info.ampdu_factor = 0x3;
- data->band.ht_info.ampdu_density = 0x6;
- memset(data->band.ht_info.supp_mcs_set, 0,
- sizeof(data->band.ht_info.supp_mcs_set));
- data->band.ht_info.supp_mcs_set[0] = 0xff;
- data->band.ht_info.supp_mcs_set[1] = 0xff;
- data->band.ht_info.supp_mcs_set[12] =
- IEEE80211_HT_CAP_MCS_TX_DEFINED;
+ data->band.ht_cap.ampdu_factor = 0x3;
+ data->band.ht_cap.ampdu_density = 0x6;
+ memset(&data->band.ht_cap.mcs, 0,
+ sizeof(data->band.ht_cap.mcs));
+ data->band.ht_cap.mcs.rx_mask[0] = 0xff;
+ data->band.ht_cap.mcs.rx_mask[1] = 0xff;
+ data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
err = ieee80211_register_hw(hw);
@@ -588,9 +810,15 @@ static int __init init_mac80211_hwsim(void)
goto failed_hw;
}
- printk(KERN_DEBUG "%s: hwaddr %s registered\n",
+ printk(KERN_DEBUG "%s: hwaddr %pM registered\n",
wiphy_name(hw->wiphy),
- print_mac(mac, hw->wiphy->perm_addr));
+ hw->wiphy->perm_addr);
+
+ data->debugfs = debugfs_create_dir("hwsim",
+ hw->wiphy->debugfsdir);
+ data->debugfs_ps = debugfs_create_file("ps", 0666,
+ data->debugfs, data,
+ &hwsim_fops_ps);
setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
(unsigned long) hw);
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index a670f36b5f3..24caec6caf1 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -737,7 +737,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
win_req_t req;
memreq_t mem;
u_char __iomem *ramBase = NULL;
- DECLARE_MAC_BUF(mac);
DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
@@ -808,12 +807,12 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, "
- "id %c%c, hw_addr %s\n",
+ "id %c%c, hw_addr %pM\n",
dev->name, dev->base_addr, dev->irq,
(u_long) ramBase,
(int) readb(ramBase+NETWAVE_EREG_NI),
(int) readb(ramBase+NETWAVE_EREG_NI+1),
- print_mac(mac, dev->dev_addr));
+ dev->dev_addr);
/* get revision words */
printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n",
@@ -1308,7 +1307,6 @@ static int netwave_rx(struct net_device *dev)
/* Queue packet for network layer */
netif_rx(skb);
- dev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes += rcvLen;
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
new file mode 100644
index 00000000000..791366e08c5
--- /dev/null
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the orinoco wireless device drivers.
+#
+
+obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o
+obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
+obj-$(CONFIG_APPLE_AIRPORT) += airport.o
+obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
+obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
+obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/orinoco/airport.c
index ce03a2e865f..28f1cae4843 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -279,7 +279,7 @@ init_airport(void)
static void __exit
exit_airport(void)
{
- return macio_unregister_driver(&airport_driver);
+ macio_unregister_driver(&airport_driver);
}
module_init(init_airport);
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index bfa375369df..bfa375369df 100644
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 8b13c8fef3d..8b13c8fef3d 100644
--- a/drivers/net/wireless/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index d8c626e61a3..d8c626e61a3 100644
--- a/drivers/net/wireless/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h
index 6fcb2627799..6fcb2627799 100644
--- a/drivers/net/wireless/hermes_dld.h
+++ b/drivers/net/wireless/orinoco/hermes_dld.h
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h
index 42eb67dea1d..42eb67dea1d 100644
--- a/drivers/net/wireless/hermes_rid.h
+++ b/drivers/net/wireless/orinoco/hermes_rid.h
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
index e0512e49d6d..bc84e2792f8 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco/orinoco.c
@@ -84,10 +84,11 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/firmware.h>
+#include <linux/suspend.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
+#include <linux/ieee80211.h>
#include <net/iw_handler.h>
-#include <net/ieee80211.h>
#include <linux/scatterlist.h>
#include <linux/crypto.h>
@@ -143,7 +144,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
#define ORINOCO_MIN_MTU 256
-#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
+#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
#define SYMBOL_MAX_VER_LEN (14)
#define USER_BAP 0
@@ -392,7 +393,7 @@ static void orinoco_bss_data_init(struct orinoco_private *priv)
}
static inline u8 *orinoco_get_ie(u8 *data, size_t len,
- enum ieee80211_mfie eid)
+ enum ieee80211_eid eid)
{
u8 *p = data;
while ((p + 2) < (data + len)) {
@@ -409,7 +410,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
{
u8 *p = data;
while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
- if ((p[0] == MFIE_TYPE_GENERIC) &&
+ if ((p[0] == WLAN_EID_GENERIC) &&
(memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
return p;
p += p[1] + 2;
@@ -431,9 +432,9 @@ struct fw_info {
};
const static struct fw_info orinoco_fw[] = {
- { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
- { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
- { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+ { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+ { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+ { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
};
/* Structure used to access fields in FW
@@ -487,13 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
if (err)
goto free;
- err = request_firmware(&fw_entry, firmware, priv->dev);
- if (err) {
- printk(KERN_ERR "%s: Cannot find firmware %s\n",
- dev->name, firmware);
- err = -ENOENT;
- goto free;
- }
+ if (!priv->cached_fw) {
+ err = request_firmware(&fw_entry, firmware, priv->dev);
+
+ if (err) {
+ printk(KERN_ERR "%s: Cannot find firmware %s\n",
+ dev->name, firmware);
+ err = -ENOENT;
+ goto free;
+ }
+ } else
+ fw_entry = priv->cached_fw;
hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -535,7 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,
dev->name, hermes_present(hw));
abort:
- release_firmware(fw_entry);
+ /* If we requested the firmware, release it. */
+ if (!priv->cached_fw)
+ release_firmware(fw_entry);
free:
kfree(pda);
@@ -639,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv,
int ret;
const struct firmware *fw_entry;
- if (request_firmware(&fw_entry, fw->pri_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
- return -ENOENT;
- }
+ if (!priv->cached_pri_fw) {
+ if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->pri_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_pri_fw;
/* Load primary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 0);
- release_firmware(fw_entry);
+
+ if (!priv->cached_pri_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Primary firmware download failed\n",
dev->name);
return ret;
}
- if (request_firmware(&fw_entry, fw->sta_fw,
- priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
- return -ENOENT;
- }
+ if (!priv->cached_fw) {
+ if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
+ printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+ dev->name, fw->sta_fw);
+ return -ENOENT;
+ }
+ } else
+ fw_entry = priv->cached_fw;
/* Load secondary firmware */
ret = symbol_dl_image(priv, fw, fw_entry->data,
fw_entry->data + fw_entry->size, 1);
- release_firmware(fw_entry);
+ if (!priv->cached_fw)
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR "%s: Secondary firmware download failed\n",
dev->name);
@@ -699,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv)
return err;
}
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+static void orinoco_cache_fw(struct orinoco_private *priv, int ap)
+{
+ const struct firmware *fw_entry = NULL;
+ const char *pri_fw;
+ const char *fw;
+
+ pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
+ if (ap)
+ fw = orinoco_fw[priv->firmware_type].ap_fw;
+ else
+ fw = orinoco_fw[priv->firmware_type].sta_fw;
+
+ if (pri_fw) {
+ if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
+ priv->cached_pri_fw = fw_entry;
+ }
+
+ if (fw) {
+ if (request_firmware(&fw_entry, fw, priv->dev) == 0)
+ priv->cached_fw = fw_entry;
+ }
+}
+
+static void orinoco_uncache_fw(struct orinoco_private *priv)
+{
+ if (priv->cached_pri_fw)
+ release_firmware(priv->cached_pri_fw);
+ if (priv->cached_fw)
+ release_firmware(priv->cached_fw);
+
+ priv->cached_pri_fw = NULL;
+ priv->cached_fw = NULL;
+}
+#else
+#define orinoco_cache_fw(priv, ap)
+#define orinoco_uncache_fw(priv)
+#endif
+
/********************************************************************/
/* Device methods */
/********************************************************************/
@@ -800,7 +853,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
wstats->qual.qual = (int)le16_to_cpu(cq.qual);
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
- wstats->qual.updated = 7;
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
}
}
@@ -830,7 +883,8 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
return -EINVAL;
- if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
+ /* MTU + encapsulation + header length */
+ if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
(priv->nicbuf_size - ETH_HLEN) )
return -EINVAL;
@@ -1158,7 +1212,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
wstats.level = level - 0x95;
wstats.noise = noise - 0x95;
wstats.qual = (level > noise) ? (level - noise) : 0;
- wstats.updated = 7;
+ wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
/* Update spy records */
wireless_spy_update(dev, mac, &wstats);
}
@@ -1245,7 +1299,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
}
/* sanity check the length */
- if (datalen > IEEE80211_DATA_LEN + 12) {
+ if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
printk(KERN_DEBUG "%s: oversized monitor frame, "
"data length = %d\n", dev->name, datalen);
stats->rx_length_errors++;
@@ -1280,7 +1334,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = __constant_htons(ETH_P_802_2);
- dev->last_rx = jiffies;
stats->rx_packets++;
stats->rx_bytes += skb->len;
@@ -1374,7 +1427,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
data. */
goto out;
}
- if (length > IEEE80211_DATA_LEN) {
+ if (length > IEEE80211_MAX_DATA_LEN) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
@@ -1477,12 +1530,11 @@ static void orinoco_rx(struct net_device *dev,
MICHAEL_MIC_LEN)) {
union iwreq_data wrqu;
struct iw_michaelmicfailure wxmic;
- DECLARE_MAC_BUF(mac);
printk(KERN_WARNING "%s: "
- "Invalid Michael MIC in data frame from %s, "
+ "Invalid Michael MIC in data frame from %pM, "
"using key %i\n",
- dev->name, print_mac(mac, src), key_id);
+ dev->name, src, key_id);
/* TODO: update stats */
@@ -1530,7 +1582,6 @@ static void orinoco_rx(struct net_device *dev,
else
memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
- dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
if (fc & IEEE80211_FCTL_TODS)
@@ -1699,7 +1750,7 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
union iwreq_data wrqu;
int err;
- err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
if (err != 0)
return;
@@ -1722,7 +1773,7 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
if (!priv->has_wpa)
return;
- err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
sizeof(buf), NULL, &buf);
if (err != 0)
return;
@@ -1752,7 +1803,7 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
if (!priv->has_wpa)
return;
- err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
sizeof(buf), NULL, &buf);
if (err != 0)
return;
@@ -2301,6 +2352,11 @@ int orinoco_reinit_firmware(struct net_device *dev)
int err;
err = hermes_init(hw);
+ if (priv->do_fw_download && !err) {
+ err = orinoco_download(priv);
+ if (err)
+ priv->do_fw_download = 0;
+ }
if (!err)
err = orinoco_allocate_fid(dev);
@@ -2926,12 +2982,6 @@ static void orinoco_reset(struct work_struct *work)
}
}
- if (priv->do_fw_download) {
- err = orinoco_download(priv);
- if (err)
- priv->do_fw_download = 0;
- }
-
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
@@ -3056,6 +3106,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
}
/********************************************************************/
+/* Power management */
+/********************************************************************/
+#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
+static int orinoco_pm_notifier(struct notifier_block *notifier,
+ unsigned long pm_event,
+ void *unused)
+{
+ struct orinoco_private *priv = container_of(notifier,
+ struct orinoco_private,
+ pm_notifier);
+
+ /* All we need to do is cache the firmware before suspend, and
+ * release it when we come out.
+ *
+ * Only need to do this if we're downloading firmware. */
+ if (!priv->do_fw_download)
+ return NOTIFY_DONE;
+
+ switch (pm_event) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ orinoco_cache_fw(priv, 0);
+ break;
+
+ case PM_POST_RESTORE:
+ /* Restore from hibernation failed. We need to clean
+ * up in exactly the same way, so fall through. */
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ orinoco_uncache_fw(priv);
+ break;
+
+ case PM_RESTORE_PREPARE:
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
+#define orinoco_pm_notifier NULL
+#endif
+
+/********************************************************************/
/* Initialization */
/********************************************************************/
@@ -3277,11 +3371,10 @@ static int orinoco_init(struct net_device *dev)
struct hermes_idstring nickbuf;
u16 reclen;
int len;
- DECLARE_MAC_BUF(mac);
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
- priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
+ priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
/* Initialize the firmware */
err = hermes_init(hw);
@@ -3299,6 +3392,10 @@ static int orinoco_init(struct net_device *dev)
}
if (priv->do_fw_download) {
+#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
+ orinoco_cache_fw(priv, 0);
+#endif
+
err = orinoco_download(priv);
if (err)
priv->do_fw_download = 0;
@@ -3348,8 +3445,8 @@ static int orinoco_init(struct net_device *dev)
goto out;
}
- printk(KERN_DEBUG "%s: MAC address %s\n",
- dev->name, print_mac(mac, dev->dev_addr));
+ printk(KERN_DEBUG "%s: MAC address %pM\n",
+ dev->name, dev->dev_addr);
/* Get the station name */
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
@@ -3535,6 +3632,13 @@ struct net_device
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
+ priv->cached_pri_fw = NULL;
+ priv->cached_fw = NULL;
+
+ /* Register PM notifiers */
+ priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+ register_pm_notifier(&priv->pm_notifier);
+
return dev;
}
@@ -3546,6 +3650,10 @@ void free_orinocodev(struct net_device *dev)
* when we call tasklet_kill it will run one final time,
* emptying the list */
tasklet_kill(&priv->rx_tasklet);
+
+ unregister_pm_notifier(&priv->pm_notifier);
+ orinoco_uncache_fw(priv);
+
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
@@ -4672,7 +4780,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
/* Determine and validate the key index */
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
- if ((idx < 1) || (idx > WEP_KEYS))
+ if ((idx < 1) || (idx > 4))
goto out;
idx--;
} else
@@ -4777,7 +4885,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx) {
- if ((idx < 1) || (idx > WEP_KEYS))
+ if ((idx < 1) || (idx > 4))
goto out;
idx--;
} else
@@ -4940,7 +5048,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
unsigned long flags;
int err = 0;
- if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
+ /* cut off at IEEE80211_MAX_DATA_LEN */
+ if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
(wrqu->data.length && (extra == NULL)))
return -EINVAL;
@@ -5433,7 +5542,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev,
char *current_ev,
char *end_buf,
union hermes_scan_info *bss,
- unsigned int last_scanned)
+ unsigned long last_scanned)
{
struct orinoco_private *priv = netdev_priv(dev);
u16 capabilities;
@@ -5580,7 +5689,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
char *current_ev,
char *end_buf,
struct agere_ext_scan_info *bss,
- unsigned int last_scanned)
+ unsigned long last_scanned)
{
u16 capabilities;
u16 channel;
@@ -5623,7 +5732,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
&iwe, IW_EV_UINT_LEN);
}
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET);
+ ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
channel = ie ? ie[2] : 0;
if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
/* Add channel and frequency */
@@ -5673,7 +5782,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
}
/* RSN IE */
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN);
+ ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
if (ie) {
iwe.cmd = IWEVGENIE;
iwe.u.data.length = ie[1] + 2;
@@ -5681,7 +5790,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev,
&iwe, ie);
}
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES);
+ ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
if (ie) {
char *p = current_ev + iwe_stream_lcp_len(info);
int i;
@@ -5976,7 +6085,7 @@ static void orinoco_get_drvinfo(struct net_device *dev,
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
if (dev->dev.parent)
- strncpy(info->bus_info, dev->dev.parent->bus_id,
+ strncpy(info->bus_info, dev_name(dev->dev.parent),
sizeof(info->bus_info) - 1);
else
snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 981570bd3b9..00750c8ba7d 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -10,6 +10,7 @@
#define DRIVER_VERSION "0.15"
#include <linux/interrupt.h>
+#include <linux/suspend.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
@@ -66,6 +67,8 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct firmware;
+
struct orinoco_private {
void *card; /* Pointer to card dependent structure */
struct device *dev;
@@ -164,6 +167,12 @@ struct orinoco_private {
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
unsigned int key_mgmt:3;
+
+ /* Cached in memory firmware to use during ->resume. */
+ const struct firmware *cached_pri_fw;
+ const struct firmware *cached_fw;
+
+ struct notifier_block pm_notifier;
};
#ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index 6fcf2bda7cd..f127602670e 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -178,13 +178,17 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
/* Note that the CIS values need to be rescaled */
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+ __func__, vcc,
+ cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
if (!ignore_cis_vcc)
goto next_entry;
}
} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+ __func__, vcc,
+ dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
if (!ignore_cis_vcc)
goto next_entry;
}
@@ -308,7 +312,7 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index 2fc86596302..2fc86596302 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index 4ebd638a073..4ebd638a073 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index f4e5e06760c..f4e5e06760c 100644
--- a/drivers/net/wireless/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index ef761857bb3..ef761857bb3 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index ede24ec309c..ede24ec309c 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 852789ad34b..b2ca2e39c2c 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -248,13 +248,17 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
/* Note that the CIS values need to be rescaled */
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+ __func__, vcc,
+ cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
if (!ignore_cis_vcc)
goto next_entry;
}
} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
- DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+ DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
+ __func__, vcc,
+ dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
if (!ignore_cis_vcc)
goto next_entry;
}
@@ -383,7 +387,7 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
@@ -450,10 +454,29 @@ spectrum_cs_resume(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct orinoco_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ err = orinoco_reinit_firmware(dev);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable--;
- schedule_work(&priv->reset_work);
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(dev);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 1d0704fe146..ab79e32f0b2 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -14,17 +14,17 @@
* published by the Free Software Foundation.
*/
-enum control_frame_types {
- P54_CONTROL_TYPE_FILTER_SET = 0,
- P54_CONTROL_TYPE_CHANNEL_CHANGE,
- P54_CONTROL_TYPE_FREQDONE,
+enum p54_control_frame_types {
+ P54_CONTROL_TYPE_SETUP = 0,
+ P54_CONTROL_TYPE_SCAN,
+ P54_CONTROL_TYPE_TRAP,
P54_CONTROL_TYPE_DCFINIT,
- P54_CONTROL_TYPE_ENCRYPTION,
+ P54_CONTROL_TYPE_RX_KEYCACHE,
P54_CONTROL_TYPE_TIM,
- P54_CONTROL_TYPE_POWERMGT,
- P54_CONTROL_TYPE_FREEQUEUE,
+ P54_CONTROL_TYPE_PSM,
+ P54_CONTROL_TYPE_TXCANCEL,
P54_CONTROL_TYPE_TXDONE,
- P54_CONTROL_TYPE_PING,
+ P54_CONTROL_TYPE_BURST,
P54_CONTROL_TYPE_STAT_READBACK,
P54_CONTROL_TYPE_BBP,
P54_CONTROL_TYPE_EEPROM_READBACK,
@@ -37,18 +37,44 @@ enum control_frame_types {
P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
P54_CONTROL_TYPE_CCE_QUIET,
P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+ P54_CONTROL_TYPE_PCS,
+ P54_CONTROL_TYPE_BT_BALANCER = 28,
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+ P54_CONTROL_TYPE_ARPTABLE = 31,
+ P54_CONTROL_TYPE_BT_OPTIONS = 35
};
-struct p54_control_hdr {
- __le16 magic1;
+#define P54_HDR_FLAG_CONTROL BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
+
+struct p54_hdr {
+ __le16 flags;
__le16 len;
__le32 req_id;
- __le16 type; /* enum control_frame_types */
- u8 retry1;
- u8 retry2;
+ __le16 type; /* enum p54_control_frame_types */
+ u8 rts_tries;
+ u8 tries;
u8 data[0];
} __attribute__ ((packed));
+#define FREE_AFTER_TX(skb) \
+ ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+struct p54_edcf_queue_param {
+ __le16 aifs;
+ __le16 cwmin;
+ __le16 cwmax;
+ __le16 txop;
+} __attribute__ ((packed));
+
+struct p54_rssi_linear_approximation {
+ s16 mul;
+ s16 add;
+ s16 longbow_unkn;
+ s16 longbow_unk2;
+};
+
#define EEPROM_READBACK_LEN 0x3fc
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
@@ -59,49 +85,53 @@ struct p54_control_hdr {
#define FW_LM20 0x4c4d3230
struct p54_common {
+ struct ieee80211_hw *hw;
u32 rx_start;
u32 rx_end;
struct sk_buff_head tx_queue;
- void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data,
- size_t len, int free_on_tx);
+ void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
int mode;
- u16 seqno;
u16 rx_mtu;
u8 headroom;
u8 tailroom;
struct mutex conf_mutex;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
- __le16 filter_type;
struct pda_iq_autocal_entry *iq_autocal;
unsigned int iq_autocal_len;
struct pda_channel_output_limit *output_limit;
unsigned int output_limit_len;
struct pda_pa_curve_data *curve_data;
+ struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
unsigned int filter_flags;
+ bool use_short_slot;
u16 rxhw;
u8 version;
- u8 rx_antenna;
unsigned int tx_hdr_len;
- void *cached_vdcf;
unsigned int fw_var;
unsigned int fw_interface;
unsigned int output_power;
u32 tsf_low32;
u32 tsf_high32;
+ u64 basic_rate_mask;
+ u16 wakeup_timer;
+ u16 aid;
struct ieee80211_tx_queue_stats tx_stats[8];
+ struct p54_edcf_queue_param qos_params[8];
struct ieee80211_low_level_stats stats;
- struct timer_list stats_timer;
- struct completion stats_comp;
- void *cached_stats;
+ struct delayed_work work;
+ struct sk_buff *cached_beacon;
int noise;
void *eeprom;
struct completion eeprom_comp;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
};
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_read_eeprom(struct ieee80211_hw *dev);
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 827ca0384a4..82354b974a0 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -1,12 +1,15 @@
-
/*
* Common code for mac80211 Prism54 drivers
*
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
*
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
*
* 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
@@ -22,6 +25,9 @@
#include "p54.h"
#include "p54common.h"
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_DESCRIPTION("Softmac Prism54 common code");
MODULE_LICENSE("GPL");
@@ -152,21 +158,21 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
priv->fw_interface = be32_to_cpup((__be32 *)
bootrec->data);
switch (priv->fw_interface) {
- case FW_FMAC:
- printk(KERN_INFO "p54: FreeMAC firmware\n");
- break;
- case FW_LM20:
- printk(KERN_INFO "p54: LM20 firmware\n");
- break;
case FW_LM86:
- printk(KERN_INFO "p54: LM86 firmware\n");
- break;
- case FW_LM87:
- printk(KERN_INFO "p54: LM87 firmware\n");
+ case FW_LM20:
+ case FW_LM87: {
+ char *iftype = (char *)bootrec->data;
+ printk(KERN_INFO "%s: p54 detected a LM%c%c "
+ "firmware\n",
+ wiphy_name(dev->wiphy),
+ iftype[2], iftype[3]);
break;
+ }
+ case FW_FMAC:
default:
- printk(KERN_INFO "p54: unknown firmware\n");
- break;
+ printk(KERN_ERR "%s: unsupported firmware\n",
+ wiphy_name(dev->wiphy));
+ return -ENODEV;
}
break;
case BR_CODE_COMPONENT_VERSION:
@@ -182,8 +188,10 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
priv->headroom = desc->headroom;
priv->tailroom = desc->tailroom;
+ priv->privacy_caps = desc->privacy_caps;
+ priv->rx_keycache_size = desc->rx_keycache_size;
if (le32_to_cpu(bootrec->len) == 11)
- priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu);
+ priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
else
priv->rx_mtu = (size_t)
0x620 - priv->tx_hdr_len;
@@ -208,18 +216,35 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
}
if (fw_version)
- printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
- fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+ printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+ wiphy_name(dev->wiphy), fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var < 0x500)
+ printk(KERN_INFO "%s: you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n",
+ wiphy_name(dev->wiphy));
if (priv->fw_var >= 0x300) {
/* Firmware supports QoS, use it! */
- priv->tx_stats[4].limit = 3;
- priv->tx_stats[5].limit = 4;
- priv->tx_stats[6].limit = 3;
- priv->tx_stats[7].limit = 1;
+ priv->tx_stats[4].limit = 3; /* AC_VO */
+ priv->tx_stats[5].limit = 4; /* AC_VI */
+ priv->tx_stats[6].limit = 3; /* AC_BE */
+ priv->tx_stats[7].limit = 2; /* AC_BK */
dev->queues = 4;
}
+ if (!modparam_nohwcrypt)
+ printk(KERN_INFO "%s: cryptographic accelerator "
+ "WEP:%s, TKIP:%s, CCMP:%s\n",
+ wiphy_name(dev->wiphy),
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+ "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+ BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+ "YES" : "no");
+
return 0;
}
EXPORT_SYMBOL_GPL(p54_parse_firmware);
@@ -310,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
"Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
static int p54_init_xbow_synth(struct ieee80211_hw *dev);
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+ u16 type)
+{
+ struct p54_common *priv = dev->priv;
+ int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+ int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+ int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+ int i;
+
+ if (len != (entry_size * num_entries)) {
+ printk(KERN_ERR "%s: unknown rssi calibration data packing "
+ " type:(%x) len:%d.\n",
+ wiphy_name(dev->wiphy), type, len);
+
+ print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ struct pda_rssi_cal_entry *cal = data +
+ (offset + i * entry_size);
+ priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+ priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+ }
+}
+
static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
{
struct p54_common *priv = dev->priv;
@@ -320,7 +375,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
int err;
u8 *end = (u8 *)eeprom + len;
u16 synth = 0;
- DECLARE_MAC_BUF(mac);
wrap = (struct eeprom_pda_wrap *) eeprom;
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -377,8 +431,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
err = p54_convert_rev1(dev, curve_data);
break;
default:
- printk(KERN_ERR "p54: unknown curve data "
+ printk(KERN_ERR "%s: unknown curve data "
"revision %d\n",
+ wiphy_name(dev->wiphy),
curve_data->cal_method_rev);
err = -ENODEV;
break;
@@ -409,12 +464,40 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
priv->version = *(u8 *)(entry->data + 1);
break;
+ case PDR_RSSI_LINEAR_APPROXIMATION:
+ case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+ case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+ p54_parse_rssical(dev, entry->data, data_len,
+ le16_to_cpu(entry->code));
+ break;
case PDR_END:
/* make it overrun */
entry_len = len;
break;
+ case PDR_MANUFACTURING_PART_NUMBER:
+ case PDR_PDA_VERSION:
+ case PDR_NIC_SERIAL_NUMBER:
+ case PDR_REGULATORY_DOMAIN_LIST:
+ case PDR_TEMPERATURE_TYPE:
+ case PDR_PRISM_PCI_IDENTIFIER:
+ case PDR_COUNTRY_INFORMATION:
+ case PDR_OEM_NAME:
+ case PDR_PRODUCT_NAME:
+ case PDR_UTF8_OEM_NAME:
+ case PDR_UTF8_PRODUCT_NAME:
+ case PDR_COUNTRY_LIST:
+ case PDR_DEFAULT_COUNTRY:
+ case PDR_ANTENNA_GAIN:
+ case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
+ case PDR_REGULATORY_POWER_LIMITS:
+ case PDR_RADIATED_TRANSMISSION_CORRECTION:
+ case PDR_PRISM_TX_IQ_CALIBRATION:
+ case PDR_BASEBAND_REGISTERS:
+ case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
+ break;
default:
- printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
+ printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
+ wiphy_name(dev->wiphy),
le16_to_cpu(entry->code));
break;
}
@@ -424,17 +507,18 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
if (!synth || !priv->iq_autocal || !priv->output_limit ||
!priv->curve_data) {
- printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
+ printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+ wiphy_name(dev->wiphy));
err = -EINVAL;
goto err;
}
- priv->rxhw = synth & 0x07;
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == 4)
p54_init_xbow_synth(dev);
- if (!(synth & 0x40))
+ if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
- if (!(synth & 0x80))
+ if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
@@ -446,9 +530,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
}
- printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n",
+ printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
wiphy_name(dev->wiphy),
- print_mac(mac, dev->wiphy->perm_addr),
+ dev->wiphy->perm_addr,
priv->version, p54_rf_chips[priv->rxhw]);
return 0;
@@ -469,36 +553,56 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
priv->curve_data = NULL;
}
- printk(KERN_ERR "p54: eeprom parse failed!\n");
+ printk(KERN_ERR "%s: eeprom parse failed!\n",
+ wiphy_name(dev->wiphy));
return err;
}
static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
{
- /* TODO: get the rssi_add & rssi_mul data from the eeprom */
- return ((rssi * 0x83) / 64 - 400) / 4;
+ struct p54_common *priv = dev->priv;
+ int band = dev->conf.channel->band;
+
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
}
static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54_common *priv = dev->priv;
- struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
+ struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
struct ieee80211_rx_status rx_status = {0};
u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
u32 tsf32;
- if (!(hdr->magic & cpu_to_le16(0x0001))) {
+ /*
+ * If the device is in a unspecified state we have to
+ * ignore all data frames. Else we could end up with a
+ * nasty crash.
+ */
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return 0;
+
+ if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
if (priv->filter_flags & FIF_FCSFAIL)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
else
return 0;
}
+ if (hdr->decrypt_status == P54_DECRYPT_OK)
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+ (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+ rx_status.flag |= RX_FLAG_MMIC_ERROR;
+
rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
rx_status.noise = priv->noise;
/* XX correct? */
rx_status.qual = (100 * hdr->rssi) / 127;
+ if (hdr->rate & 0x10)
+ rx_status.flag |= RX_FLAG_SHORTPRE;
rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
hdr->rate : (hdr->rate - 4)) & 0xf;
rx_status.freq = freq;
@@ -513,7 +617,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.flag |= RX_FLAG_TSFT;
- if (hdr->magic & cpu_to_le16(0x4000))
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
header_len += hdr->align[0];
skb_pull(skb, header_len);
@@ -521,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ queue_delayed_work(dev->workqueue, &priv->work,
+ msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
return -1;
}
@@ -529,88 +636,197 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv;
int i;
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
for (i = 0; i < dev->queues; i++)
if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
ieee80211_wake_queue(dev, i);
}
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_tx_info *info;
+ struct memrecord *range;
+ unsigned long flags;
+ u32 freed = 0, last_addr = priv->rx_start;
+
+ if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
+ return;
+
+ /*
+ * don't try to free an already unlinked skb
+ */
+ if (unlikely((!skb->next) || (!skb->prev)))
+ return;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *)info->rate_driver_data;
+ if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
+ struct ieee80211_tx_info *ni;
+ struct memrecord *mr;
+
+ ni = IEEE80211_SKB_CB(skb->prev);
+ mr = (struct memrecord *)ni->rate_driver_data;
+ last_addr = mr->end_addr;
+ }
+ if (skb->next != (struct sk_buff *)&priv->tx_queue) {
+ struct ieee80211_tx_info *ni;
+ struct memrecord *mr;
+
+ ni = IEEE80211_SKB_CB(skb->next);
+ mr = (struct memrecord *)ni->rate_driver_data;
+ freed = mr->start_addr - last_addr;
+ } else
+ freed = priv->rx_end - last_addr;
+ __skb_unlink(skb, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ dev_kfree_skb_any(skb);
+
+ if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
+ IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
+ p54_wake_free_queues(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
+ __le32 req_id)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *entry = priv->tx_queue.next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ while (entry != (struct sk_buff *)&priv->tx_queue) {
+ struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+ if (hdr->req_id == req_id) {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return entry;
+ }
+ entry = entry->next;
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return NULL;
+}
+
static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
- struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
struct memrecord *range = NULL;
u32 freed = 0;
u32 last_addr = priv->rx_start;
unsigned long flags;
+ int count, idx;
spin_lock_irqsave(&priv->tx_queue.lock, flags);
while (entry != (struct sk_buff *)&priv->tx_queue) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- range = (void *)info->driver_data;
- if (range->start_addr == addr) {
- struct p54_control_hdr *entry_hdr;
- struct p54_tx_control_allocdata *entry_data;
- int pad = 0;
-
- if (entry->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct memrecord *mr;
-
- ni = IEEE80211_SKB_CB(entry->next);
- mr = (struct memrecord *)ni->driver_data;
- freed = mr->start_addr - last_addr;
- } else
- freed = priv->rx_end - last_addr;
+ struct p54_hdr *entry_hdr;
+ struct p54_tx_data *entry_data;
+ int pad = 0;
+ range = (void *)info->rate_driver_data;
+ if (range->start_addr != addr) {
last_addr = range->end_addr;
- __skb_unlink(entry, &priv->tx_queue);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ entry = entry->next;
+ continue;
+ }
- memset(&info->status, 0, sizeof(info->status));
- entry_hdr = (struct p54_control_hdr *) entry->data;
- entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
- if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
- pad = entry_data->align[0];
-
- priv->tx_stats[entry_data->hw_queue].len--;
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
- if (!(payload->status & 0x01))
- info->flags |= IEEE80211_TX_STAT_ACK;
- else
- info->status.excessive_retries = 1;
- }
- info->status.retry_count = payload->retries - 1;
- info->status.ack_signal = p54_rssi_to_dbm(dev,
- le16_to_cpu(payload->ack_rssi));
- skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry);
- goto out;
+ if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+ struct ieee80211_tx_info *ni;
+ struct memrecord *mr;
+
+ ni = IEEE80211_SKB_CB(entry->next);
+ mr = (struct memrecord *)ni->rate_driver_data;
+ freed = mr->start_addr - last_addr;
} else
- last_addr = range->end_addr;
- entry = entry->next;
+ freed = priv->rx_end - last_addr;
+
+ last_addr = range->end_addr;
+ __skb_unlink(entry, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+ entry_hdr = (struct p54_hdr *) entry->data;
+ entry_data = (struct p54_tx_data *) entry_hdr->data;
+ priv->tx_stats[entry_data->hw_queue].len--;
+ priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+ if (unlikely(entry == priv->cached_beacon)) {
+ kfree_skb(entry);
+ priv->cached_beacon = NULL;
+ goto out;
+ }
+
+ /*
+ * Clear manually, ieee80211_tx_info_clear_status would
+ * clear the counts too and we need them.
+ */
+ memset(&info->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+ status.ampdu_ack_len) != 23);
+
+ if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ pad = entry_data->align[0];
+
+ /* walk through the rates array and adjust the counts */
+ count = payload->tries;
+ for (idx = 0; idx < 4; idx++) {
+ if (count >= info->status.rates[idx].count) {
+ count -= info->status.rates[idx].count;
+ } else if (count > 0) {
+ info->status.rates[idx].count = count;
+ count = 0;
+ } else {
+ info->status.rates[idx].idx = -1;
+ info->status.rates[idx].count = 0;
+ }
+ }
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (!payload->status))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (payload->status & P54_TX_PSM_CANCELLED)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.ack_signal = p54_rssi_to_dbm(dev,
+ (int)payload->ack_rssi);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(dev, entry);
+ goto out;
}
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
out:
- if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
- sizeof(struct p54_control_hdr))
+ if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
+ IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
p54_wake_free_queues(dev);
}
static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
struct sk_buff *skb)
{
- struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
struct p54_common *priv = dev->priv;
if (!priv->eeprom)
return ;
- memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len));
+ if (priv->fw_var >= 0x509) {
+ memcpy(priv->eeprom, eeprom->v2.data,
+ le16_to_cpu(eeprom->v2.len));
+ } else {
+ memcpy(priv->eeprom, eeprom->v1.data,
+ le16_to_cpu(eeprom->v1.len));
+ }
complete(&priv->eeprom_comp);
}
@@ -618,10 +834,14 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
- u32 tsf32 = le32_to_cpu(stats->tsf32);
+ u32 tsf32;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+ tsf32 = le32_to_cpu(stats->tsf32);
if (tsf32 < priv->tsf_low32)
priv->tsf_high32++;
priv->tsf_low32 = tsf32;
@@ -631,19 +851,50 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
- complete(&priv->stats_comp);
- mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
+ p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
+}
+
+static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_trap *trap = (struct p54_trap *) hdr->data;
+ u16 event = le16_to_cpu(trap->event);
+ u16 freq = le16_to_cpu(trap->frequency);
+
+ switch (event) {
+ case P54_TRAP_BEACON_TX:
+ break;
+ case P54_TRAP_RADAR:
+ printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+ wiphy_name(dev->wiphy), freq);
+ break;
+ case P54_TRAP_NO_BEACON:
+ break;
+ case P54_TRAP_SCAN:
+ break;
+ case P54_TRAP_TBTT:
+ break;
+ case P54_TRAP_TIMER:
+ break;
+ default:
+ printk(KERN_INFO "%s: received event:%x freq:%d\n",
+ wiphy_name(dev->wiphy), event, freq);
+ break;
+ }
}
static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
{
- struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
switch (le16_to_cpu(hdr->type)) {
case P54_CONTROL_TYPE_TXDONE:
p54_rx_frame_sent(dev, skb);
break;
+ case P54_CONTROL_TYPE_TRAP:
+ p54_rx_trap(dev, skb);
+ break;
case P54_CONTROL_TYPE_BBP:
break;
case P54_CONTROL_TYPE_STAT_READBACK:
@@ -664,9 +915,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
/* returns zero if skb can be reused */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
- u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+ u16 type = le16_to_cpu(*((__le16 *)skb->data));
- if (type == 0x80)
+ if (type & P54_HDR_FLAG_CONTROL)
return p54_rx_control(dev, skb);
else
return p54_rx_data(dev, skb);
@@ -682,12 +933,14 @@ EXPORT_SYMBOL_GPL(p54_rx);
* marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
* allocated areas.
*/
-static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_control_hdr *data, u32 len)
+static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct p54_hdr *data, u32 len)
{
struct p54_common *priv = dev->priv;
struct sk_buff *entry = priv->tx_queue.next;
struct sk_buff *target_skb = NULL;
+ struct ieee80211_tx_info *info;
+ struct memrecord *range;
u32 last_addr = priv->rx_start;
u32 largest_hole = 0;
u32 target_addr = priv->rx_start;
@@ -695,12 +948,37 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
unsigned int left;
len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
+ if (!skb)
+ return -EINVAL;
+
spin_lock_irqsave(&priv->tx_queue.lock, flags);
+
left = skb_queue_len(&priv->tx_queue);
+ if (unlikely(left >= 28)) {
+ /*
+ * The tx_queue is nearly full!
+ * We have throttle normal data traffic, because we must
+ * have a few spare slots for control frames left.
+ */
+ ieee80211_stop_queues(dev);
+ queue_delayed_work(dev->workqueue, &priv->work,
+ msecs_to_jiffies(P54_TX_TIMEOUT));
+
+ if (unlikely(left == 32)) {
+ /*
+ * The tx_queue is now really full.
+ *
+ * TODO: check if the device has crashed and reset it.
+ */
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -ENOSPC;
+ }
+ }
+
while (left--) {
u32 hole_size;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- struct memrecord *range = (void *)info->driver_data;
+ info = IEEE80211_SKB_CB(entry);
+ range = (void *)info->rate_driver_data;
hole_size = range->start_addr - last_addr;
if (!target_skb && hole_size >= len) {
target_skb = entry->prev;
@@ -715,64 +993,102 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
target_skb = priv->tx_queue.prev;
largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
if (!skb_queue_empty(&priv->tx_queue)) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
- struct memrecord *range = (void *)info->driver_data;
+ info = IEEE80211_SKB_CB(target_skb);
+ range = (void *)info->rate_driver_data;
target_addr = range->end_addr;
}
} else
largest_hole = max(largest_hole, priv->rx_end - last_addr);
- if (skb) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct memrecord *range = (void *)info->driver_data;
- range->start_addr = target_addr;
- range->end_addr = target_addr + len;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
- if (largest_hole < priv->rx_mtu + priv->headroom +
- priv->tailroom +
- sizeof(struct p54_control_hdr))
- ieee80211_stop_queues(dev);
+ if (!target_skb) {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ ieee80211_stop_queues(dev);
+ return -ENOSPC;
}
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *)info->rate_driver_data;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
+ 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
+ ieee80211_stop_queues(dev);
+
data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ return 0;
+}
+
+static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev,
+ u16 hdr_flags, u16 len, u16 type, gfp_t memflags)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_hdr *hdr;
+ struct sk_buff *skb;
+
+ skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, priv->tx_hdr_len);
+
+ hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->len = cpu_to_le16(len - sizeof(*hdr));
+ hdr->type = cpu_to_le16(type);
+ hdr->tries = hdr->rts_tries = 0;
+
+ if (unlikely(p54_assign_address(dev, skb, hdr, len))) {
+ kfree_skb(skb);
+ return NULL;
+ }
+ return skb;
}
int p54_read_eeprom(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr = NULL;
+ struct p54_hdr *hdr = NULL;
struct p54_eeprom_lm86 *eeprom_hdr;
- size_t eeprom_size = 0x2020, offset = 0, blocksize;
+ struct sk_buff *skb;
+ size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
int ret = -ENOMEM;
void *eeprom = NULL;
- hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) +
- sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL);
- if (!hdr)
- goto free;
+ maxblocksize = EEPROM_READBACK_LEN;
+ if (priv->fw_var >= 0x509)
+ maxblocksize -= 0xc;
+ else
+ maxblocksize -= 0x4;
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) +
+ sizeof(*eeprom_hdr) + maxblocksize,
+ P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL);
+ if (!skb)
+ goto free;
priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
if (!priv->eeprom)
goto free;
-
eeprom = kzalloc(eeprom_size, GFP_KERNEL);
if (!eeprom)
goto free;
- hdr->magic1 = cpu_to_le16(0x8000);
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
- hdr->retry1 = hdr->retry2 = 0;
- eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+ sizeof(*eeprom_hdr) + maxblocksize);
while (eeprom_size) {
- blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN);
- hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr));
- eeprom_hdr->offset = cpu_to_le16(offset);
- eeprom_hdr->len = cpu_to_le16(blocksize);
- p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) +
- sizeof(*hdr));
- priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0);
+ blocksize = min(eeprom_size, maxblocksize);
+ if (priv->fw_var < 0x509) {
+ eeprom_hdr->v1.offset = cpu_to_le16(offset);
+ eeprom_hdr->v1.len = cpu_to_le16(blocksize);
+ } else {
+ eeprom_hdr->v2.offset = cpu_to_le32(offset);
+ eeprom_hdr->v2.len = cpu_to_le16(blocksize);
+ eeprom_hdr->v2.magic2 = 0xf;
+ memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+ }
+ priv->tx(dev, skb);
if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
printk(KERN_ERR "%s: device does not respond!\n",
@@ -790,166 +1106,422 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
free:
kfree(priv->eeprom);
priv->eeprom = NULL;
- kfree(hdr);
+ p54_free_skb(dev, skb);
kfree(eeprom);
return ret;
}
EXPORT_SYMBOL_GPL(p54_read_eeprom);
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ struct p54_tim *tim;
+
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+ sizeof(struct p54_hdr) + sizeof(*tim),
+ P54_CONTROL_TYPE_TIM, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
+ priv->tx(dev, skb);
+ return 0;
+}
+
+static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ struct p54_sta_unlock *sta;
+
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+ sizeof(struct p54_hdr) + sizeof(*sta),
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+ memcpy(sta->addr, addr, ETH_ALEN);
+ priv->tx(dev, skb);
+ return 0;
+}
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ struct ieee80211_sta *sta)
+{
+ switch (notify_cmd) {
+ case STA_NOTIFY_ADD:
+ case STA_NOTIFY_REMOVE:
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(dev, sta->addr);
+ break;
+ case STA_NOTIFY_AWAKE:
+ /* update the firmware's filter table */
+ p54_sta_unlock(dev, sta->addr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ struct p54_txcancel *cancel;
+
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+ sizeof(struct p54_hdr) + sizeof(*cancel),
+ P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = (void *)entry->data;
+ cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+ cancel->req_id = hdr->req_id;
+ priv->tx(dev, skb);
+ return 0;
+}
+
+static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
+ u16 *flags, u16 *aid)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct p54_common *priv = dev->priv;
+ int ret = 0;
+
+ if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+ if (ieee80211_is_beacon(hdr->frame_control)) {
+ *aid = 0;
+ *queue = 0;
+ *extra_len = IEEE80211_MAX_TIM_LEN;
+ *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+ return 0;
+ } else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ *aid = 0;
+ *queue = 2;
+ *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+ P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ return 0;
+ } else {
+ *queue = 2;
+ ret = 0;
+ }
+ } else {
+ *queue += 4;
+ ret = 1;
+ }
+
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ *aid = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ *aid = 0;
+ *queue = 3;
+ return 0;
+ }
+ if (info->control.sta)
+ *aid = info->control.sta->aid;
+ else
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ }
+ return ret;
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+ switch (alg) {
+ case ALG_WEP:
+ return P54_CRYPTO_WEP;
+ case ALG_TKIP:
+ return P54_CRYPTO_TKIPMICHAEL;
+ case ALG_CCMP:
+ return P54_CRYPTO_AESCCMP;
+ default:
+ return 0;
+ }
+}
+
static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_queue_stats *current_queue;
+ struct ieee80211_tx_queue_stats *current_queue = NULL;
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
- struct p54_tx_control_allocdata *txhdr;
- size_t padding, len;
- u8 rate;
+ struct p54_hdr *hdr;
+ struct p54_tx_data *txhdr;
+ size_t padding, len, tim_len = 0;
+ int i, j, ridx, ret;
+ u16 hdr_flags = 0, aid = 0;
+ u8 rate, queue, crypt_offset = 0;
u8 cts_rate = 0x20;
+ u8 rc_flags;
+ u8 calculated_tries[4];
+ u8 nrates = 0, nremaining = 8;
- current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
- if (unlikely(current_queue->len > current_queue->limit))
+ queue = skb_get_queue_mapping(skb);
+
+ ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
+ current_queue = &priv->tx_stats[queue];
+ if (unlikely((current_queue->len > current_queue->limit) && ret))
return NETDEV_TX_BUSY;
current_queue->len++;
current_queue->count++;
- if (current_queue->len == current_queue->limit)
+ if ((current_queue->len == current_queue->limit) && ret)
ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
len = skb->len;
- txhdr = (struct p54_tx_control_allocdata *)
- skb_push(skb, sizeof(*txhdr) + padding);
- hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
+ if (info->control.hw_key) {
+ crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ u8 *iv = (u8 *)(skb->data + crypt_offset);
+ /*
+ * The firmware excepts that the IV has to have
+ * this special format
+ */
+ iv[1] = iv[0];
+ iv[0] = iv[2];
+ iv[2] = 0;
+ }
+ }
+
+ txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
if (padding)
- hdr->magic1 = cpu_to_le16(0x4010);
- else
- hdr->magic1 = cpu_to_le16(0x0010);
- hdr->len = cpu_to_le16(len);
- hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
- hdr->retry1 = hdr->retry2 = info->control.retry_limit;
-
- /* TODO: add support for alternate retry TX rates */
- rate = ieee80211_get_tx_rate(dev, info)->hw_value;
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
- rate |= 0x10;
- cts_rate |= 0x10;
+ hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+ hdr->type = cpu_to_le16(aid);
+ hdr->rts_tries = info->control.rates[0].count;
+
+ /*
+ * we register the rates in perfect order, and
+ * RTS/CTS won't happen on 5 GHz
+ */
+ cts_rate = info->control.rts_cts_rate_idx;
+
+ memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+ /* see how many rates got used */
+ for (i = 0; i < 4; i++) {
+ if (info->control.rates[i].idx < 0)
+ break;
+ nrates++;
+ }
+
+ /* limit tries to 8/nrates per rate */
+ for (i = 0; i < nrates; i++) {
+ /*
+ * The magic expression here is equivalent to 8/nrates for
+ * all values that matter, but avoids division and jumps.
+ * Note that nrates can only take the values 1 through 4.
+ */
+ calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+ info->control.rates[i].count);
+ nremaining -= calculated_tries[i];
}
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
- rate |= 0x40;
- cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
- rate |= 0x20;
- cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+
+ /* if there are tries left, distribute from back to front */
+ for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+ int tmp = info->control.rates[i].count - calculated_tries[i];
+
+ if (tmp <= 0)
+ continue;
+ /* RC requested more tries at this rate */
+
+ tmp = min_t(int, tmp, nremaining);
+ calculated_tries[i] += tmp;
+ nremaining -= tmp;
+ }
+
+ ridx = 0;
+ for (i = 0; i < nrates && ridx < 8; i++) {
+ /* we register the rates in perfect order */
+ rate = info->control.rates[i].idx;
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate += 4;
+
+ /* store the count we actually calculated for TX status */
+ info->control.rates[i].count = calculated_tries[i];
+
+ rc_flags = info->control.rates[i].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+ rate |= 0x10;
+ cts_rate |= 0x10;
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ rate |= 0x40;
+ else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+ rate |= 0x20;
+ for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+ txhdr->rateset[ridx] = rate;
+ ridx++;
+ }
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+ /* TODO: enable bursting */
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->tries = ridx;
+ txhdr->rts_rate_idx = 0;
+ if (info->control.hw_key) {
+ crypt_offset += info->control.hw_key->iv_len;
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+ memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ if (unlikely(skb_tailroom(skb) < 12))
+ goto err;
+ /* reserve space for the MIC key */
+ len += 8;
+ memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+ [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+ }
+ /* reserve some space for ICV */
+ len += info->control.hw_key->icv_len;
+ } else {
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
}
- memset(txhdr->rateset, rate, 8);
- txhdr->key_type = 0;
- txhdr->key_len = 0;
- txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+ txhdr->crypt_offset = crypt_offset;
+ txhdr->hw_queue = queue;
+ if (current_queue)
+ txhdr->backlog = current_queue->len;
+ else
+ txhdr->backlog = 0;
+ memset(txhdr->durations, 0, sizeof(txhdr->durations));
txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
2 : info->antenna_sel_tx - 1;
txhdr->output_power = priv->output_power;
- txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 0 : cts_rate;
+ txhdr->cts_rate = cts_rate;
if (padding)
txhdr->align[0] = padding;
- /* FIXME: The sequence that follows is needed for this driver to
- * work with mac80211 since "mac80211: fix TX sequence numbers".
- * As with the temporary code in rt2x00, changes will be needed
- * to get proper sequence numbers on beacons. In addition, this
- * patch places the sequence number in the hardware state, which
- * limits us to a single virtual state.
- */
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- priv->seqno += 0x10;
- ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
- }
+ hdr->len = cpu_to_le16(len);
/* modifies skb->cb and with it info, so must be last! */
- p54_assign_address(dev, skb, hdr, skb->len);
+ if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
+ goto err;
+ priv->tx(dev, skb);
+
+ queue_delayed_work(dev->workqueue, &priv->work,
+ msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
- priv->tx(dev, hdr, skb->len, 0);
return 0;
+
+ err:
+ skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
+ if (current_queue) {
+ current_queue->len--;
+ current_queue->count--;
+ }
+ return NETDEV_TX_BUSY;
}
-static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
- const u8 *bssid)
+static int p54_setup_mac(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_filter *filter;
- size_t data_len;
+ struct sk_buff *skb;
+ struct p54_setup_mac *setup;
+ u16 mode;
- hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
- priv->tx_hdr_len, GFP_ATOMIC);
- if (!hdr)
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) +
+ sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP,
+ GFP_ATOMIC);
+ if (!skb)
return -ENOMEM;
- hdr = (void *)hdr + priv->tx_hdr_len;
-
- filter = (struct p54_tx_control_filter *) hdr->data;
- hdr->magic1 = cpu_to_le16(0x8001);
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
-
- priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
- memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN);
- if (!bssid)
- memset(filter->bssid, ~0, ETH_ALEN);
- else
- memcpy(filter->bssid, bssid, ETH_ALEN);
-
- filter->rx_antenna = priv->rx_antenna;
+ setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+ if (dev->conf.radio_enabled) {
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ mode = P54_FILTER_TYPE_STATION;
+ break;
+ case NL80211_IFTYPE_AP:
+ mode = P54_FILTER_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ mode = P54_FILTER_TYPE_IBSS;
+ break;
+ default:
+ mode = P54_FILTER_TYPE_NONE;
+ break;
+ }
+ if (priv->filter_flags & FIF_PROMISC_IN_BSS)
+ mode |= P54_FILTER_TYPE_TRANSPARENT;
+ } else
+ mode = P54_FILTER_TYPE_RX_DISABLED;
+ setup->mac_mode = cpu_to_le16(mode);
+ memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+ setup->rx_antenna = 2; /* automatic */
+ setup->rx_align = 0;
if (priv->fw_var < 0x500) {
- data_len = P54_TX_CONTROL_FILTER_V1_LEN;
- filter->v1.basic_rate_mask = cpu_to_le32(0x15F);
- filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
- filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
- filter->v1.rxhw = cpu_to_le16(priv->rxhw);
- filter->v1.wakeup_timer = cpu_to_le16(500);
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(setup->v1.rts_rates, 0, 8);
+ setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v1.unalloc0 = cpu_to_le16(0);
} else {
- data_len = P54_TX_CONTROL_FILTER_V2_LEN;
- filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
- filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
- filter->v2.rxhw = cpu_to_le16(priv->rxhw);
- filter->v2.timer = cpu_to_le16(1000);
+ setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v2.truncate = cpu_to_le16(48896);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ setup->v2.sbss_offset = 0;
+ setup->v2.mcast_window = 0;
+ setup->v2.rx_rssi_threshold = 0;
+ setup->v2.rx_ed_threshold = 0;
+ setup->v2.ref_clock = cpu_to_le32(644245094);
+ setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+ setup->v2.osc_start_delay = cpu_to_le16(65535);
}
-
- hdr->len = cpu_to_le16(data_len);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
- priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
+ priv->tx(dev, skb);
return 0;
}
-static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_channel *chan;
+ struct sk_buff *skb;
+ struct p54_scan *chan;
unsigned int i;
- size_t data_len;
void *entry;
+ __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
+ int band = dev->conf.channel->band;
- hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
- priv->tx_hdr_len, GFP_KERNEL);
- if (!hdr)
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
+ sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
+ GFP_ATOMIC);
+ if (!skb)
return -ENOMEM;
- hdr = (void *)hdr + priv->tx_hdr_len;
-
- chan = (struct p54_tx_control_channel *) hdr->data;
-
- hdr->magic1 = cpu_to_le16(0x8001);
-
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
-
- chan->flags = cpu_to_le16(0x1);
- chan->dwell = cpu_to_le16(0x0);
+ chan = (struct p54_scan *) skb_put(skb, sizeof(*chan));
+ memset(chan->padding1, 0, sizeof(chan->padding1));
+ chan->mode = cpu_to_le16(mode);
+ chan->dwell = cpu_to_le16(dwell);
for (i = 0; i < priv->iq_autocal_len; i++) {
if (priv->iq_autocal[i].freq != freq)
@@ -990,61 +1562,50 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
}
entry += sizeof(__le16);
- chan->pa_points_per_curve =
- min(priv->curve_data->points_per_channel, (u8) 8);
-
- memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
- chan->pa_points_per_curve);
+ chan->pa_points_per_curve = 8;
+ memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memcpy(chan->curve_data, entry,
+ sizeof(struct p54_pa_curve_data_sample) *
+ min((u8)8, priv->curve_data->points_per_channel));
break;
}
if (priv->fw_var < 0x500) {
- data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
- chan->v1.rssical_mul = cpu_to_le16(130);
- chan->v1.rssical_add = cpu_to_le16(0xfe70);
+ chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+ chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
} else {
- data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
- chan->v2.rssical_mul = cpu_to_le16(130);
- chan->v2.rssical_add = cpu_to_le16(0xfe70);
- chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
+ chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+ chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
+ chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(chan->v2.rts_rates, 0, 8);
}
-
- hdr->len = cpu_to_le16(data_len);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
- priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
+ priv->tx(dev, skb);
return 0;
err:
printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
- kfree(hdr);
+ kfree_skb(skb);
return -EINVAL;
}
static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_led *led;
+ struct sk_buff *skb;
+ struct p54_led *led;
- hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
- priv->tx_hdr_len, GFP_KERNEL);
- if (!hdr)
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) +
+ sizeof(struct p54_hdr), P54_CONTROL_TYPE_LED,
+ GFP_ATOMIC);
+ if (!skb)
return -ENOMEM;
- hdr = (void *)hdr + priv->tx_hdr_len;
- hdr->magic1 = cpu_to_le16(0x8001);
- hdr->len = cpu_to_le16(sizeof(*led));
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
-
- led = (struct p54_tx_control_led *) hdr->data;
+ led = (struct p54_led *)skb_put(skb, sizeof(*led));
led->mode = cpu_to_le16(mode);
led->led_permanent = cpu_to_le16(link);
led->led_temporary = cpu_to_le16(act);
led->duration = cpu_to_le16(1000);
-
- priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
-
+ priv->tx(dev, skb);
return 0;
}
@@ -1056,88 +1617,144 @@ do { \
queue.txop = cpu_to_le16(_txop); \
} while(0)
-static void p54_init_vdcf(struct ieee80211_hw *dev)
+static int p54_set_edcf(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_vdcf *vdcf;
-
- /* all USB V1 adapters need a extra headroom */
- hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
- hdr->magic1 = cpu_to_le16(0x8001);
- hdr->len = cpu_to_le16(sizeof(*vdcf));
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
- hdr->req_id = cpu_to_le32(priv->rx_start);
-
- vdcf = (struct p54_tx_control_vdcf *) hdr->data;
-
- P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47);
- P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94);
- P54_SET_QUEUE(vdcf->queue[2], 0x0003, 0x000f, 0x03ff, 0);
- P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0);
+ struct sk_buff *skb;
+ struct p54_edcf *edcf;
+
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) +
+ sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT,
+ GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+ if (priv->use_short_slot) {
+ edcf->slottime = 9;
+ edcf->sifs = 0x10;
+ edcf->eofpad = 0x00;
+ } else {
+ edcf->slottime = 20;
+ edcf->sifs = 0x0a;
+ edcf->eofpad = 0x06;
+ }
+ /* (see prism54/isl_oid.h for further details) */
+ edcf->frameburst = cpu_to_le16(0);
+ edcf->round_trip_delay = cpu_to_le16(0);
+ edcf->flags = 0;
+ memset(edcf->mapping, 0, sizeof(edcf->mapping));
+ memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+ priv->tx(dev, skb);
+ return 0;
}
-static void p54_set_vdcf(struct ieee80211_hw *dev)
+static int p54_beacon_tim(struct sk_buff *skb)
{
- struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_vdcf *vdcf;
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
- hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf));
+ if (skb->len <= sizeof(mgmt))
+ return -EINVAL;
- vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return -EINVAL;
- if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
- vdcf->slottime = 9;
- vdcf->magic1 = 0x10;
- vdcf->magic2 = 0x00;
- } else {
- vdcf->slottime = 20;
- vdcf->magic1 = 0x0a;
- vdcf->magic2 = 0x06;
- }
+ if (pos[0] == WLAN_EID_TIM) {
+ u8 dtim_len = pos[1];
+ u8 dtim_period = pos[3];
+ u8 *next = pos + 2 + dtim_len;
- /* (see prism54/isl_oid.h for further details) */
- vdcf->frameburst = cpu_to_le16(0);
+ if (dtim_len < 3)
+ return -EINVAL;
+
+ memmove(pos, next, end - next);
- priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+
+ pos = end - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ pos[0] = WLAN_EID_TIM;
+ pos[1] = 3;
+ pos[2] = 0;
+ pos[3] = dtim_period;
+ pos[4] = 0;
+ return 0;
+ }
+ pos += 2 + pos[1];
+ }
+ return 0;
}
-static int p54_start(struct ieee80211_hw *dev)
+static int p54_beacon_update(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif)
{
struct p54_common *priv = dev->priv;
- int err;
-
- if (!priv->cached_vdcf) {
- priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+
- priv->tx_hdr_len + sizeof(struct p54_control_hdr),
- GFP_KERNEL);
+ struct sk_buff *beacon;
+ int ret;
- if (!priv->cached_vdcf)
- return -ENOMEM;
+ if (priv->cached_beacon) {
+ p54_tx_cancel(dev, priv->cached_beacon);
+ /* wait for the last beacon the be freed */
+ msleep(10);
}
- if (!priv->cached_stats) {
- priv->cached_stats = kzalloc(sizeof(struct p54_statistics) +
- priv->tx_hdr_len + sizeof(struct p54_control_hdr),
- GFP_KERNEL);
+ beacon = ieee80211_beacon_get(dev, vif);
+ if (!beacon)
+ return -ENOMEM;
+ ret = p54_beacon_tim(beacon);
+ if (ret)
+ return ret;
+ ret = p54_tx(dev, beacon);
+ if (ret)
+ return ret;
+ priv->cached_beacon = beacon;
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
- if (!priv->cached_stats) {
- kfree(priv->cached_vdcf);
- priv->cached_vdcf = NULL;
- return -ENOMEM;
- }
- }
+ return 0;
+}
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ mutex_lock(&priv->conf_mutex);
err = priv->open(dev);
- if (!err)
- priv->mode = NL80211_IFTYPE_MONITOR;
+ if (err)
+ goto out;
+ P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+ err = p54_set_edcf(dev);
+ if (err)
+ goto out;
+
+ memset(priv->bssid, ~0, ETH_ALEN);
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ err = p54_setup_mac(dev);
+ if (err) {
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ goto out;
+ }
- p54_init_vdcf(dev);
+ queue_delayed_work(dev->workqueue, &priv->work, 0);
- mod_timer(&priv->stats_timer, jiffies + HZ);
+out:
+ mutex_unlock(&priv->conf_mutex);
return err;
}
@@ -1146,12 +1763,18 @@ static void p54_stop(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv;
struct sk_buff *skb;
- del_timer(&priv->stats_timer);
+ mutex_lock(&priv->conf_mutex);
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ cancel_delayed_work_sync(&priv->work);
+ if (priv->cached_beacon)
+ p54_tx_cancel(dev, priv->cached_beacon);
+
+ priv->stop(dev);
while ((skb = skb_dequeue(&priv->tx_queue)))
kfree_skb(skb);
- priv->stop(dev);
+ priv->cached_beacon = NULL;
priv->tsf_high32 = priv->tsf_low32 = 0;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ mutex_unlock(&priv->conf_mutex);
}
static int p54_add_interface(struct ieee80211_hw *dev,
@@ -1159,32 +1782,28 @@ static int p54_add_interface(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- if (priv->mode != NL80211_IFTYPE_MONITOR)
+ mutex_lock(&priv->conf_mutex);
+ if (priv->mode != NL80211_IFTYPE_MONITOR) {
+ mutex_unlock(&priv->conf_mutex);
return -EOPNOTSUPP;
+ }
switch (conf->type) {
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
priv->mode = conf->type;
break;
default:
+ mutex_unlock(&priv->conf_mutex);
return -EOPNOTSUPP;
}
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
-
- p54_set_filter(dev, 0, NULL);
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- p54_set_filter(dev, 1, NULL);
- break;
- default:
- BUG(); /* impossible */
- break;
- }
-
+ p54_setup_mac(dev);
p54_set_leds(dev, 1, 0, 0);
-
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -1192,22 +1811,38 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (priv->cached_beacon)
+ p54_tx_cancel(dev, priv->cached_beacon);
priv->mode = NL80211_IFTYPE_MONITOR;
memset(priv->mac_addr, 0, ETH_ALEN);
- p54_set_filter(dev, 0, NULL);
+ memset(priv->bssid, 0, ETH_ALEN);
+ p54_setup_mac(dev);
+ mutex_unlock(&priv->conf_mutex);
}
-static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
{
int ret;
struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
mutex_lock(&priv->conf_mutex);
- priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
- 2 : conf->antenna_sel_tx - 1;
- priv->output_power = conf->power_level << 2;
- ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
- p54_set_vdcf(dev);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ priv->output_power = conf->power_level << 2;
+ if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
+ ret = p54_setup_mac(dev);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = p54_scan(dev, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ }
+
+out:
mutex_unlock(&priv->conf_mutex);
return ret;
}
@@ -1217,13 +1852,36 @@ static int p54_config_interface(struct ieee80211_hw *dev,
struct ieee80211_if_conf *conf)
{
struct p54_common *priv = dev->priv;
+ int ret = 0;
mutex_lock(&priv->conf_mutex);
- p54_set_filter(dev, 0, conf->bssid);
- p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
- memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ if (conf->changed & IEEE80211_IFCC_BSSID) {
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ ret = p54_setup_mac(dev);
+ if (ret)
+ goto out;
+ }
+
+ if (conf->changed & IEEE80211_IFCC_BEACON) {
+ ret = p54_scan(dev, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ ret = p54_setup_mac(dev);
+ if (ret)
+ goto out;
+ ret = p54_beacon_update(dev, vif);
+ if (ret)
+ goto out;
+ ret = p54_set_edcf(dev);
+ if (ret)
+ goto out;
+ }
+
+ ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0);
+
+out:
mutex_unlock(&priv->conf_mutex);
- return 0;
+ return ret;
}
static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1233,94 +1891,78 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- *total_flags &= FIF_BCN_PRBRESP_PROMISC |
- FIF_PROMISC_IN_BSS |
- FIF_FCSFAIL;
+ *total_flags &= FIF_PROMISC_IN_BSS |
+ (*total_flags & FIF_PROMISC_IN_BSS) ?
+ FIF_FCSFAIL : 0;
priv->filter_flags = *total_flags;
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
- p54_set_filter(dev, le16_to_cpu(priv->filter_type),
- NULL);
- else
- p54_set_filter(dev, le16_to_cpu(priv->filter_type),
- priv->bssid);
- }
-
- if (changed_flags & FIF_PROMISC_IN_BSS) {
- if (*total_flags & FIF_PROMISC_IN_BSS)
- p54_set_filter(dev, le16_to_cpu(priv->filter_type) |
- 0x8, NULL);
- else
- p54_set_filter(dev, le16_to_cpu(priv->filter_type) &
- ~0x8, priv->bssid);
- }
+ if (changed_flags & FIF_PROMISC_IN_BSS)
+ p54_setup_mac(dev);
}
static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct p54_common *priv = dev->priv;
- struct p54_tx_control_vdcf *vdcf;
-
- vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
- ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
+ int ret;
+ mutex_lock(&priv->conf_mutex);
if ((params) && !(queue > 4)) {
- P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(dev);
} else
- return -EINVAL;
-
- p54_set_vdcf(dev);
-
- return 0;
+ ret = -EINVAL;
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
}
static int p54_init_xbow_synth(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_tx_control_xbow_synth *xbow;
+ struct sk_buff *skb;
+ struct p54_xbow_synth *xbow;
- hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) +
- priv->tx_hdr_len, GFP_KERNEL);
- if (!hdr)
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) +
+ sizeof(struct p54_hdr),
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+ GFP_KERNEL);
+ if (!skb)
return -ENOMEM;
- hdr = (void *)hdr + priv->tx_hdr_len;
- hdr->magic1 = cpu_to_le16(0x8001);
- hdr->len = cpu_to_le16(sizeof(*xbow));
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow));
-
- xbow = (struct p54_tx_control_xbow_synth *) hdr->data;
+ xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
xbow->magic1 = cpu_to_le16(0x1);
xbow->magic2 = cpu_to_le16(0x2);
xbow->freq = cpu_to_le16(5390);
-
- priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1);
-
+ memset(xbow->padding, 0, sizeof(xbow->padding));
+ priv->tx(dev, skb);
return 0;
}
-static void p54_statistics_timer(unsigned long data)
+static void p54_work(struct work_struct *work)
{
- struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
- struct p54_common *priv = dev->priv;
- struct p54_control_hdr *hdr;
- struct p54_statistics *stats;
+ struct p54_common *priv = container_of(work, struct p54_common,
+ work.work);
+ struct ieee80211_hw *dev = priv->hw;
+ struct sk_buff *skb;
- BUG_ON(!priv->cached_stats);
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
- hdr = (void *)priv->cached_stats + priv->tx_hdr_len;
- hdr->magic1 = cpu_to_le16(0x8000);
- hdr->len = cpu_to_le16(sizeof(*stats));
- hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats));
+ /*
+ * TODO: walk through tx_queue and do the following tasks
+ * 1. initiate bursts.
+ * 2. cancel stuck frames / reset the device if necessary.
+ */
+
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) +
+ sizeof(struct p54_statistics),
+ P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+ if (!skb)
+ return ;
- priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0);
+ priv->tx(dev, skb);
}
static int p54_get_stats(struct ieee80211_hw *dev,
@@ -1328,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
- del_timer(&priv->stats_timer);
- p54_statistics_timer((unsigned long)dev);
-
- if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(dev->wiphy));
- return -EBUSY;
- }
-
memcpy(stats, &priv->stats, sizeof(*stats));
-
return 0;
}
@@ -1352,14 +1984,133 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev,
return 0;
}
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ priv->use_short_slot = info->use_short_slot;
+ p54_set_edcf(dev);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(dev);
+ if (priv->fw_var >= 0x500)
+ p54_scan(dev, P54_SCAN_EXIT, 0);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(dev);
+ }
+ }
+
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+ const u8 *local_address, const u8 *address,
+ struct ieee80211_key_conf *key)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ struct p54_keycache *rxkey;
+ u8 algo = 0;
+
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ if (cmd == DISABLE_KEY)
+ algo = 0;
+ else {
+ switch (key->alg) {
+ case ALG_TKIP:
+ if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+ BR_DESC_PRIV_CAP_TKIP)))
+ return -EOPNOTSUPP;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_TKIPMICHAEL;
+ break;
+ case ALG_WEP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP))
+ return -EOPNOTSUPP;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_WEP;
+ break;
+ case ALG_CCMP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP))
+ return -EOPNOTSUPP;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_AESCCMP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (key->keyidx > priv->rx_keycache_size) {
+ /*
+ * The device supports the choosen algorithm, but the firmware
+ * does not provide enough key slots to store all of them.
+ * So, incoming frames have to be decoded by the mac80211 stack,
+ * but we can still offload encryption for outgoing frames.
+ */
+
+ return 0;
+ }
+
+ mutex_lock(&priv->conf_mutex);
+ skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) +
+ sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE,
+ GFP_ATOMIC);
+ if (!skb) {
+ mutex_unlock(&priv->conf_mutex);
+ return -ENOMEM;
+ }
+
+ /* TODO: some devices have 4 more free slots for rx keys */
+ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+ rxkey->entry = key->keyidx;
+ rxkey->key_id = key->keyidx;
+ rxkey->key_type = algo;
+ if (address)
+ memcpy(rxkey->mac, address, ETH_ALEN);
+ else
+ memset(rxkey->mac, ~0, ETH_ALEN);
+ if (key->alg != ALG_TKIP) {
+ rxkey->key_len = min((u8)16, key->keylen);
+ memcpy(rxkey->key, key->key, rxkey->key_len);
+ } else {
+ rxkey->key_len = 24;
+ memcpy(rxkey->key, key->key, 16);
+ memcpy(&(rxkey->key[16]), &(key->key
+ [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+ }
+
+ priv->tx(dev, skb);
+ mutex_unlock(&priv->conf_mutex);
+ return 0;
+}
+
static const struct ieee80211_ops p54_ops = {
.tx = p54_tx,
.start = p54_start,
.stop = p54_stop,
.add_interface = p54_add_interface,
.remove_interface = p54_remove_interface,
+ .set_tim = p54_set_tim,
+ .sta_notify = p54_sta_notify,
+ .set_key = p54_set_key,
.config = p54_config,
.config_interface = p54_config_interface,
+ .bss_info_changed = p54_bss_info_changed,
.configure_filter = p54_configure_filter,
.conf_tx = p54_conf_tx,
.get_stats = p54_get_stats,
@@ -1376,32 +2127,43 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
return NULL;
priv = dev->priv;
+ priv->hw = dev;
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
skb_queue_head_init(&priv->tx_queue);
- dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
- IEEE80211_HW_RX_INCLUDES_FCS |
+ dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
dev->channel_change_time = 1000; /* TODO: find actual value */
-
- priv->tx_stats[0].limit = 1;
- priv->tx_stats[1].limit = 1;
- priv->tx_stats[2].limit = 1;
- priv->tx_stats[3].limit = 1;
- priv->tx_stats[4].limit = 5;
+ priv->tx_stats[0].limit = 1; /* Beacon queue */
+ priv->tx_stats[1].limit = 1; /* Probe queue for HW scan */
+ priv->tx_stats[2].limit = 3; /* queue for MLMEs */
+ priv->tx_stats[3].limit = 3; /* Broadcast / MC queue */
+ priv->tx_stats[4].limit = 5; /* Data */
dev->queues = 1;
priv->noise = -94;
- dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
- sizeof(struct p54_tx_control_allocdata);
+ /*
+ * We support at most 8 tries no matter which rate they're at,
+ * we cannot support max_rates * max_rate_tries as we set it
+ * here, but setting it correctly to 4/2 or so would limit us
+ * artificially if the RC algorithm wants just two rates, so
+ * let's say 4/7, we'll redistribute it at TX time, see the
+ * comments there.
+ */
+ dev->max_rates = 4;
+ dev->max_rate_tries = 7;
+ dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+ sizeof(struct p54_tx_data);
mutex_init(&priv->conf_mutex);
init_completion(&priv->eeprom_comp);
- init_completion(&priv->stats_comp);
- setup_timer(&priv->stats_timer, p54_statistics_timer,
- (unsigned long)dev);
+ INIT_DELAYED_WORK(&priv->work, p54_work);
return dev;
}
@@ -1410,11 +2172,9 @@ EXPORT_SYMBOL_GPL(p54_init_common);
void p54_free_common(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
- kfree(priv->cached_stats);
kfree(priv->iq_autocal);
kfree(priv->output_limit);
kfree(priv->curve_data);
- kfree(priv->cached_vdcf);
}
EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 2fa994cfcfe..f5729de83fe 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -7,8 +7,12 @@
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
*
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, 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
@@ -19,9 +23,24 @@ struct bootrec {
__le32 code;
__le32 len;
u32 data[10];
- __le16 rx_mtu;
} __attribute__((packed));
+#define PDR_SYNTH_FRONTEND_MASK 0x0007
+#define PDR_SYNTH_IQ_CAL_MASK 0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0001
+#define PDR_SYNTH_24_GHZ_MASK 0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
+#define PDR_SYNTH_5_GHZ_MASK 0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
+#define PDR_SYNTH_RX_DIV_MASK 0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
+#define PDR_SYNTH_TX_DIV_MASK 0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
+
struct bootrec_exp_if {
__le16 role;
__le16 if_id;
@@ -30,6 +49,13 @@ struct bootrec_exp_if {
__le16 top_compat;
} __attribute__((packed));
+#define BR_DESC_PRIV_CAP_WEP BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
+
struct bootrec_desc {
__le16 modes;
__le16 flags;
@@ -37,8 +63,15 @@ struct bootrec_desc {
__le32 rx_end;
u8 headroom;
u8 tailroom;
- u8 unimportant[6];
+ u8 tx_queues;
+ u8 tx_depth;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
+ u8 time_size;
+ u8 padding;
u8 rates[16];
+ u8 padding2[4];
+ __le16 rx_mtu;
} __attribute__((packed));
#define BR_CODE_MIN 0x80000000
@@ -51,6 +84,31 @@ struct bootrec_desc {
#define BR_CODE_END_OF_BRA 0xFF0000FF
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
+#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
struct pda_entry {
@@ -117,6 +175,11 @@ struct pda_pa_curve_data {
u8 data[0];
} __attribute__ ((packed));
+struct pda_rssi_cal_entry {
+ __le16 mul;
+ __le16 add;
+} __attribute__ ((packed));
+
/*
* this defines the PDR codes used to build PDAs as defined in document
* number 553155. The current implementation mirrors version 1.1 of the
@@ -165,6 +228,19 @@ struct pda_pa_curve_data {
#define PDR_BASEBAND_REGISTERS 0x8000
#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE 0x80
+#define PDR_COUNTRY_CERT_CODE_REAL 0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
+#define PDR_COUNTRY_CERT_BAND 0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
+#define PDR_COUNTRY_CERT_IODOOR 0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
+#define PDR_COUNTRY_CERT_INDEX 0x0F
+
/* stored in skb->cb */
struct memrecord {
u32 start_addr;
@@ -172,41 +248,108 @@ struct memrecord {
};
struct p54_eeprom_lm86 {
- __le16 offset;
- __le16 len;
- u8 data[0];
+ union {
+ struct {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+ } v1;
+ struct {
+ __le32 offset;
+ __le16 len;
+ u8 magic2;
+ u8 pad;
+ u8 magic[4];
+ u8 data[0];
+ } v2;
+ } __attribute__ ((packed));
} __attribute__ ((packed));
-struct p54_rx_hdr {
- __le16 magic;
+enum p54_rx_decrypt_status {
+ P54_DECRYPT_NONE = 0,
+ P54_DECRYPT_OK,
+ P54_DECRYPT_NOKEY,
+ P54_DECRYPT_NOMICHAEL,
+ P54_DECRYPT_NOCKIPMIC,
+ P54_DECRYPT_FAIL_WEP,
+ P54_DECRYPT_FAIL_TKIP,
+ P54_DECRYPT_FAIL_MICHAEL,
+ P54_DECRYPT_FAIL_CKIPKP,
+ P54_DECRYPT_FAIL_CKIPMIC,
+ P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+ __le16 flags;
__le16 len;
__le16 freq;
u8 antenna;
u8 rate;
u8 rssi;
u8 quality;
- u16 unknown2;
+ u8 decrypt_status;
+ u8 rssi_raw;
__le32 tsf32;
__le32 unalloc0;
u8 align[0];
} __attribute__ ((packed));
-struct p54_frame_sent_hdr {
+enum p54_trap_type {
+ P54_TRAP_SCAN = 0,
+ P54_TRAP_TIMER,
+ P54_TRAP_BEACON_TX,
+ P54_TRAP_FAA_RADIO_ON,
+ P54_TRAP_FAA_RADIO_OFF,
+ P54_TRAP_RADAR,
+ P54_TRAP_NO_BEACON,
+ P54_TRAP_TBTT,
+ P54_TRAP_SCO_ENTER,
+ P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+ __le16 event;
+ __le16 frequency;
+} __attribute__ ((packed));
+
+enum p54_frame_sent_status {
+ P54_TX_OK = 0,
+ P54_TX_FAILED,
+ P54_TX_PSM,
+ P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
u8 status;
- u8 retries;
- __le16 ack_rssi;
+ u8 tries;
+ u8 ack_rssi;
+ u8 quality;
__le16 seq;
- u16 rate;
+ u8 antenna;
+ u8 padding;
} __attribute__ ((packed));
-struct p54_tx_control_allocdata {
+enum p54_tx_data_crypt {
+ P54_CRYPTO_NONE = 0,
+ P54_CRYPTO_WEP,
+ P54_CRYPTO_TKIP,
+ P54_CRYPTO_TKIPMICHAEL,
+ P54_CRYPTO_CCX_WEPMIC,
+ P54_CRYPTO_CCX_KPMIC,
+ P54_CRYPTO_CCX_KP,
+ P54_CRYPTO_AESCCMP
+};
+
+struct p54_tx_data {
u8 rateset[8];
- u8 unalloc0[2];
+ u8 rts_rate_idx;
+ u8 crypt_offset;
u8 key_type;
u8 key_len;
u8 key[16];
u8 hw_queue;
- u8 unalloc1[9];
+ u8 backlog;
+ __le16 durations[4];
u8 tx_antenna;
u8 output_power;
u8 cts_rate;
@@ -214,8 +357,23 @@ struct p54_tx_control_allocdata {
u8 align[0];
} __attribute__ ((packed));
-struct p54_tx_control_filter {
- __le16 filter_type;
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE 0
+#define P54_FILTER_TYPE_STATION BIT(0)
+#define P54_FILTER_TYPE_IBSS BIT(1)
+#define P54_FILTER_TYPE_AP BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE BIT(5)
+#define P54_FILTER_TYPE_NOACK BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
+
+struct p54_setup_mac {
+ __le16 mac_mode;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u8 rx_antenna;
@@ -235,17 +393,29 @@ struct p54_tx_control_filter {
__le16 max_rx;
__le16 rxhw;
__le16 timer;
- __le16 unalloc0;
- __le32 unalloc1;
+ __le16 truncate;
+ __le32 basic_rate_mask;
+ u8 sbss_offset;
+ u8 mcast_window;
+ u8 rx_rssi_threshold;
+ u8 rx_ed_threshold;
+ __le32 ref_clock;
+ __le16 lpf_bandwidth;
+ __le16 osc_start_delay;
} v2 __attribute__ ((packed));
} __attribute__ ((packed));
} __attribute__ ((packed));
-#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter))
-#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8)
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-struct p54_tx_control_channel {
- __le16 flags;
+#define P54_SCAN_EXIT BIT(0)
+#define P54_SCAN_TRAP BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan {
+ __le16 mode;
__le16 dwell;
u8 padding1[20];
struct pda_iq_autocal_entry iq_autocal;
@@ -261,45 +431,35 @@ struct p54_tx_control_channel {
u8 dup_16qam;
u8 dup_64qam;
union {
- struct {
- __le16 rssical_mul;
- __le16 rssical_add;
- } v1 __attribute__ ((packed));
+ struct pda_rssi_cal_entry v1_rssi;
struct {
__le32 basic_rate_mask;
- u8 rts_rates[8];
- __le16 rssical_mul;
- __le16 rssical_add;
+ u8 rts_rates[8];
+ struct pda_rssi_cal_entry rssi;
} v2 __attribute__ ((packed));
} __attribute__ ((packed));
} __attribute__ ((packed));
-#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12)
-#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel))
+#define P54_SCAN_V1_LEN 0x70
+#define P54_SCAN_V2_LEN 0x7c
-struct p54_tx_control_led {
+struct p54_led {
__le16 mode;
__le16 led_temporary;
__le16 led_permanent;
__le16 duration;
} __attribute__ ((packed));
-struct p54_tx_vdcf_queues {
- __le16 aifs;
- __le16 cwmin;
- __le16 cwmax;
- __le16 txop;
-} __attribute__ ((packed));
-
-struct p54_tx_control_vdcf {
- u8 padding;
+struct p54_edcf {
+ u8 flags;
u8 slottime;
- u8 magic1;
- u8 magic2;
- struct p54_tx_vdcf_queues queue[8];
- u8 pad2[4];
+ u8 sifs;
+ u8 eofpad;
+ struct p54_edcf_queue_param queue[8];
+ u8 mapping[4];
__le16 frameburst;
+ __le16 round_trip_delay;
} __attribute__ ((packed));
struct p54_statistics {
@@ -312,14 +472,103 @@ struct p54_statistics {
__le32 tsf32;
__le32 airtime;
__le32 noise;
- __le32 unkn[10]; /* CCE / CCA / RADAR */
+ __le32 sample_noise[8];
+ __le32 sample_cca;
+ __le32 sample_tx;
} __attribute__ ((packed));
-struct p54_tx_control_xbow_synth {
+struct p54_xbow_synth {
__le16 magic1;
__le16 magic2;
__le16 freq;
u32 padding[5];
} __attribute__ ((packed));
+struct p54_timer {
+ __le32 interval;
+} __attribute__ ((packed));
+
+struct p54_keycache {
+ u8 entry;
+ u8 key_id;
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[24];
+} __attribute__ ((packed));
+
+struct p54_burst {
+ u8 flags;
+ u8 queue;
+ u8 backlog;
+ u8 pad;
+ __le16 durations[32];
+} __attribute__ ((packed));
+
+struct p54_psm_interval {
+ __le16 interval;
+ __le16 periods;
+} __attribute__ ((packed));
+
+#define P54_PSM BIT(0)
+#define P54_PSM_DTIM BIT(1)
+#define P54_PSM_MCBC BIT(2)
+#define P54_PSM_CHECKSUM BIT(3)
+#define P54_PSM_SKIP_MORE_DATA BIT(4)
+#define P54_PSM_BEACON_TIMEOUT BIT(5)
+#define P54_PSM_HFOSLEEP BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
+#define P54_PSM_LPIT BIT(8)
+#define P54_PSM_BF_UCAST_SKIP BIT(9)
+#define P54_PSM_BF_MCAST_SKIP BIT(10)
+
+struct p54_psm {
+ __le16 mode;
+ __le16 aid;
+ struct p54_psm_interval intervals[4];
+ u8 beacon_rssi_skip_max;
+ u8 rssi_delta_threshold;
+ u8 nr;
+ u8 exclude[1];
+} __attribute__ ((packed));
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+ __le16 filter_enable;
+ __le16 num_address;
+ u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __attribute__ ((packed));
+
+struct p54_txcancel {
+ __le32 req_id;
+} __attribute__ ((packed));
+
+struct p54_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __attribute__ ((packed));
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+ u8 count;
+ u8 padding[3];
+ __le16 entry[8];
+} __attribute__ ((packed));
+
+struct p54_cce_quiet {
+ __le32 period;
+} __attribute__ ((packed));
+
+struct p54_bt_balancer {
+ __le16 prio_thresh;
+ __le16 acl_thresh;
+} __attribute__ ((packed));
+
+struct p54_arp_table {
+ __le16 filter_enable;
+ u8 ipv4_addr[4];
+} __attribute__ ((packed));
+
#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 88b3cad8b65..aa367a0ddc4 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_DESCRIPTION("Prism54 PCI wireless driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54pci");
+MODULE_FIRMWARE("isl3886pci");
static struct pci_device_id p54p_table[] __devinitdata = {
/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
@@ -46,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table);
static int p54p_upload_firmware(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
- const struct firmware *fw_entry = NULL;
__le32 reg;
int err;
__le32 *data;
@@ -72,21 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_WRITE(ctrl_stat, reg);
wmb();
- err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
- if (err) {
- printk(KERN_ERR "%s (p54pci): cannot find firmware "
- "(isl3886)\n", pci_name(priv->pdev));
- return err;
- }
+ /* wait for the firmware to reset properly */
+ mdelay(10);
- err = p54_parse_firmware(dev, fw_entry);
- if (err) {
- release_firmware(fw_entry);
+ err = p54_parse_firmware(dev, priv->firmware);
+ if (err)
return err;
- }
- data = (__le32 *) fw_entry->data;
- remains = fw_entry->size;
+ data = (__le32 *) priv->firmware->data;
+ remains = priv->firmware->size;
device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
while (remains) {
u32 i = 0;
@@ -104,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
P54P_READ(int_enable);
}
- release_firmware(fw_entry);
-
reg = P54P_READ(ctrl_stat);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
@@ -235,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
while (i != idx) {
desc = &ring[i];
- kfree(tx_buf[i]);
+ if (tx_buf[i])
+ if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
+ p54_free_skb(dev, tx_buf[i]);
tx_buf[i] = NULL;
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@@ -306,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
return reg ? IRQ_HANDLED : IRQ_NONE;
}
-static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
- size_t len, int free_on_tx)
+static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
@@ -322,28 +315,21 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data);
- mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
+ priv->tx_buf_data[i] = skb;
+ mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
desc = &ring_control->tx_data[i];
desc->host_addr = cpu_to_le32(mapping);
- desc->device_addr = data->req_id;
- desc->len = cpu_to_le16(len);
+ desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
+ desc->len = cpu_to_le16(skb->len);
desc->flags = 0;
wmb();
ring_control->host_idx[1] = cpu_to_le32(idx + 1);
-
- if (free_on_tx)
- priv->tx_buf_data[i] = data;
-
spin_unlock_irqrestore(&priv->lock, flags);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
P54P_READ(dev_int);
-
- /* FIXME: unlikely to happen because the device usually runs out of
- memory before we fill the ring up, but we can make it impossible */
- if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2)
- printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
}
static void p54p_stop(struct ieee80211_hw *dev)
@@ -393,7 +379,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
- kfree(priv->tx_buf_data[i]);
+ p54_free_skb(dev, priv->tx_buf_data[i]);
priv->tx_buf_data[i] = NULL;
}
@@ -405,7 +391,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
- kfree(priv->tx_buf_mgmt[i]);
+ p54_free_skb(dev, priv->tx_buf_mgmt[i]);
priv->tx_buf_mgmt[i] = NULL;
}
@@ -481,7 +467,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
struct ieee80211_hw *dev;
unsigned long mem_addr, mem_len;
int err;
- DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if (err) {
@@ -495,15 +480,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
if (mem_len < sizeof(struct p54p_csr)) {
printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
pci_name(pdev));
- pci_disable_device(pdev);
- return err;
+ goto err_disable_dev;
}
err = pci_request_regions(pdev, "p54pci");
if (err) {
printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
pci_name(pdev));
- return err;
+ goto err_disable_dev;
}
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
@@ -556,6 +540,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
+ err = request_firmware(&priv->firmware, "isl3886pci",
+ &priv->pdev->dev);
+ if (err) {
+ printk(KERN_ERR "%s (p54pci): cannot find firmware "
+ "(isl3886pci)\n", pci_name(priv->pdev));
+ err = request_firmware(&priv->firmware, "isl3886",
+ &priv->pdev->dev);
+ if (err)
+ goto err_free_common;
+ }
+
err = p54p_open(dev);
if (err)
goto err_free_common;
@@ -574,6 +569,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
return 0;
err_free_common:
+ release_firmware(priv->firmware);
p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -587,6 +583,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_reg:
pci_release_regions(pdev);
+ err_disable_dev:
pci_disable_device(pdev);
return err;
}
@@ -601,6 +598,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
ieee80211_unregister_hw(dev);
priv = dev->priv;
+ release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
p54_free_common(dev);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 4a6778070af..fbb683953fb 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -93,7 +93,7 @@ struct p54p_priv {
struct pci_dev *pdev;
struct p54p_csr __iomem *map;
struct tasklet_struct rx_tasklet;
-
+ const struct firmware *firmware;
spinlock_t lock;
struct p54p_ring_control *ring_control;
dma_addr_t ring_control_dma;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 75d749bccb0..c44a200059d 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_DESCRIPTION("Prism54 USB wireless driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("prism54usb");
+MODULE_FIRMWARE("isl3886usb");
+MODULE_FIRMWARE("isl3887usb");
static struct usb_device_id p54u_table[] __devinitdata = {
/* Version 1 devices (pci chip + net2280) */
@@ -84,13 +86,13 @@ static void p54u_rx_cb(struct urb *urb)
struct ieee80211_hw *dev = info->dev;
struct p54u_priv *priv = dev->priv;
+ skb_unlink(skb, &priv->rx_queue);
+
if (unlikely(urb->status)) {
- info->urb = NULL;
- usb_free_urb(urb);
+ dev_kfree_skb_irq(skb);
return;
}
- skb_unlink(skb, &priv->rx_queue);
skb_put(skb, urb->actual_length);
if (priv->hw_type == P54U_NET2280)
@@ -103,7 +105,6 @@ static void p54u_rx_cb(struct urb *urb)
if (p54_rx(dev, skb)) {
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
if (unlikely(!skb)) {
- usb_free_urb(urb);
/* TODO check rx queue length and refill *somewhere* */
return;
}
@@ -113,7 +114,6 @@ static void p54u_rx_cb(struct urb *urb)
info->dev = dev;
urb->transfer_buffer = skb_tail_pointer(skb);
urb->context = skb;
- skb_queue_tail(&priv->rx_queue, skb);
} else {
if (priv->hw_type == P54U_NET2280)
skb_push(skb, priv->common.tx_hdr_len);
@@ -128,40 +128,56 @@ static void p54u_rx_cb(struct urb *urb)
WARN_ON(1);
urb->transfer_buffer = skb_tail_pointer(skb);
}
-
- skb_queue_tail(&priv->rx_queue, skb);
}
-
- usb_submit_urb(urb, GFP_ATOMIC);
+ skb_queue_tail(&priv->rx_queue, skb);
+ usb_anchor_urb(urb, &priv->submitted);
+ if (usb_submit_urb(urb, GFP_ATOMIC)) {
+ skb_unlink(skb, &priv->rx_queue);
+ usb_unanchor_urb(urb);
+ dev_kfree_skb_irq(skb);
+ }
}
static void p54u_tx_cb(struct urb *urb)
{
- usb_free_urb(urb);
+ struct sk_buff *skb = urb->context;
+ struct ieee80211_hw *dev = (struct ieee80211_hw *)
+ usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+ struct p54u_priv *priv = dev->priv;
+
+ skb_pull(skb, priv->common.tx_hdr_len);
+ if (FREE_AFTER_TX(skb))
+ p54_free_skb(dev, skb);
}
-static void p54u_tx_free_cb(struct urb *urb)
+static void p54u_tx_dummy_cb(struct urb *urb) { }
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
{
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
+ struct p54u_priv *priv = dev->priv;
+ usb_kill_anchored_urbs(&priv->submitted);
}
static int p54u_init_urbs(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
- struct urb *entry;
+ struct urb *entry = NULL;
struct sk_buff *skb;
struct p54u_rx_info *info;
+ int ret = 0;
while (skb_queue_len(&priv->rx_queue) < 32) {
skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
- if (!skb)
- break;
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err;
+ }
entry = usb_alloc_urb(0, GFP_KERNEL);
if (!entry) {
- kfree_skb(skb);
- break;
+ ret = -ENOMEM;
+ goto err;
}
+
usb_fill_bulk_urb(entry, priv->udev,
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
skb_tail_pointer(skb),
@@ -170,33 +186,32 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
info->urb = entry;
info->dev = dev;
skb_queue_tail(&priv->rx_queue, skb);
- usb_submit_urb(entry, GFP_KERNEL);
+
+ usb_anchor_urb(entry, &priv->submitted);
+ ret = usb_submit_urb(entry, GFP_KERNEL);
+ if (ret) {
+ skb_unlink(skb, &priv->rx_queue);
+ usb_unanchor_urb(entry);
+ goto err;
+ }
+ usb_free_urb(entry);
+ entry = NULL;
}
return 0;
-}
-
-static void p54u_free_urbs(struct ieee80211_hw *dev)
-{
- struct p54u_priv *priv = dev->priv;
- struct p54u_rx_info *info;
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&priv->rx_queue))) {
- info = (struct p54u_rx_info *) skb->cb;
- if (!info->urb)
- continue;
-
- usb_kill_urb(info->urb);
- kfree_skb(skb);
- }
+ err:
+ usb_free_urb(entry);
+ kfree_skb(skb);
+ p54u_free_urbs(dev);
+ return ret;
}
-static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
- size_t len, int free_on_tx)
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
struct urb *addr_urb, *data_urb;
+ int err = 0;
addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!addr_urb)
@@ -209,59 +224,85 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
}
usb_fill_bulk_urb(addr_urb, priv->udev,
- usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
- sizeof(data->req_id), p54u_tx_cb, dev);
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+ &((struct p54_hdr *)skb->data)->req_id, 4,
+ p54u_tx_dummy_cb, dev);
usb_fill_bulk_urb(data_urb, priv->udev,
- usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
- free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+ skb->data, skb->len, p54u_tx_cb, skb);
+
+ usb_anchor_urb(addr_urb, &priv->submitted);
+ err = usb_submit_urb(addr_urb, GFP_ATOMIC);
+ if (err) {
+ usb_unanchor_urb(addr_urb);
+ goto out;
+ }
- usb_submit_urb(addr_urb, GFP_ATOMIC);
- usb_submit_urb(data_urb, GFP_ATOMIC);
+ usb_anchor_urb(addr_urb, &priv->submitted);
+ err = usb_submit_urb(data_urb, GFP_ATOMIC);
+ if (err)
+ usb_unanchor_urb(data_urb);
+
+ out:
+ usb_free_urb(addr_urb);
+ usb_free_urb(data_urb);
+
+ if (err)
+ p54_free_skb(dev, skb);
}
-static __le32 p54u_lm87_chksum(const u32 *data, size_t length)
+static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
{
u32 chk = 0;
length >>= 2;
while (length--) {
- chk ^= *data++;
+ chk ^= le32_to_cpu(*data++);
chk = (chk >> 5) ^ (chk << 3);
}
return cpu_to_le32(chk);
}
-static void p54u_tx_lm87(struct ieee80211_hw *dev,
- struct p54_control_hdr *data,
- size_t len, int free_on_tx)
+static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
struct urb *data_urb;
- struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
+ struct lm87_tx_hdr *hdr;
+ __le32 checksum;
+ __le32 addr = ((struct p54_hdr *)skb->data)->req_id;
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!data_urb)
return;
- hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
- hdr->device_addr = data->req_id;
+ checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
+ hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr));
+ hdr->chksum = checksum;
+ hdr->device_addr = addr;
usb_fill_bulk_urb(data_urb, priv->udev,
- usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
- len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
- dev);
-
- usb_submit_urb(data_urb, GFP_ATOMIC);
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+ skb->data, skb->len, p54u_tx_cb, skb);
+
+ usb_anchor_urb(data_urb, &priv->submitted);
+ if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
+ usb_unanchor_urb(data_urb);
+ skb_pull(skb, sizeof(*hdr));
+ p54_free_skb(dev, skb);
+ }
+ usb_free_urb(data_urb);
}
-static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
- size_t len, int free_on_tx)
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
struct urb *int_urb, *data_urb;
struct net2280_tx_hdr *hdr;
struct net2280_reg_write *reg;
+ int err = 0;
+ __le32 addr = ((struct p54_hdr *) skb->data)->req_id;
+ __le16 len = cpu_to_le16(skb->len);
reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg)
@@ -284,21 +325,47 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da
reg->addr = cpu_to_le32(P54U_DEV_BASE);
reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
- len += sizeof(*data);
- hdr = (void *)data - sizeof(*hdr);
+ hdr = (void *)skb_push(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(*hdr));
- hdr->device_addr = data->req_id;
- hdr->len = cpu_to_le16(len);
+ hdr->len = len;
+ hdr->device_addr = addr;
usb_fill_bulk_urb(int_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
- p54u_tx_free_cb, dev);
- usb_submit_urb(int_urb, GFP_ATOMIC);
+ p54u_tx_dummy_cb, dev);
+
+ /*
+ * This flag triggers a code path in the USB subsystem that will
+ * free what's inside the transfer_buffer after the callback routine
+ * has completed.
+ */
+ int_urb->transfer_flags |= URB_FREE_BUFFER;
usb_fill_bulk_urb(data_urb, priv->udev,
- usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
- free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
- usb_submit_urb(data_urb, GFP_ATOMIC);
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+ skb->data, skb->len, p54u_tx_cb, skb);
+
+ usb_anchor_urb(int_urb, &priv->submitted);
+ err = usb_submit_urb(int_urb, GFP_ATOMIC);
+ if (err) {
+ usb_unanchor_urb(int_urb);
+ goto out;
+ }
+
+ usb_anchor_urb(data_urb, &priv->submitted);
+ err = usb_submit_urb(data_urb, GFP_ATOMIC);
+ if (err) {
+ usb_unanchor_urb(data_urb);
+ goto out;
+ }
+ out:
+ usb_free_urb(int_urb);
+ usb_free_urb(data_urb);
+
+ if (err) {
+ skb_pull(skb, sizeof(*hdr));
+ p54_free_skb(dev, skb);
+ }
}
static int p54u_write(struct p54u_priv *priv,
@@ -375,7 +442,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
if (!buf) {
- printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
+ dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware"
+ "upload buffer!\n");
err = -ENOMEM;
goto err_bufalloc;
}
@@ -383,14 +451,18 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
memcpy(buf, start_string, 4);
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
if (err) {
- printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
+ dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err);
goto err_reset;
}
- err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+ err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
if (err) {
- printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
- goto err_req_fw_failed;
+ dev_err(&priv->udev->dev, "p54usb: cannot find firmware "
+ "(isl3887usb)\n");
+ err = request_firmware(&fw_entry, "isl3887usb_bare",
+ &priv->udev->dev);
+ if (err)
+ goto err_req_fw_failed;
}
err = p54_parse_firmware(dev, fw_entry);
@@ -441,7 +513,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
if (err) {
- printk(KERN_ERR "p54usb: firmware upload failed!\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware "
+ "upload failed!\n");
goto err_upload_failed;
}
@@ -452,10 +525,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
if (err) {
- printk(KERN_ERR "p54usb: firmware upload failed!\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
goto err_upload_failed;
}
-
timeout = jiffies + msecs_to_jiffies(1000);
while (!(err = usb_bulk_msg(priv->udev,
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
@@ -463,25 +535,27 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
break;
if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
- printk(KERN_INFO "p54usb: firmware upload failed!\n");
err = -EINVAL;
break;
}
if (time_after(jiffies, timeout)) {
- printk(KERN_ERR "p54usb: firmware boot timed out!\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware boot "
+ "timed out!\n");
err = -ETIMEDOUT;
break;
}
}
- if (err)
+ if (err) {
+ dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
goto err_upload_failed;
+ }
buf[0] = 'g';
buf[1] = '\r';
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
if (err) {
- printk(KERN_ERR "p54usb: firmware boot failed!\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
goto err_upload_failed;
}
@@ -521,15 +595,21 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
buf = kmalloc(512, GFP_KERNEL);
if (!buf) {
- printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware buffer "
+ "alloc failed!\n");
return -ENOMEM;
}
- err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+ err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
if (err) {
- printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
- kfree(buf);
- return err;
+ dev_err(&priv->udev->dev, "(p54usb) cannot find firmware "
+ "(isl3886usb)\n");
+ err = request_firmware(&fw_entry, "isl3890usb",
+ &priv->udev->dev);
+ if (err) {
+ kfree(buf);
+ return err;
+ }
}
err = p54_parse_firmware(dev, fw_entry);
@@ -648,8 +728,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
if (err) {
- printk(KERN_ERR "p54usb: firmware block upload "
- "failed\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware block "
+ "upload failed\n");
goto fail;
}
@@ -682,8 +762,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
0x002C | (unsigned long)&devreg->direct_mem_win);
if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
- printk(KERN_ERR "p54usb: firmware DMA transfer "
- "failed\n");
+ dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
+ "transfer failed\n");
goto fail;
}
@@ -786,11 +866,11 @@ static int __devinit p54u_probe(struct usb_interface *intf,
struct p54u_priv *priv;
int err;
unsigned int i, recognized_pipes;
- DECLARE_MAC_BUF(mac);
dev = p54_init_common(sizeof(*priv));
+
if (!dev) {
- printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
+ dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
return -ENOMEM;
}
@@ -842,6 +922,7 @@ static int __devinit p54u_probe(struct usb_interface *intf,
goto err_free_dev;
skb_queue_head_init(&priv->rx_queue);
+ init_usb_anchor(&priv->submitted);
p54u_open(dev);
err = p54_read_eeprom(dev);
@@ -851,7 +932,7 @@ static int __devinit p54u_probe(struct usb_interface *intf,
err = ieee80211_register_hw(dev);
if (err) {
- printk(KERN_ERR "p54usb: Cannot register netdevice\n");
+ dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
goto err_free_dev;
}
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index 5b8fe91379c..54ee738bf2a 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -133,6 +133,7 @@ struct p54u_priv {
spinlock_t lock;
struct sk_buff_head rx_queue;
+ struct usb_anchor submitted;
};
#endif /* P54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 16e68f4b654..57a150a22de 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2028,12 +2028,11 @@ static void
format_event(islpci_private *priv, char *dest, const char *str,
const struct obj_mlme *mlme, u16 *length, int error)
{
- DECLARE_MAC_BUF(mac);
int n = snprintf(dest, IW_CUSTOM_MAX,
- "%s %s %s %s (%2.2X)",
+ "%s %s %pM %s (%2.2X)",
str,
((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
- print_mac(mac, mlme->address),
+ mlme->address,
(error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
: ""), mlme->code);
BUG_ON(n > IW_CUSTOM_MAX);
@@ -2113,7 +2112,6 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
- DECLARE_MAC_BUF(mac);
if (wpa_ie_len > MAX_WPA_IE_LEN)
wpa_ie_len = MAX_WPA_IE_LEN;
@@ -2154,7 +2152,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
bss->last_update = jiffies;
} else {
printk(KERN_DEBUG "Failed to add BSS WPA entry for "
- "%s\n", print_mac(mac, bssid));
+ "%pM\n", bssid);
}
/* expire old entries from WPA list */
@@ -2219,7 +2217,6 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
{
struct ieee80211_beacon_phdr *hdr;
u8 *pos, *end;
- DECLARE_MAC_BUF(mac);
if (!priv->wpa)
return;
@@ -2230,7 +2227,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
while (pos < end) {
if (pos + 2 + pos[1] > end) {
printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
- "for %s\n", print_mac(mac, addr));
+ "for %pM\n", addr);
return;
}
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
@@ -2269,7 +2266,6 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
size_t len = 0; /* u16, better? */
u8 *payload = NULL, *pos = NULL;
int ret;
- DECLARE_MAC_BUF(mac);
/* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted
@@ -2358,8 +2354,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
break;
memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
- printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
- print_mac(mac, mlmeex->address));
+ printk(KERN_DEBUG "Authenticate from: address:\t%pM\n",
+ mlmeex->address);
confirm->id = -1; /* or mlmeex->id ? */
confirm->state = 0; /* not used */
confirm->code = 0;
@@ -2404,8 +2400,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
- print_mac(mac, mlmeex->address));
+ printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
+ mlmeex->address);
kfree(confirm);
break;
}
@@ -2441,8 +2437,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
- print_mac(mac, mlmeex->address));
+ printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
+ mlmeex->address);
kfree(confirm);
break;
}
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index af2e4f2405f..9a72b1e3e16 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -93,7 +93,7 @@ static struct pci_driver prism54_driver = {
Module initialization functions
******************************************************************************/
-int
+static int
prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct net_device *ndev;
@@ -216,7 +216,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static volatile int __in_cleanup_module = 0;
/* this one removes one(!!) instance only */
-void
+static void
prism54_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
@@ -259,7 +259,7 @@ prism54_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-int
+static int
prism54_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *ndev = pci_get_drvdata(pdev);
@@ -282,7 +282,7 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-int
+static int
prism54_resume(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 1404a571752..99ec7d62251 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -414,7 +414,6 @@ static int ray_config(struct pcmcia_device *link)
memreq_t mem;
struct net_device *dev = (struct net_device *)link->priv;
ray_dev_t *local = netdev_priv(dev);
- DECLARE_MAC_BUF(mac);
DEBUG(1, "ray_config(0x%p)\n", link);
@@ -485,8 +484,8 @@ static int ray_config(struct pcmcia_device *link)
strcpy(local->node.dev_name, dev->name);
link->dev_node = &local->node;
- printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n",
- dev->name, dev->irq, print_mac(mac, dev->dev_addr));
+ printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
+ dev->name, dev->irq, dev->dev_addr);
return 0;
@@ -829,7 +828,7 @@ static int ray_resume(struct pcmcia_device *link)
}
/*===========================================================================*/
-int ray_dev_init(struct net_device *dev)
+static int ray_dev_init(struct net_device *dev)
{
#ifdef RAY_IMMEDIATE_INIT
int i;
@@ -2285,7 +2284,6 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
- dev->last_rx = jiffies;
local->stats.rx_packets++;
local->stats.rx_bytes += total_len;
@@ -2595,7 +2593,6 @@ static int ray_cs_proc_show(struct seq_file *m, void *v)
UCHAR *p;
struct freq_hop_element *pfh;
UCHAR c[33];
- DECLARE_MAC_BUF(mac);
link = this_device;
if (!link)
@@ -2623,8 +2620,7 @@ static int ray_cs_proc_show(struct seq_file *m, void *v)
nettype[local->sparm.b5.a_network_type], c);
p = local->bss_id;
- seq_printf(m, "BSSID = %s\n",
- print_mac(mac, p));
+ seq_printf(m, "BSSID = %pM\n", p);
seq_printf(m, "Country code = %d\n",
local->sparm.b5.a_curr_country_code);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 2b414899dfa..607ce9f61b5 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -37,11 +37,11 @@
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include <linux/wireless.h>
+#include <linux/ieee80211.h>
#include <linux/if_arp.h>
#include <linux/ctype.h>
#include <linux/spinlock.h>
#include <net/iw_handler.h>
-#include <net/ieee80211.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/rndis_host.h>
@@ -1104,7 +1104,7 @@ static int rndis_iw_get_range(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct iw_range *range = (struct iw_range *)extra;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
int len, ret, i, j, num, has_80211g_rates;
u8 rates[8];
@@ -1210,7 +1210,7 @@ static int rndis_iw_get_range(struct net_device *dev,
static int rndis_iw_get_name(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
strcpy(wrqu->name, priv->name);
@@ -1223,7 +1223,7 @@ static int rndis_iw_set_essid(struct net_device *dev,
{
struct ndis_80211_ssid ssid;
int length = wrqu->essid.length;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'",
wrqu->essid.flags, wrqu->essid.length, essid);
@@ -1250,7 +1250,7 @@ static int rndis_iw_get_essid(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
{
struct ndis_80211_ssid ssid;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
int ret;
ret = get_essid(usbdev, &ssid);
@@ -1273,15 +1273,14 @@ static int rndis_iw_get_essid(struct net_device *dev,
static int rndis_iw_get_bssid(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
unsigned char bssid[ETH_ALEN];
int ret;
- DECLARE_MAC_BUF(mac);
ret = get_bssid(usbdev, bssid);
if (ret == 0)
- devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid));
+ devdbg(usbdev, "SIOCGIWAP: %pM", bssid);
else
devdbg(usbdev, "SIOCGIWAP: <not associated>");
@@ -1295,12 +1294,11 @@ static int rndis_iw_get_bssid(struct net_device *dev,
static int rndis_iw_set_bssid(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
u8 *bssid = (u8 *)wrqu->ap_addr.sa_data;
- DECLARE_MAC_BUF(mac);
int ret;
- devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid));
+ devdbg(usbdev, "SIOCSIWAP: %pM", bssid);
ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
@@ -1318,7 +1316,7 @@ static int rndis_iw_set_auth(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct iw_param *p = &wrqu->param;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
int ret = -ENOTSUPP;
@@ -1399,7 +1397,7 @@ static int rndis_iw_get_auth(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct iw_param *p = &wrqu->param;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
switch (p->flags & IW_AUTH_INDEX) {
@@ -1431,7 +1429,7 @@ static int rndis_iw_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
switch (priv->infra_mode) {
@@ -1454,7 +1452,7 @@ static int rndis_iw_get_mode(struct net_device *dev,
static int rndis_iw_set_mode(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
int mode;
devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode);
@@ -1479,7 +1477,7 @@ static int rndis_iw_set_mode(struct net_device *dev,
static int rndis_iw_set_encode(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
int ret, index, key_len;
u8 *key;
@@ -1542,7 +1540,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
struct ndis_80211_key ndis_key;
int keyidx, ret;
@@ -1627,7 +1625,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
static int rndis_iw_set_scan(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
union iwreq_data evt;
int ret = -EINVAL;
__le32 tmp;
@@ -1652,19 +1650,18 @@ static char *rndis_translate_scan(struct net_device *dev,
struct ndis_80211_bssid_ex *bssid)
{
#ifdef DEBUG
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
#endif
- struct ieee80211_info_element *ie;
+ u8 *ie;
char *current_val;
int bssid_len, ie_len, i;
u32 beacon, atim;
struct iw_event iwe;
unsigned char sbuf[32];
- DECLARE_MAC_BUF(mac);
bssid_len = le32_to_cpu(bssid->length);
- devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac));
+ devdbg(usbdev, "BSSID %pM", bssid->mac);
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN);
@@ -1753,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev,
ie_len = min(bssid_len - (int)sizeof(*bssid),
(int)le32_to_cpu(bssid->ie_length));
ie_len -= sizeof(struct ndis_80211_fixed_ies);
- while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
- if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
- memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
- ie->id == MFIE_TYPE_RSN) {
+ while (ie_len >= 2 && 2 + ie[1] <= ie_len) {
+ if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 &&
+ memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) ||
+ ie[0] == WLAN_EID_RSN) {
devdbg(usbdev, "IE: WPA%d",
- (ie->id == MFIE_TYPE_RSN) ? 2 : 1);
+ (ie[0] == WLAN_EID_RSN) ? 2 : 1);
iwe.cmd = IWEVGENIE;
- iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
- (u8 *)ie);
+ /* arbitrary cut-off at 64 */
+ iwe.u.data.length = min(ie[1] + 2, 64);
+ cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie);
}
- ie_len -= sizeof(*ie) + ie->len;
- ie = (struct ieee80211_info_element *)&ie->data[ie->len];
+ ie_len -= 2 + ie[1];
+ ie += 2 + ie[1];
}
return cev;
@@ -1776,7 +1773,7 @@ static char *rndis_translate_scan(struct net_device *dev,
static int rndis_iw_get_scan(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
void *buf = NULL;
char *cev = extra;
struct ndis_80211_bssid_list_ex *bssid_list;
@@ -1822,7 +1819,7 @@ out:
static int rndis_iw_set_genie(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
int ret = 0;
@@ -1856,7 +1853,7 @@ static int rndis_iw_set_genie(struct net_device *dev,
static int rndis_iw_get_genie(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
devdbg(usbdev, "SIOCGIWGENIE");
@@ -1879,7 +1876,7 @@ static int rndis_iw_get_genie(struct net_device *dev,
static int rndis_iw_set_rts(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
__le32 tmp;
devdbg(usbdev, "SIOCSIWRTS");
@@ -1892,7 +1889,7 @@ static int rndis_iw_set_rts(struct net_device *dev,
static int rndis_iw_get_rts(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
__le32 tmp;
int len, ret;
@@ -1913,7 +1910,7 @@ static int rndis_iw_get_rts(struct net_device *dev,
static int rndis_iw_set_frag(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
__le32 tmp;
devdbg(usbdev, "SIOCSIWFRAG");
@@ -1927,7 +1924,7 @@ static int rndis_iw_set_frag(struct net_device *dev,
static int rndis_iw_get_frag(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
__le32 tmp;
int len, ret;
@@ -1947,7 +1944,7 @@ static int rndis_iw_get_frag(struct net_device *dev,
static int rndis_iw_set_nick(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
devdbg(usbdev, "SIOCSIWNICK");
@@ -1964,7 +1961,7 @@ static int rndis_iw_set_nick(struct net_device *dev,
static int rndis_iw_get_nick(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
wrqu->data.flags = 1;
@@ -1980,7 +1977,7 @@ static int rndis_iw_get_nick(struct net_device *dev,
static int rndis_iw_set_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct ndis_80211_conf config;
unsigned int dsconfig;
int len, ret;
@@ -2011,7 +2008,7 @@ static int rndis_iw_set_freq(struct net_device *dev,
static int rndis_iw_get_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct ndis_80211_conf config;
int len, ret;
@@ -2028,7 +2025,7 @@ static int rndis_iw_get_freq(struct net_device *dev,
static int rndis_iw_get_txpower(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
__le32 tx_power;
int ret = 0, len;
@@ -2062,7 +2059,7 @@ static int rndis_iw_get_txpower(struct net_device *dev,
static int rndis_iw_set_txpower(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
__le32 tx_power = 0;
int ret = 0;
@@ -2114,7 +2111,7 @@ static int rndis_iw_set_txpower(struct net_device *dev,
static int rndis_iw_get_rate(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
__le32 tmp;
int ret, len;
@@ -2132,7 +2129,7 @@ static int rndis_iw_get_rate(struct net_device *dev,
static int rndis_iw_set_mlme(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
struct iw_mlme *mlme = (struct iw_mlme *)extra;
unsigned char bssid[ETH_ALEN];
@@ -2157,7 +2154,7 @@ static int rndis_iw_set_mlme(struct net_device *dev,
static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
unsigned long flags;
@@ -2287,7 +2284,7 @@ get_bssid:
static void rndis_wext_set_multicast_list(struct net_device *dev)
{
- struct usbnet *usbdev = dev->priv;
+ struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 95511ac2247..178b313293b 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -57,6 +57,7 @@ config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
select RT2X00_LIB_USB
+ select RT2X00_LIB_CRYPTO
---help---
This adds support for rt2500 wireless chipset family.
Supported chips: RT2571 & RT2572.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 08cb9eec16a..6a977679124 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -49,45 +49,33 @@
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
- if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the data into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ }
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -95,66 +83,58 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the request into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2400pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- *value = 0xff;
- return;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
}
*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
- if (!rt2x00_get_field32(reg, RFCSR_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
- return;
+ mutex_lock(&rt2x00dev->csr_mutex);
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, RFCSR_VALUE, value);
- rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
- rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
- rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -188,43 +168,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 *data)
-{
- rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 data)
-{
- rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
static const struct rt2x00debug rt2400pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2400pci_read_csr,
- .write = rt2400pci_write_csr,
+ .read = rt2x00pci_register_read,
+ .write = rt2x00pci_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
.word_count = CSR_REG_SIZE / sizeof(u32),
},
.eeprom = {
.read = rt2x00_eeprom_read,
.write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
.word_size = sizeof(u16),
.word_count = EEPROM_SIZE / sizeof(u16),
},
.bbp = {
.read = rt2400pci_bbp_read,
.write = rt2400pci_bbp_write,
+ .word_base = BBP_BASE,
.word_size = sizeof(u8),
.word_count = BBP_SIZE / sizeof(u8),
},
.rf = {
.read = rt2x00_rf_read,
.write = rt2400pci_rf_write,
+ .word_base = RF_BASE,
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
@@ -331,7 +302,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
/*
* Enable beacon config
*/
- bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
@@ -376,32 +347,94 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
}
-static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int basic_rate_mask)
+static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
{
- rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+ u8 r1;
+ u8 r4;
+
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
+ rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+ rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (ant->tx) {
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ default:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (ant->rx) {
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ default:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ }
+
+ rt2400pci_bbp_write(rt2x00dev, 4, r4);
+ rt2400pci_bbp_write(rt2x00dev, 1, r1);
}
static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -460,56 +493,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
}
-static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
{
- u8 r1;
- u8 r4;
-
- /*
- * We should never come here because rt2x00lib is supposed
- * to catch this and send us the correct antenna explicitely.
- */
- BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
- ant->tx == ANTENNA_SW_DIVERSITY);
-
- rt2400pci_bbp_read(rt2x00dev, 4, &r4);
- rt2400pci_bbp_read(rt2x00dev, 1, &r1);
-
- /*
- * Configure the TX antenna.
- */
- switch (ant->tx) {
- case ANTENNA_HW_DIVERSITY:
- rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
- break;
- case ANTENNA_A:
- rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
- break;
- case ANTENNA_B:
- default:
- rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
- break;
- }
-
- /*
- * Configure the RX antenna.
- */
- switch (ant->rx) {
- case ANTENNA_HW_DIVERSITY:
- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
- break;
- case ANTENNA_A:
- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
- break;
- case ANTENNA_B:
- default:
- rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
- break;
- }
+ u32 reg;
- rt2400pci_bbp_write(rt2x00dev, 4, r4);
- rt2400pci_bbp_write(rt2x00dev, 1, r1);
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
}
static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -517,20 +511,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
- rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
- rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
- rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
- rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -548,16 +528,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int flags)
{
- if (flags & CONFIG_UPDATE_PHYMODE)
- rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
- if (flags & CONFIG_UPDATE_CHANNEL)
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2400pci_config_channel(rt2x00dev, &libconf->rf);
- if (flags & CONFIG_UPDATE_TXPOWER)
+ if (flags & IEEE80211_CONF_CHANGE_POWER)
rt2400pci_config_txpower(rt2x00dev,
libconf->conf->power_level);
- if (flags & CONFIG_UPDATE_ANTENNA)
- rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
- if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt2400pci_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
rt2400pci_config_duration(rt2x00dev, libconf);
}
@@ -628,36 +606,47 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
/*
* Initialization functions.
*/
-static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static bool rt2400pci_get_entry_state(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 2, &word);
- rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
- rt2x00_desc_write(entry_priv->desc, 2, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ rt2x00_get_field32(word, TXD_W0_VALID));
+ }
}
-static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static void rt2400pci_clear_entry(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_VALID, 0);
- rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 2, &word);
+ rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len);
+ rt2x00_desc_write(entry_priv->desc, 2, word);
+
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ }
}
static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1313,10 +1302,8 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1504,20 +1491,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry, u32 long_retry)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
- rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
- return 0;
-}
-
static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
@@ -1576,7 +1549,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.config_interface = rt2x00mac_config_interface,
.configure_filter = rt2x00mac_configure_filter,
.get_stats = rt2x00mac_get_stats,
- .set_retry_limit = rt2400pci_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
@@ -1589,8 +1561,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.probe_hw = rt2400pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
- .init_rxentry = rt2400pci_init_rxentry,
- .init_txentry = rt2400pci_init_txentry,
+ .get_entry_state = rt2400pci_get_entry_state,
+ .clear_entry = rt2400pci_clear_entry,
.set_device_state = rt2400pci_set_device_state,
.rfkill_poll = rt2400pci_rfkill_poll,
.link_stats = rt2400pci_link_stats,
@@ -1604,6 +1576,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.config_filter = rt2400pci_config_filter,
.config_intf = rt2400pci_config_intf,
.config_erp = rt2400pci_config_erp,
+ .config_ant = rt2400pci_config_ant,
.config = rt2400pci_config,
};
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index bbff381ce39..9aefda4ab3c 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -46,7 +46,9 @@
#define CSR_REG_SIZE 0x014c
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0100
+#define BBP_BASE 0x0000
#define BBP_SIZE 0x0020
+#define RF_BASE 0x0000
#define RF_SIZE 0x0010
/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index ef42cc04a2d..d3bc218ec85 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -49,45 +49,33 @@
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
- if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the data into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ }
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -95,66 +83,58 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the request into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = 0;
- rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
- rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
- rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
- ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
- *value = 0xff;
- return;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
}
*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
- if (!rt2x00_get_field32(reg, RFCSR_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
- return;
+ mutex_lock(&rt2x00dev->csr_mutex);
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, RFCSR_VALUE, value);
- rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
- rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
- rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -188,43 +168,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 *data)
-{
- rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 data)
-{
- rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
static const struct rt2x00debug rt2500pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2500pci_read_csr,
- .write = rt2500pci_write_csr,
+ .read = rt2x00pci_register_read,
+ .write = rt2x00pci_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
.word_count = CSR_REG_SIZE / sizeof(u32),
},
.eeprom = {
.read = rt2x00_eeprom_read,
.write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
.word_size = sizeof(u16),
.word_count = EEPROM_SIZE / sizeof(u16),
},
.bbp = {
.read = rt2500pci_bbp_read,
.write = rt2500pci_bbp_write,
+ .word_base = BBP_BASE,
.word_size = sizeof(u8),
.word_count = BBP_SIZE / sizeof(u8),
},
.rf = {
.read = rt2x00_rf_read,
.write = rt2500pci_rf_write,
+ .word_base = RF_BASE,
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
@@ -336,7 +307,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
/*
* Enable beacon config
*/
- bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN, queue->cw_min);
@@ -382,32 +353,114 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10));
rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20));
rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55));
rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
- rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110));
rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
}
-static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int basic_rate_mask)
+static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
{
- rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+ u32 reg;
+ u8 r14;
+ u8 r2;
+
+ /*
+ * We should never come here because rt2x00lib is supposed
+ * to catch this and send us the correct antenna explicitely.
+ */
+ BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+ ant->tx == ANTENNA_SW_DIVERSITY);
+
+ rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+ rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+ rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (ant->tx) {
+ case ANTENNA_A:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+ break;
+ case ANTENNA_B:
+ default:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (ant->rx) {
+ case ANTENNA_A:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ default:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * RT2525E and RT5222 need to flip TX I/Q
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+ /*
+ * RT2525E does not need RX I/Q Flip.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+ } else {
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+ rt2500pci_bbp_write(rt2x00dev, 14, r14);
+ rt2500pci_bbp_write(rt2x00dev, 2, r2);
}
static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -489,76 +542,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
rt2500pci_rf_write(rt2x00dev, 3, rf3);
}
-static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
{
u32 reg;
- u8 r14;
- u8 r2;
-
- /*
- * We should never come here because rt2x00lib is supposed
- * to catch this and send us the correct antenna explicitely.
- */
- BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
- ant->tx == ANTENNA_SW_DIVERSITY);
-
- rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
- rt2500pci_bbp_read(rt2x00dev, 14, &r14);
- rt2500pci_bbp_read(rt2x00dev, 2, &r2);
-
- /*
- * Configure the TX antenna.
- */
- switch (ant->tx) {
- case ANTENNA_A:
- rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
- rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
- rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
- break;
- case ANTENNA_B:
- default:
- rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
- rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
- rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
- break;
- }
-
- /*
- * Configure the RX antenna.
- */
- switch (ant->rx) {
- case ANTENNA_A:
- rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
- break;
- case ANTENNA_B:
- default:
- rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
- break;
- }
-
- /*
- * RT2525E and RT5222 need to flip TX I/Q
- */
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
- rt2x00_rf(&rt2x00dev->chip, RF5222)) {
- rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
- rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
- rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
- /*
- * RT2525E does not need RX I/Q Flip.
- */
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
- rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
- } else {
- rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
- rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
- }
-
- rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
- rt2500pci_bbp_write(rt2x00dev, 14, r14);
- rt2500pci_bbp_write(rt2x00dev, 2, r2);
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
}
static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -566,20 +560,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
- rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
- rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
- rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
- rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -597,17 +577,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int flags)
{
- if (flags & CONFIG_UPDATE_PHYMODE)
- rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
- if (flags & CONFIG_UPDATE_CHANNEL)
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2500pci_config_channel(rt2x00dev, &libconf->rf,
libconf->conf->power_level);
- if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+ !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
rt2500pci_config_txpower(rt2x00dev,
libconf->conf->power_level);
- if (flags & CONFIG_UPDATE_ANTENNA)
- rt2500pci_config_antenna(rt2x00dev, &libconf->ant);
- if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt2500pci_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
rt2500pci_config_duration(rt2x00dev, libconf);
}
@@ -723,32 +702,43 @@ dynamic_cca_tune:
/*
* Initialization functions.
*/
-static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static bool rt2500pci_get_entry_state(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+ return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ rt2x00_get_field32(word, TXD_W0_VALID));
+ }
}
-static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static void rt2500pci_clear_entry(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_VALID, 0);
- rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ }
}
static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1451,11 +1441,8 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n",
- print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1830,20 +1817,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry, u32 long_retry)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
- rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
- rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
- return 0;
-}
-
static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1877,7 +1850,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.config_interface = rt2x00mac_config_interface,
.configure_filter = rt2x00mac_configure_filter,
.get_stats = rt2x00mac_get_stats,
- .set_retry_limit = rt2500pci_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
@@ -1890,8 +1862,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.probe_hw = rt2500pci_probe_hw,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
- .init_rxentry = rt2500pci_init_rxentry,
- .init_txentry = rt2500pci_init_txentry,
+ .get_entry_state = rt2500pci_get_entry_state,
+ .clear_entry = rt2500pci_clear_entry,
.set_device_state = rt2500pci_set_device_state,
.rfkill_poll = rt2500pci_rfkill_poll,
.link_stats = rt2500pci_link_stats,
@@ -1905,6 +1877,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.config_filter = rt2500pci_config_filter,
.config_intf = rt2500pci_config_intf,
.config_erp = rt2500pci_config_erp,
+ .config_ant = rt2500pci_config_ant,
.config = rt2500pci_config,
};
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index 8c26bef6cf4..e135247f7f8 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -57,7 +57,9 @@
#define CSR_REG_SIZE 0x0174
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0200
+#define BBP_BASE 0x0000
#define BBP_SIZE 0x0040
+#define RF_BASE 0x0000
#define RF_SIZE 0x0014
/*
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index d3bf7bba611..30028e2422f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -36,6 +36,13 @@
#include "rt2500usb.h"
/*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 1;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
* Register access.
* All access to the CSR registers will go through the methods
* rt2500usb_register_read and rt2500usb_register_write.
@@ -47,7 +54,7 @@
* between each attampt. When the busy bit is still set at that time,
* the access attempt is considered to have failed,
* and we will print an error.
- * If the usb_cache_mutex is already held then the _lock variants must
+ * If the csr_mutex is already held then the _lock variants must
* be used instead.
*/
static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
@@ -57,7 +64,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
__le16 reg;
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg);
}
@@ -68,7 +75,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
__le16 reg;
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
*value = le16_to_cpu(reg);
}
@@ -89,7 +96,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
__le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
}
static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
@@ -99,7 +106,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
__le16 reg = cpu_to_le16(value);
rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u16), REGISTER_TIMEOUT);
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
}
static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
@@ -112,53 +119,53 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
REGISTER_TIMEOUT16(length));
}
-static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field16 field,
+ u16 *reg)
{
- u16 reg;
unsigned int i;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
- if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- break;
+ rt2500usb_register_read_lock(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field16(*reg, field))
+ return 1;
udelay(REGISTER_BUSY_DELAY);
}
- return reg;
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg))
+
static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u16 reg;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
- */
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
- rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
- rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
-
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
-
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
- return;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
-exit_fail:
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+ }
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -166,122 +173,107 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
{
u16 reg;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
-
- /*
- * Write the request into the BBP.
- */
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
- rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
- goto exit_fail;
+ if (WAIT_FOR_BBP(rt2x00dev, &reg))
+ rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
+ }
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- *value = 0xff;
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u16 reg;
- unsigned int i;
if (!word)
return;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
- if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
- reg = 0;
- rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
- rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
- rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) )
-
-static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 *data)
+static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
{
- rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+ rt2500usb_register_read(rt2x00dev, offset, (u16 *)value);
}
-static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 data)
+static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
{
- rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+ rt2500usb_register_write(rt2x00dev, offset, value);
}
static const struct rt2x00debug rt2500usb_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2500usb_read_csr,
- .write = rt2500usb_write_csr,
+ .read = _rt2500usb_register_read,
+ .write = _rt2500usb_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
.word_size = sizeof(u16),
.word_count = CSR_REG_SIZE / sizeof(u16),
},
.eeprom = {
.read = rt2x00_eeprom_read,
.write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
.word_size = sizeof(u16),
.word_count = EEPROM_SIZE / sizeof(u16),
},
.bbp = {
.read = rt2500usb_bbp_read,
.write = rt2500usb_bbp_write,
+ .word_base = BBP_BASE,
.word_size = sizeof(u8),
.word_count = BBP_SIZE / sizeof(u8),
},
.rf = {
.read = rt2x00_rf_read,
.write = rt2500usb_rf_write,
+ .word_base = RF_BASE,
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
@@ -338,6 +330,82 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev,
/*
* Configuration handlers.
*/
+
+/*
+ * rt2500usb does not differentiate between shared and pairwise
+ * keys, so we should use the same function for both key types.
+ */
+static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ int timeout;
+ u32 mask;
+ u16 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * Pairwise key will always be entry 0, but this
+ * could collide with a shared key on the same
+ * position...
+ */
+ mask = TXRX_CSR0_KEY_ID.bit_mask;
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ reg &= mask;
+
+ if (reg && reg == mask)
+ return -ENOSPC;
+
+ reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
+
+ key->hw_key_idx += reg ? ffz(reg) : 0;
+
+ /*
+ * The encryption key doesn't fit within the CSR cache,
+ * this means we should allocate it seperately and use
+ * rt2x00usb_vendor_request() to send the key to the hardware.
+ */
+ reg = KEY_ENTRY(key->hw_key_idx);
+ timeout = REGISTER_TIMEOUT32(sizeof(crypto->key));
+ rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, reg,
+ crypto->key,
+ sizeof(crypto->key),
+ timeout);
+
+ /*
+ * The driver does not support the IV/EIV generation
+ * in hardware. However it doesn't support the IV/EIV
+ * inside the ieee80211 frame either, but requires it
+ * to be provided seperately for the descriptor.
+ * rt2x00lib will cut the IV/EIV data out of all frames
+ * given to us by mac80211, but we must tell mac80211
+ * to generate the IV/EIV data.
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ }
+
+ /*
+ * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate
+ * a particular key is valid.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR0_ALGORITHM, crypto->cipher);
+ rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
+
+ mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);
+ if (crypto->cmd == SET_KEY)
+ mask |= 1 << key->hw_key_idx;
+ else if (crypto->cmd == DISABLE_KEY)
+ mask &= ~(1 << key->hw_key_idx);
+ rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, mask);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ return 0;
+}
+
static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
@@ -380,7 +448,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
/*
* Enable beacon config
*/
- bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20);
+ bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET, bcn_preload >> 6);
rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW,
@@ -423,57 +491,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
-}
-
-static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int basic_rate_mask)
-{
- rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
-}
-
-static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
- struct rf_channel *rf, const int txpower)
-{
- /*
- * Set TXpower.
- */
- rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-
- /*
- * For RT2525E we should first set the channel to half band higher.
- */
- if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
- static const u32 vals[] = {
- 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
- 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
- 0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
- 0x00000902, 0x00000906
- };
-
- rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
- if (rf->rf4)
- rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
- }
-
- rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
- rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
- rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
- if (rf->rf4)
- rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-}
-static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
- const int txpower)
-{
- u32 rf3;
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
- rt2x00_rf_read(rt2x00dev, 3, &rf3);
- rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
- rt2500usb_rf_write(rt2x00dev, 3, rf3);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
}
-static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
{
u8 r2;
u8 r14;
@@ -555,15 +582,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
}
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ /*
+ * Set TXpower.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+ /*
+ * For RT2525E we should first set the channel to half band higher.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ static const u32 vals[] = {
+ 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+ 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+ 0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+ 0x00000902, 0x00000906
+ };
+
+ rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+ }
+
+ rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 rf3;
+
+ rt2x00_rf_read(rt2x00dev, 3, &rf3);
+ rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf)
{
u16 reg;
- rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
- rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs);
- rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs);
-
rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
libconf->conf->beacon_int * 4);
@@ -574,17 +638,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
const unsigned int flags)
{
- if (flags & CONFIG_UPDATE_PHYMODE)
- rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates);
- if (flags & CONFIG_UPDATE_CHANNEL)
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2500usb_config_channel(rt2x00dev, &libconf->rf,
libconf->conf->power_level);
- if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+ !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
rt2500usb_config_txpower(rt2x00dev,
libconf->conf->power_level);
- if (flags & CONFIG_UPDATE_ANTENNA)
- rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
- if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
rt2500usb_config_duration(rt2x00dev, libconf);
}
@@ -866,7 +927,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
+ rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
@@ -1088,7 +1149,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
* Start writing the descriptor words.
*/
rt2x00_desc_read(txd, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1101,6 +1162,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);
+ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+ _rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+ _rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
+ }
+
rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
@@ -1115,7 +1181,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
- rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher);
+ rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
rt2x00_desc_write(txd, 0, word);
}
@@ -1130,7 +1197,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
int length;
u16 reg;
@@ -1156,7 +1223,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
*/
- length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
entry->skb->data, length, rt2500usb_beacondone,
@@ -1178,8 +1245,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
}
-static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb)
+static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -1187,8 +1253,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
* The length _must_ be a multiple of 2,
* but it must _not_ be a multiple of the USB packet size.
*/
- length = roundup(skb->len, 2);
- length += (2 * !(length % rt2x00dev->usb_maxpacket));
+ length = roundup(entry->skb->len, 2);
+ length += (2 * !(length % entry->queue->usb_maxpacket));
return length;
}
@@ -1227,6 +1293,7 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
static void rt2500usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd =
@@ -1254,6 +1321,33 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
+ if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+ rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
+ }
+
+ if (rxdesc->cipher != CIPHER_NONE) {
+ _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
+ _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]);
+ rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
+ /* ICV is located at the end of frame */
+
+ /*
+ * Hardware has stripped IV/EIV data from 802.11 frame during
+ * decryption. It has provided the data seperately but rt2x00lib
+ * should decide if it should be reinserted.
+ */
+ rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+ if (rxdesc->cipher != CIPHER_TKIP)
+ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+ if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+ rxdesc->flags |= RX_FLAG_DECRYPTED;
+ else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+ rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+ }
+
/*
* Obtain the status about this packet.
* When frame was received with an OFDM bitrate,
@@ -1261,8 +1355,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
* a CCK bitrate the signal is the rate in 100kbit/s.
*/
rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
- entry->queue->rt2x00dev->rssi_offset;
+ rxdesc->rssi =
+ rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
@@ -1319,10 +1413,8 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1752,6 +1844,10 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
+ if (!modparam_nohwcrypt) {
+ __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+ __set_bit(CONFIG_CRYPTO_COPY_IV, &rt2x00dev->flags);
+ }
__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
/*
@@ -1771,6 +1867,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
.configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
@@ -1781,8 +1878,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.probe_hw = rt2500usb_probe_hw,
.initialize = rt2x00usb_initialize,
.uninitialize = rt2x00usb_uninitialize,
- .init_rxentry = rt2x00usb_init_rxentry,
- .init_txentry = rt2x00usb_init_txentry,
+ .clear_entry = rt2x00usb_clear_entry,
.set_device_state = rt2500usb_set_device_state,
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
@@ -1793,9 +1889,12 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2500usb_kick_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
+ .config_shared_key = rt2500usb_config_key,
+ .config_pairwise_key = rt2500usb_config_key,
.config_filter = rt2500usb_config_filter,
.config_intf = rt2500usb_config_intf,
.config_erp = rt2500usb_config_erp,
+ .config_ant = rt2500usb_config_ant,
.config = rt2500usb_config,
};
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 89e5ed24e4f..4347dfdabcd 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -57,7 +57,9 @@
#define CSR_REG_SIZE 0x0100
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x006a
+#define BBP_BASE 0x0000
#define BBP_SIZE 0x0060
+#define RF_BASE 0x0000
#define RF_SIZE 0x0014
/*
@@ -445,6 +447,9 @@
#define SEC_CSR30 0x04bc
#define SEC_CSR31 0x04be
+#define KEY_ENTRY(__idx) \
+ ( SEC_CSR0 + ((__idx) * 16) )
+
/*
* PHY control registers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 1359a376840..39ecf3b82ca 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -44,7 +44,7 @@
/*
* Module information.
*/
-#define DRV_VERSION "2.2.1"
+#define DRV_VERSION "2.2.3"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
@@ -92,6 +92,16 @@
DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
/*
+ * Duration calculations
+ * The rate variable passed is: 100kbs.
+ * To convert from bytes to bits we multiply size with 8,
+ * then the size is multiplied with 10 to make the
+ * real rate -> rate argument correction.
+ */
+#define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate))
+#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
+
+/*
* Standard timing and size defines.
* These values should follow the ieee80211 specifications.
*/
@@ -109,9 +119,9 @@
#define DIFS ( PIFS + SLOT_TIME )
#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
#define EIFS ( SIFS + DIFS + \
- (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
#define SHORT_EIFS ( SIFS + SHORT_DIFS + \
- (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
/*
* Chipset identification
@@ -348,13 +358,6 @@ struct rt2x00_intf {
spinlock_t lock;
/*
- * BSS configuration. Copied from the structure
- * passed to us through the bss_info_changed()
- * callback funtion.
- */
- struct ieee80211_bss_conf conf;
-
- /*
* MAC of the device.
*/
u8 mac[ETH_ALEN];
@@ -433,18 +436,6 @@ struct rt2x00lib_conf {
struct rf_channel rf;
struct channel_info channel;
-
- struct antenna_setup ant;
-
- enum ieee80211_band band;
-
- u32 basic_rates;
- u32 slot_time;
-
- short sifs;
- short pifs;
- short difs;
- short eifs;
};
/*
@@ -456,6 +447,15 @@ struct rt2x00lib_erp {
int ack_timeout;
int ack_consume_time;
+
+ u64 basic_rates;
+
+ int slot_time;
+
+ short sifs;
+ short pifs;
+ short difs;
+ short eifs;
};
/*
@@ -533,10 +533,8 @@ struct rt2x00lib_ops {
/*
* queue initialization handlers
*/
- void (*init_rxentry) (struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
- void (*init_txentry) (struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
+ bool (*get_entry_state) (struct queue_entry *entry);
+ void (*clear_entry) (struct queue_entry *entry);
/*
* Radio control handlers.
@@ -557,8 +555,7 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry);
void (*write_beacon) (struct queue_entry *entry);
- int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb);
+ int (*get_tx_data_len) (struct queue_entry *entry);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue);
@@ -589,16 +586,11 @@ struct rt2x00lib_ops {
void (*config_erp) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_erp *erp);
+ void (*config_ant) (struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant);
void (*config) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf,
- const unsigned int flags);
-#define CONFIG_UPDATE_PHYMODE ( 1 << 1 )
-#define CONFIG_UPDATE_CHANNEL ( 1 << 2 )
-#define CONFIG_UPDATE_TXPOWER ( 1 << 3 )
-#define CONFIG_UPDATE_ANTENNA ( 1 << 4 )
-#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 )
-#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 )
-#define CONFIG_UPDATE_ALL 0xffff
+ const unsigned int changed_flags);
};
/*
@@ -661,6 +653,7 @@ enum rt2x00_flags {
CONFIG_EXTERNAL_LNA_BG,
CONFIG_DOUBLE_ANTENNA,
CONFIG_DISABLE_LINK_TUNING,
+ CONFIG_CRYPTO_COPY_IV,
};
/*
@@ -738,8 +731,7 @@ struct rt2x00_dev {
/*
* This is the default TX/RX antenna setup as indicated
- * by the device's EEPROM. When mac80211 sets its
- * antenna value to 0 we should be using these values.
+ * by the device's EEPROM.
*/
struct antenna_setup default_ant;
@@ -754,16 +746,15 @@ struct rt2x00_dev {
} csr;
/*
- * Mutex to protect register accesses on USB devices.
- * There are 2 reasons this is needed, one is to ensure
- * use of the csr_cache (for USB devices) by one thread
- * isn't corrupted by another thread trying to access it.
- * The other is that access to BBP and RF registers
- * require multiple BUS transactions and if another thread
- * attempted to access one of those registers at the same
- * time one of the writes could silently fail.
+ * Mutex to protect register accesses.
+ * For PCI and USB devices it protects against concurrent indirect
+ * register access (BBP, RF, MCU) since accessing those
+ * registers require multiple calls to the CSR registers.
+ * For USB devices it also protects the csr_cache since that
+ * field is used for normal CSR access and it cannot support
+ * multiple callers simultaneously.
*/
- struct mutex usb_cache_mutex;
+ struct mutex csr_mutex;
/*
* Current packet filter configuration for the device.
@@ -808,14 +799,15 @@ struct rt2x00_dev {
short lna_gain;
/*
- * USB Max frame size (for rt2500usb & rt73usb).
+ * Current TX power value.
*/
- u16 usb_maxpacket;
+ u16 tx_power;
/*
- * Current TX power value.
+ * Current retry values.
*/
- u16 tx_power;
+ u8 short_retry;
+ u8 long_retry;
/*
* Rssi <-> Dbm offset
@@ -938,23 +930,6 @@ static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset,
!!(chipset->rev & 0x0000f));
}
-/*
- * Duration calculations
- * The rate variable passed is: 100kbs.
- * To convert from bytes to bits we multiply size with 8,
- * then the size is multiplied with 10 to make the
- * real rate -> rate argument correction.
- */
-static inline u16 get_duration(const unsigned int size, const u8 rate)
-{
- return ((size * 8 * 10) / rate);
-}
-
-static inline u16 get_duration_res(const unsigned int size, const u8 rate)
-{
- return ((size * 8 * 10) % rate);
-}
-
/**
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @rt2x00dev: Pointer to &struct rt2x00_dev.
@@ -997,7 +972,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
int rt2x00mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf);
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 4d5e87b015a..e66fb316cd6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
erp.short_preamble = bss_conf->use_short_preamble;
erp.cts_protection = bss_conf->use_cts_prot;
- erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
- erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
+ erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
+ erp.sifs = SIFS;
+ erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
+ erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
+ erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
- if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME)
- erp.ack_timeout += SHORT_DIFS;
- else
- erp.ack_timeout += DIFS;
+ erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10);
+ erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10);
if (bss_conf->use_short_preamble) {
erp.ack_timeout += SHORT_PREAMBLE;
@@ -102,19 +103,39 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
erp.ack_consume_time += PREAMBLE;
}
+ erp.basic_rates = bss_conf->basic_rates;
+
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
}
+static inline
+enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
+ enum antenna default_ant)
+{
+ if (current_ant != ANTENNA_SW_DIVERSITY)
+ return current_ant;
+ return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B;
+}
+
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- enum antenna rx, enum antenna tx)
+ struct antenna_setup *ant)
{
- struct rt2x00lib_conf libconf;
+ struct antenna_setup *def = &rt2x00dev->default_ant;
+ struct antenna_setup *active = &rt2x00dev->link.ant.active;
- libconf.ant.rx = rx;
- libconf.ant.tx = tx;
+ /*
+ * Failsafe: Make sure we are not sending the
+ * ANTENNA_SW_DIVERSITY state to the driver.
+ * If that happes fallback to hardware default,
+ * or our own default.
+ * The calls to rt2x00lib_config_antenna_check()
+ * might have caused that we restore back to the already
+ * active setting. If that has happened we can quit.
+ */
+ ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx);
+ ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx);
- if (rx == rt2x00dev->link.ant.active.rx &&
- tx == rt2x00dev->link.ant.active.tx)
+ if (ant->rx == active->rx && ant->tx == active->tx)
return;
/*
@@ -129,119 +150,28 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* The latter is required since we need to recalibrate the
* noise-sensitivity ratio for the new setup.
*/
- rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
+ rt2x00dev->ops->lib->config_ant(rt2x00dev, ant);
+
rt2x00lib_reset_link_tuner(rt2x00dev);
rt2x00_reset_link_ant_rssi(&rt2x00dev->link);
- rt2x00dev->link.ant.active.rx = libconf.ant.rx;
- rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+ memcpy(active, ant, sizeof(*ant));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
}
-static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band)
-{
- const struct rt2x00_rate *rate;
- unsigned int i;
- u32 mask = 0;
-
- for (i = 0; i < band->n_bitrates; i++) {
- rate = rt2x00_get_rate(band->bitrates[i].hw_value);
- if (rate->flags & DEV_RATE_BASIC)
- mask |= rate->ratemask;
- }
-
- return mask;
-}
-
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_conf *conf, const int force_config)
+ struct ieee80211_conf *conf,
+ unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
- struct ieee80211_supported_band *band;
- struct antenna_setup *default_ant = &rt2x00dev->default_ant;
- struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
- int flags = 0;
- int short_slot_time;
-
- /*
- * In some situations we want to force all configurations
- * to be reloaded (When resuming for instance).
- */
- if (force_config) {
- flags = CONFIG_UPDATE_ALL;
- goto config;
- }
- /*
- * Check which configuration options have been
- * updated and should be send to the device.
- */
- if (rt2x00dev->rx_status.band != conf->channel->band)
- flags |= CONFIG_UPDATE_PHYMODE;
- if (rt2x00dev->rx_status.freq != conf->channel->center_freq)
- flags |= CONFIG_UPDATE_CHANNEL;
- if (rt2x00dev->tx_power != conf->power_level)
- flags |= CONFIG_UPDATE_TXPOWER;
-
- /*
- * Determining changes in the antenna setups request several checks:
- * antenna_sel_{r,t}x = 0
- * -> Does active_{r,t}x match default_{r,t}x
- * -> Is default_{r,t}x SW_DIVERSITY
- * antenna_sel_{r,t}x = 1/2
- * -> Does active_{r,t}x match antenna_sel_{r,t}x
- * The reason for not updating the antenna while SW diversity
- * should be used is simple: Software diversity means that
- * we should switch between the antenna's based on the
- * quality. This means that the current antenna is good enough
- * to work with untill the link tuner decides that an antenna
- * switch should be performed.
- */
- if (!conf->antenna_sel_rx &&
- default_ant->rx != ANTENNA_SW_DIVERSITY &&
- default_ant->rx != active_ant->rx)
- flags |= CONFIG_UPDATE_ANTENNA;
- else if (conf->antenna_sel_rx &&
- conf->antenna_sel_rx != active_ant->rx)
- flags |= CONFIG_UPDATE_ANTENNA;
- else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
- flags |= CONFIG_UPDATE_ANTENNA;
-
- if (!conf->antenna_sel_tx &&
- default_ant->tx != ANTENNA_SW_DIVERSITY &&
- default_ant->tx != active_ant->tx)
- flags |= CONFIG_UPDATE_ANTENNA;
- else if (conf->antenna_sel_tx &&
- conf->antenna_sel_tx != active_ant->tx)
- flags |= CONFIG_UPDATE_ANTENNA;
- else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
- flags |= CONFIG_UPDATE_ANTENNA;
-
- /*
- * The following configuration options are never
- * stored anywhere and will always be updated.
- */
- flags |= CONFIG_UPDATE_SLOT_TIME;
- flags |= CONFIG_UPDATE_BEACON_INT;
-
- /*
- * We have determined what options should be updated,
- * now precalculate device configuration values depending
- * on what configuration options need to be updated.
- */
-config:
memset(&libconf, 0, sizeof(libconf));
- if (flags & CONFIG_UPDATE_PHYMODE) {
- band = &rt2x00dev->bands[conf->channel->band];
-
- libconf.band = conf->channel->band;
- libconf.basic_rates = rt2x00lib_get_basic_rates(band);
- }
+ libconf.conf = conf;
- if (flags & CONFIG_UPDATE_CHANNEL) {
+ if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
memcpy(&libconf.rf,
&rt2x00dev->spec.channels[conf->channel->hw_value],
sizeof(libconf.rf));
@@ -251,61 +181,23 @@ config:
sizeof(libconf.channel));
}
- if (flags & CONFIG_UPDATE_ANTENNA) {
- if (conf->antenna_sel_rx)
- libconf.ant.rx = conf->antenna_sel_rx;
- else if (default_ant->rx != ANTENNA_SW_DIVERSITY)
- libconf.ant.rx = default_ant->rx;
- else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
- libconf.ant.rx = ANTENNA_B;
- else
- libconf.ant.rx = active_ant->rx;
-
- if (conf->antenna_sel_tx)
- libconf.ant.tx = conf->antenna_sel_tx;
- else if (default_ant->tx != ANTENNA_SW_DIVERSITY)
- libconf.ant.tx = default_ant->tx;
- else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
- libconf.ant.tx = ANTENNA_B;
- else
- libconf.ant.tx = active_ant->tx;
- }
-
- if (flags & CONFIG_UPDATE_SLOT_TIME) {
- short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
-
- libconf.slot_time =
- short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
- libconf.sifs = SIFS;
- libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
- libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
- libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
- }
-
- libconf.conf = conf;
-
/*
* Start configuration.
*/
- rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
+ rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
/*
* Some configuration changes affect the link quality
* which means we need to reset the link tuner.
*/
- if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+ if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2x00lib_reset_link_tuner(rt2x00dev);
- if (flags & CONFIG_UPDATE_PHYMODE) {
- rt2x00dev->curr_band = conf->channel->band;
- rt2x00dev->rx_status.band = conf->channel->band;
- }
-
- rt2x00dev->rx_status.freq = conf->channel->center_freq;
+ rt2x00dev->curr_band = conf->channel->band;
rt2x00dev->tx_power = conf->power_level;
+ rt2x00dev->short_retry = conf->short_frame_max_tx_count;
+ rt2x00dev->long_retry = conf->long_frame_max_tx_count;
- if (flags & CONFIG_UPDATE_ANTENNA) {
- rt2x00dev->link.ant.active.rx = libconf.ant.rx;
- rt2x00dev->link.ant.active.tx = libconf.ant.tx;
- }
+ rt2x00dev->rx_status.band = conf->channel->band;
+ rt2x00dev->rx_status.freq = conf->channel->center_freq;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 5a858e5106c..37ad0d2fb64 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -46,6 +46,29 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
}
}
+void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+ struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
+
+ __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
+
+ txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
+
+ if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
+
+ txdesc->key_idx = hw_key->hw_key_idx;
+ txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+
+ if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+ __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
+
+ if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+ __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
+}
+
unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
{
struct ieee80211_key_conf *key = tx_info->control.hw_key;
@@ -69,6 +92,18 @@ unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
return overhead;
}
+void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (unlikely(!iv_len))
+ return;
+
+ /* Copy IV/EIV data */
+ memcpy(skbdesc->iv, skb->data + header_length, iv_len);
+}
+
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
@@ -78,10 +113,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len)
return;
/* Copy IV/EIV data */
- if (iv_len >= 4)
- memcpy(&skbdesc->iv, skb->data + header_length, 4);
- if (iv_len >= 8)
- memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4);
+ memcpy(skbdesc->iv, skb->data + header_length, iv_len);
/* Move ieee80211 header */
memmove(skb->data + iv_len, skb->data, header_length);
@@ -98,7 +130,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
const unsigned int iv_len =
- ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4);
+ ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4);
if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED))
return;
@@ -109,10 +141,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
memmove(skb->data, skb->data + iv_len, header_length);
/* Copy IV/EIV data */
- if (iv_len >= 4)
- memcpy(skb->data + header_length, &skbdesc->iv, 4);
- if (iv_len >= 8)
- memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4);
+ memcpy(skb->data + header_length, skbdesc->iv, iv_len);
/* IV/EIV data has returned into the frame */
skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED;
@@ -172,17 +201,9 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
header_length);
transfer += header_length;
- /* Copy IV data */
- if (iv_len >= 4) {
- memcpy(skb->data + transfer, &rxdesc->iv, 4);
- transfer += 4;
- }
-
- /* Copy EIV data */
- if (iv_len >= 8) {
- memcpy(skb->data + transfer, &rxdesc->eiv, 4);
- transfer += 4;
- }
+ /* Copy IV/EIV data */
+ memcpy(skb->data + transfer, rxdesc->iv, iv_len);
+ transfer += iv_len;
/* Move payload */
if (align) {
@@ -198,16 +219,14 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
*/
transfer += payload_len;
- /* Copy ICV data */
- if (icv_len >= 4) {
- memcpy(skb->data + transfer, &rxdesc->icv, 4);
- /*
- * AES appends 8 bytes, we can't fill the upper
- * 4 bytes, but mac80211 doesn't care about what
- * we provide here anyway and strips it immediately.
- */
- transfer += icv_len;
- }
+ /*
+ * Copy ICV data
+ * AES appends 8 bytes, we can't fill the upper
+ * 4 bytes, but mac80211 doesn't care about what
+ * we provide here anyway and strips it immediately.
+ */
+ memcpy(skb->data + transfer, &rxdesc->icv, 4);
+ transfer += icv_len;
/* IV/EIV/ICV has been inserted into frame */
rxdesc->size = transfer;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 5cf4c859e39..54dd10060bf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -285,7 +285,7 @@ exit:
}
static unsigned int rt2x00debug_poll_queue_dump(struct file *file,
- poll_table *wait)
+ poll_table *wait)
{
struct rt2x00debug_intf *intf = file->private_data;
@@ -377,7 +377,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
if (*offset)
return 0;
- data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL);
+ data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \
const struct rt2x00debug *debug = intf->debug; \
char line[16]; \
size_t size; \
+ unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
- if (intf->offset_##__name >= debug->__name.word_count) \
+ if (index >= debug->__name.word_count) \
return -EINVAL; \
\
- debug->__name.read(intf->rt2x00dev, \
- intf->offset_##__name, &value); \
+ if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
+ index *= debug->__name.word_size; \
+ \
+ index += debug->__name.word_base; \
+ \
+ debug->__name.read(intf->rt2x00dev, index, &value); \
\
size = sprintf(line, __format, value); \
\
@@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \
const struct rt2x00debug *debug = intf->debug; \
char line[16]; \
size_t size; \
+ unsigned int index = intf->offset_##__name; \
__type value; \
\
if (*offset) \
return 0; \
\
- if (intf->offset_##__name >= debug->__name.word_count) \
+ if (index >= debug->__name.word_count) \
return -EINVAL; \
\
if (copy_from_user(line, buf, length)) \
@@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \
size = strlen(line); \
value = simple_strtoul(line, NULL, 0); \
\
- debug->__name.write(intf->rt2x00dev, \
- intf->offset_##__name, value); \
+ if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \
+ index *= debug->__name.word_size; \
+ \
+ index += debug->__name.word_base; \
+ \
+ debug->__name.write(intf->rt2x00dev, index, value); \
\
*offset += size; \
return size; \
@@ -587,29 +597,29 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf->driver_folder =
debugfs_create_dir(intf->rt2x00dev->ops->name,
rt2x00dev->hw->wiphy->debugfsdir);
- if (IS_ERR(intf->driver_folder))
+ if (IS_ERR(intf->driver_folder) || !intf->driver_folder)
goto exit;
intf->driver_entry =
rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
- if (IS_ERR(intf->driver_entry))
+ if (IS_ERR(intf->driver_entry) || !intf->driver_entry)
goto exit;
intf->chipset_entry =
rt2x00debug_create_file_chipset("chipset",
intf, &intf->chipset_blob);
- if (IS_ERR(intf->chipset_entry))
+ if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry)
goto exit;
intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
- if (IS_ERR(intf->dev_flags))
+ if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
goto exit;
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
- if (IS_ERR(intf->register_folder))
+ if (IS_ERR(intf->register_folder) || !intf->register_folder)
goto exit;
#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
@@ -619,7 +629,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
- if (IS_ERR((__intf)->__name##_off_entry)) \
+ if (IS_ERR((__intf)->__name##_off_entry) \
+ || !(__intf)->__name##_off_entry) \
goto exit; \
\
(__intf)->__name##_val_entry = \
@@ -627,7 +638,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
(__intf), &rt2x00debug_fop_##__name);\
- if (IS_ERR((__intf)->__name##_val_entry)) \
+ if (IS_ERR((__intf)->__name##_val_entry) \
+ || !(__intf)->__name##_val_entry) \
goto exit; \
})
@@ -640,13 +652,14 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf->queue_folder =
debugfs_create_dir("queue", intf->driver_folder);
- if (IS_ERR(intf->queue_folder))
+ if (IS_ERR(intf->queue_folder) || !intf->queue_folder)
goto exit;
intf->queue_frame_dump_entry =
debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_dump);
- if (IS_ERR(intf->queue_frame_dump_entry))
+ if (IS_ERR(intf->queue_frame_dump_entry)
+ || !intf->queue_frame_dump_entry)
goto exit;
skb_queue_head_init(&intf->frame_dump_skbqueue);
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
index c4ce895aa1c..a92104dfee9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.h
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -28,6 +28,16 @@
struct rt2x00_dev;
+/**
+ * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
+ *
+ * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
+ * as argument when using the callback function read()/write()
+ */
+enum rt2x00debugfs_entry_flags {
+ RT2X00DEBUGFS_OFFSET = (1 << 0),
+};
+
#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
struct reg##__name { \
void (*read)(struct rt2x00_dev *rt2x00dev, \
@@ -35,6 +45,9 @@ struct reg##__name { \
void (*write)(struct rt2x00_dev *rt2x00dev, \
const unsigned int word, __type data); \
\
+ unsigned int flags; \
+ \
+ unsigned int word_base; \
unsigned int word_size; \
unsigned int word_count; \
} __name
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 86840e3585e..6d92542fcf0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -101,8 +101,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize all data queues.
*/
- rt2x00queue_init_rx(rt2x00dev);
- rt2x00queue_init_tx(rt2x00dev);
+ rt2x00queue_init_queues(rt2x00dev);
/*
* Enable radio.
@@ -176,13 +175,14 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
{
- enum antenna rx = rt2x00dev->link.ant.active.rx;
- enum antenna tx = rt2x00dev->link.ant.active.tx;
+ struct antenna_setup ant;
int sample_a =
rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
int sample_b =
rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
+ memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
+
/*
* We are done sampling. Now we should evaluate the results.
*/
@@ -200,21 +200,22 @@ static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
return;
if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
- rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
- tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
+ ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
- rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+ rt2x00lib_config_antenna(rt2x00dev, &ant);
}
static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
{
- enum antenna rx = rt2x00dev->link.ant.active.rx;
- enum antenna tx = rt2x00dev->link.ant.active.tx;
+ struct antenna_setup ant;
int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
+ memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant));
+
/*
* Legacy driver indicates that we should swap antenna's
* when the difference in RSSI is greater that 5. This
@@ -230,12 +231,12 @@ static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
- rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+ ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
- tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+ ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
- rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+ rt2x00lib_config_antenna(rt2x00dev, &ant);
}
static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
@@ -249,11 +250,9 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
- if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
- rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+ if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
- if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
- rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
@@ -419,7 +418,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
*/
spin_lock(&intf->lock);
- memcpy(&conf, &intf->conf, sizeof(conf));
+ memcpy(&conf, &vif->bss_conf, sizeof(conf));
delayed_flags = intf->delayed_flags;
intf->delayed_flags = 0;
@@ -500,7 +499,9 @@ void rt2x00lib_txdone(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
+ u8 rate_idx, rate_flags;
/*
* Unmap the skb.
@@ -530,14 +531,18 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->link.qual.tx_failed +=
test_bit(TXDONE_FAILURE, &txdesc->flags);
+ rate_idx = skbdesc->tx_rate_idx;
+ rate_flags = skbdesc->tx_rate_flags;
+
/*
* Initialize TX status
*/
memset(&tx_info->status, 0, sizeof(tx_info->status));
tx_info->status.ack_signal = 0;
- tx_info->status.excessive_retries =
- test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
- tx_info->status.retry_count = txdesc->retry;
+ tx_info->status.rates[0].idx = rate_idx;
+ tx_info->status.rates[0].flags = rate_flags;
+ tx_info->status.rates[0].count = txdesc->retry + 1;
+ tx_info->status.rates[1].idx = -1; /* terminate */
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
@@ -546,7 +551,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
- if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
@@ -570,7 +575,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
entry->skb = NULL;
entry->flags = 0;
- rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry);
+ rt2x00dev->ops->lib->clear_entry(entry);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
@@ -631,7 +636,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* provided seperately (through hardware descriptor)
* in which case we should reinsert the data into the frame.
*/
- if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
+ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
+ (rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
rt2x00crypto_rx_insert_iv(entry->skb, align,
header_length, &rxdesc);
} else if (align) {
@@ -702,7 +708,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
entry->skb = skb;
entry->flags = 0;
- rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry);
+ rt2x00dev->ops->lib->clear_entry(entry);
rt2x00queue_index_inc(entry->queue, Q_INDEX);
}
@@ -713,31 +719,31 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
*/
const struct rt2x00_rate rt2x00_supported_rates[12] = {
{
- .flags = DEV_RATE_CCK | DEV_RATE_BASIC,
+ .flags = DEV_RATE_CCK,
.bitrate = 10,
.ratemask = BIT(0),
.plcp = 0x00,
},
{
- .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 20,
.ratemask = BIT(1),
.plcp = 0x01,
},
{
- .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 55,
.ratemask = BIT(2),
.plcp = 0x02,
},
{
- .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC,
+ .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE,
.bitrate = 110,
.ratemask = BIT(3),
.plcp = 0x03,
},
{
- .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .flags = DEV_RATE_OFDM,
.bitrate = 60,
.ratemask = BIT(4),
.plcp = 0x0b,
@@ -749,7 +755,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = {
.plcp = 0x0f,
},
{
- .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .flags = DEV_RATE_OFDM,
.bitrate = 120,
.ratemask = BIT(6),
.plcp = 0x0a,
@@ -761,7 +767,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = {
.plcp = 0x0e,
},
{
- .flags = DEV_RATE_OFDM | DEV_RATE_BASIC,
+ .flags = DEV_RATE_OFDM,
.bitrate = 240,
.ratemask = BIT(8),
.plcp = 0x09,
@@ -1046,16 +1052,24 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{
int retval = -ENOMEM;
+ mutex_init(&rt2x00dev->csr_mutex);
+
/*
* Make room for rt2x00_intf inside the per-interface
* structure ieee80211_vif.
*/
rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
- rt2x00dev->hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ /*
+ * Determine which operating modes are supported, all modes
+ * which require beaconing, depend on the availability of
+ * beacon entries.
+ */
+ rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ if (rt2x00dev->ops->bcn->entry_num > 0)
+ rt2x00dev->hw->wiphy->interface_modes |=
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP);
/*
* Let the driver probe the device to detect the capabilities.
@@ -1247,7 +1261,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
/*
* Reconfigure device.
*/
- retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
+ retval = rt2x00mac_config(rt2x00dev->hw, ~0);
if (retval)
goto exit;
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index b362a1cf3f8..68f4e0fc35b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -72,49 +72,33 @@ void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
}
}
-void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
+static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled)
{
- struct rt2x00_led *led = &rt2x00dev->led_qual;
- unsigned int brightness;
+ unsigned int brightness = enabled ? LED_FULL : LED_OFF;
- if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED))
+ if (!(led->flags & LED_REGISTERED))
return;
- brightness = enabled ? LED_FULL : LED_OFF;
- if (brightness != led->led_dev.brightness) {
- led->led_dev.brightness_set(&led->led_dev, brightness);
- led->led_dev.brightness = brightness;
- }
+ led->led_dev.brightness_set(&led->led_dev, brightness);
+ led->led_dev.brightness = brightness;
}
-void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
+void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
{
- struct rt2x00_led *led = &rt2x00dev->led_assoc;
- unsigned int brightness;
-
- if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED))
- return;
+ if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY)
+ rt2x00led_led_simple(&rt2x00dev->led_qual, enabled);
+}
- brightness = enabled ? LED_FULL : LED_OFF;
- if (brightness != led->led_dev.brightness) {
- led->led_dev.brightness_set(&led->led_dev, brightness);
- led->led_dev.brightness = brightness;
- }
+void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
+{
+ if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC)
+ rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled);
}
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
{
- struct rt2x00_led *led = &rt2x00dev->led_radio;
- unsigned int brightness;
-
- if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED))
- return;
-
- brightness = enabled ? LED_FULL : LED_OFF;
- if (brightness != led->led_dev.brightness) {
- led->led_dev.brightness_set(&led->led_dev, brightness);
- led->led_dev.brightness = brightness;
- }
+ if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC)
+ rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
}
static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
@@ -125,6 +109,7 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
int retval;
led->led_dev.name = name;
+ led->led_dev.brightness = LED_OFF;
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
@@ -199,7 +184,16 @@ exit_fail:
static void rt2x00leds_unregister_led(struct rt2x00_led *led)
{
led_classdev_unregister(&led->led_dev);
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+
+ /*
+ * This might look weird, but when we are unregistering while
+ * suspended the led is already off, and since we haven't
+ * fully resumed yet, access to the device might not be
+ * possible yet.
+ */
+ if (!(led->led_dev.flags & LED_SUSPENDED))
+ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+
led->flags &= ~LED_REGISTERED;
}
@@ -213,22 +207,40 @@ void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
rt2x00leds_unregister_led(&rt2x00dev->led_radio);
}
+static inline void rt2x00leds_suspend_led(struct rt2x00_led *led)
+{
+ led_classdev_suspend(&led->led_dev);
+
+ /* This shouldn't be needed, but just to be safe */
+ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+ led->led_dev.brightness = LED_OFF;
+}
+
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
- led_classdev_suspend(&rt2x00dev->led_qual.led_dev);
+ rt2x00leds_suspend_led(&rt2x00dev->led_qual);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
- led_classdev_suspend(&rt2x00dev->led_assoc.led_dev);
+ rt2x00leds_suspend_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
- led_classdev_suspend(&rt2x00dev->led_radio.led_dev);
+ rt2x00leds_suspend_led(&rt2x00dev->led_radio);
+}
+
+static inline void rt2x00leds_resume_led(struct rt2x00_led *led)
+{
+ led_classdev_resume(&led->led_dev);
+
+ /* Device might have enabled the LEDS during resume */
+ led->led_dev.brightness_set(&led->led_dev, LED_OFF);
+ led->led_dev.brightness = LED_OFF;
}
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_radio.flags & LED_REGISTERED)
- led_classdev_resume(&rt2x00dev->led_radio.led_dev);
+ rt2x00leds_resume_led(&rt2x00dev->led_radio);
if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
- led_classdev_resume(&rt2x00dev->led_assoc.led_dev);
+ rt2x00leds_resume_led(&rt2x00dev->led_assoc);
if (rt2x00dev->led_qual.flags & LED_REGISTERED)
- led_classdev_resume(&rt2x00dev->led_qual.led_dev);
+ rt2x00leds_resume_led(&rt2x00dev->led_qual);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 797eb619aa0..03024327767 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -43,7 +43,6 @@ struct rt2x00_rate {
#define DEV_RATE_CCK 0x0001
#define DEV_RATE_OFDM 0x0002
#define DEV_RATE_SHORT_PREAMBLE 0x0004
-#define DEV_RATE_BASIC 0x0008
unsigned short bitrate; /* In 100kbit/s */
unsigned short ratemask;
@@ -94,9 +93,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf,
struct ieee80211_bss_conf *conf);
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
- enum antenna rx, enum antenna tx);
+ struct antenna_setup *ant);
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_conf *conf, const int force_config);
+ struct ieee80211_conf *conf,
+ const unsigned int changed_flags);
/**
* DOC: Queue handlers
@@ -150,8 +150,16 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
*/
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
-void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev);
-void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev);
+/**
+ * rt2x00queue_init_queues - Initialize all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to clear all
+ * index numbers and set the queue entry to the correct initialization
+ * state.
+ */
+void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev);
+
int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev);
int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev);
@@ -210,7 +218,10 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
*/
#ifdef CONFIG_RT2X00_LIB_CRYPTO
enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
+void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc);
unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info);
+void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len);
void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len);
void rt2x00crypto_tx_insert_iv(struct sk_buff *skb);
void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
@@ -222,11 +233,21 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *
return CIPHER_NONE;
}
+static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
+{
+}
+
static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
{
return 0;
}
+static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb,
+ unsigned int iv_len)
+{
+}
+
static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
unsigned int iv_len)
{
@@ -242,7 +263,7 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc)
{
}
-#endif
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
* RFkill handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 2c6cc5c374f..38edee5fe16 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
unsigned int data_length;
int retval = 0;
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
data_length = sizeof(struct ieee80211_cts);
else
data_length = sizeof(struct ieee80211_rts);
@@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
- rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
- rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+ rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
+ rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
@@ -79,12 +79,10 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
* RTS/CTS frame should use the length of the frame plus any
* encryption overhead that will be added by the hardware.
*/
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (!frag_skb->do_not_encrypt)
data_length += rt2x00crypto_tx_overhead(tx_info);
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, data_length, tx_info,
(struct ieee80211_cts *)(skb->data));
@@ -132,8 +130,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
"Please file bug report to %s.\n", qid, DRV_PROJECT);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ goto exit_fail;
}
/*
@@ -146,8 +143,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* inside the hardware.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
- if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
- IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+ if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
+ IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
!rt2x00dev->ops->hw->set_rts_threshold) {
if (rt2x00queue_available(queue) <= 1)
goto exit_fail;
@@ -335,10 +332,10 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- int radio_on;
+ struct ieee80211_conf *conf = &hw->conf;
int status;
/*
@@ -355,7 +352,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
* some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled.
*/
- radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
if (conf->radio_enabled) {
/* For programming the values, we have to turn RX off */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
@@ -369,7 +365,18 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
* When we've just turned on the radio, we want to reprogram
* everything to ensure a consistent state
*/
- rt2x00lib_config(rt2x00dev, conf, !radio_on);
+ rt2x00lib_config(rt2x00dev, conf, changed);
+
+ /*
+ * The radio was enabled, configure the antenna to the
+ * default settings, the link tuner will later start
+ * continue configuring the antenna based on the software
+ * diversity. But for non-diversity configurations, we need
+ * to have configured the correct state now.
+ */
+ if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED)
+ rt2x00lib_config_antenna(rt2x00dev,
+ &rt2x00dev->default_ant);
/* Turn RX back on */
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
@@ -480,12 +487,15 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_sta *sta;
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
struct rt2x00lib_crypto crypto;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return 0;
+ else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
return -EOPNOTSUPP;
else if (key->keylen > 32)
return -ENOSPC;
@@ -528,6 +538,17 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
memcpy(&crypto.key, &key->key[0], key->keylen);
/*
+ * Discover the Association ID from mac80211.
+ * Some drivers need this information when updating the
+ * hardware key (either adding or removing).
+ */
+ rcu_read_lock();
+ sta = ieee80211_find_sta(hw, address);
+ if (sta)
+ crypto.aid = sta->aid;
+ rcu_read_unlock();
+
+ /*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
* 0) BSS0 key0
@@ -625,7 +646,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
- if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
+ if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
else
@@ -633,7 +654,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
}
spin_lock(&intf->lock);
- memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
if (delayed) {
intf->delayed_flags |= delayed;
schedule_work(&rt2x00dev->intf_work);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index adf2876ed8a..d52b22b82d1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -32,24 +32,46 @@
#include "rt2x00pci.h"
/*
+ * Register access.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
+
+/*
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct queue_entry *entry)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
- u32 word;
-
- rt2x00_desc_read(entry_priv->desc, 0, &word);
/*
* This should not happen, we already checked the entry
* was ours. When the hardware disagrees there has been
* a queue corruption!
*/
- if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
- rt2x00_get_field32(word, TXD_ENTRY_VALID))) {
- ERROR(entry->queue->rt2x00dev,
+ if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {
+ ERROR(rt2x00dev,
"Corrupt queue %d, accessing entry which is not ours.\n"
"Please file bug report to %s.\n",
entry->queue->qid, DRV_PROJECT);
@@ -76,14 +98,12 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
- u32 word;
while (1) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
entry_priv = entry->priv_data;
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+ if (rt2x00dev->ops->lib->get_entry_state(entry))
break;
/*
@@ -222,8 +242,7 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
{
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
- rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0),
- pci_resource_len(pci_dev, 0));
+ rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
if (!rt2x00dev->csr.base)
goto exit;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 80bf97c03e2..9c0a4d77bc1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -44,21 +44,10 @@
#define REGISTER_BUSY_DELAY 100
/*
- * Descriptor availability flags.
- * All PCI device descriptors have these 2 flags
- * with the exact same definition.
- * By storing them here we can use them inside rt2x00pci
- * for some simple entry availability checking.
- */
-#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
-#define TXD_ENTRY_VALID FIELD32(0x00000002)
-#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
-
-/*
* Register access.
*/
static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
- const unsigned long offset,
+ const unsigned int offset,
u32 *value)
{
*value = readl(rt2x00dev->csr.base + offset);
@@ -66,14 +55,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
static inline void
rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
- const unsigned long offset,
+ const unsigned int offset,
void *value, const u16 length)
{
memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
}
static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
- const unsigned long offset,
+ const unsigned int offset,
u32 value)
{
writel(value, rt2x00dev->csr.base + offset);
@@ -81,13 +70,31 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
static inline void
rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
- const unsigned long offset,
+ const unsigned int offset,
const void *value, const u16 length)
{
memcpy_toio(rt2x00dev->csr.base + offset, value, length);
}
/**
+ * rt2x00pci_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg);
+
+/**
* rt2x00pci_write_tx_data - Initialize data for TX operation
* @entry: The entry where the frame is located
*
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 451d410ecda..eaec6bd93ed 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -55,14 +55,12 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
/*
* For IV/EIV/ICV assembly we must make sure there is
* at least 8 bytes bytes available in headroom for IV/EIV
- * and 4 bytes for ICV data as tailroon.
+ * and 8 bytes for ICV data as tailroon.
*/
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
head_size += 8;
- tail_size += 4;
+ tail_size += 8;
}
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
* Allocate skbuffer.
@@ -174,7 +172,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
txdesc->cw_max = entry->queue->cw_max;
txdesc->aifs = entry->queue->aifs;
- /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */
+ /* Data length + CRC */
data_length = entry->skb->len + 4;
/*
@@ -183,34 +181,17 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
-#ifdef CONFIG_RT2X00_LIB_CRYPTO
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) &&
!entry->skb->do_not_encrypt) {
- struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
-
- __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
-
- txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
-
- if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
- __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
-
- txdesc->key_idx = hw_key->hw_key_idx;
- txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+ /* Apply crypto specific descriptor information */
+ rt2x00crypto_create_tx_descriptor(entry, txdesc);
/*
* Extend frame length to include all encryption overhead
* that will be added by the hardware.
*/
data_length += rt2x00crypto_tx_overhead(tx_info);
-
- if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
- __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
-
- if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
- __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
}
-#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
* Check if this is a RTS/CTS frame
@@ -230,8 +211,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Determine retry information.
*/
- txdesc->retry_limit = tx_info->control.retry_limit;
- if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+ txdesc->retry_limit = tx_info->control.rates[0].count - 1;
+ if (txdesc->retry_limit >= rt2x00dev->long_retry)
__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
/*
@@ -312,8 +293,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
/*
* Convert length to microseconds.
*/
- residual = get_duration_res(data_length, hwrate->bitrate);
- duration = get_duration(data_length, hwrate->bitrate);
+ residual = GET_DURATION_RES(data_length, hwrate->bitrate);
+ duration = GET_DURATION(data_length, hwrate->bitrate);
if (residual != 0) {
duration++;
@@ -371,13 +352,15 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *tx_info;
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct txentry_desc txdesc;
struct skb_frame_desc *skbdesc;
unsigned int iv_len = 0;
+ u8 rate_idx, rate_flags;
if (unlikely(rt2x00queue_full(queue)))
- return -EINVAL;
+ return -ENOBUFS;
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) {
ERROR(queue->rt2x00dev,
@@ -399,13 +382,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
/*
- * All information is retreived from the skb->cb array,
+ * All information is retrieved from the skb->cb array,
* now we should claim ownership of the driver part of that
- * array.
+ * array, preserving the bitrate index and flags.
*/
- skbdesc = get_skb_frame_desc(entry->skb);
+ tx_info = IEEE80211_SKB_CB(skb);
+ rate_idx = tx_info->control.rates[0].idx;
+ rate_flags = tx_info->control.rates[0].flags;
+ skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
+ skbdesc->tx_rate_idx = rate_idx;
+ skbdesc->tx_rate_flags = rate_flags;
/*
* When hardware encryption is supported, and this frame
@@ -414,19 +402,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
- rt2x00crypto_tx_remove_iv(skb, iv_len);
+ if (test_bit(CONFIG_CRYPTO_COPY_IV, &queue->rt2x00dev->flags))
+ rt2x00crypto_tx_copy_iv(skb, iv_len);
+ else
+ rt2x00crypto_tx_remove_iv(skb, iv_len);
}
/*
* It could be possible that the queue was corrupted and this
- * call failed. Just drop the frame, we cannot rollback and pass
- * the frame to mac80211 because the skb->cb has now been tainted.
+ * call failed. Since we always return NETDEV_TX_OK to mac80211,
+ * this frame will simply be dropped.
*/
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
- return 0;
+ return -EIO;
}
if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
@@ -556,7 +546,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
queue->length++;
} else if (index == Q_INDEX_DONE) {
queue->length--;
- queue->count ++;
+ queue->count++;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -575,40 +565,18 @@ static void rt2x00queue_reset(struct data_queue *queue)
spin_unlock_irqrestore(&queue->lock, irqflags);
}
-void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue = rt2x00dev->rx;
- unsigned int i;
-
- rt2x00queue_reset(queue);
-
- if (!rt2x00dev->ops->lib->init_rxentry)
- return;
-
- for (i = 0; i < queue->limit; i++) {
- queue->entries[i].flags = 0;
-
- rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
- &queue->entries[i]);
- }
-}
-
-void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
+void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
unsigned int i;
- txall_queue_for_each(rt2x00dev, queue) {
+ queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);
- if (!rt2x00dev->ops->lib->init_txentry)
- continue;
-
for (i = 0; i < queue->limit; i++) {
queue->entries[i].flags = 0;
- rt2x00dev->ops->lib->init_txentry(rt2x00dev,
- &queue->entries[i]);
+ rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
}
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 9dbf04f0f04..28293715340 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -104,22 +104,25 @@ enum skb_frame_desc_flags {
*
* @flags: Frame flags, see &enum skb_frame_desc_flags.
* @desc_len: Length of the frame descriptor.
+ * @tx_rate_idx: the index of the TX rate, used for TX status reporting
+ * @tx_rate_flags: the TX rate flags, used for TX status reporting
* @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside
* of the scope of the skb->data pointer.
- * @iv: IV data used during encryption/decryption.
- * @eiv: EIV data used during encryption/decryption.
+ * @iv: IV/EIV data used during encryption/decryption.
* @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
* @entry: The entry to which this sk buffer belongs.
*/
struct skb_frame_desc {
- unsigned int flags;
+ u8 flags;
+
+ u8 desc_len;
+ u8 tx_rate_idx;
+ u8 tx_rate_flags;
- unsigned int desc_len;
void *desc;
- __le32 iv;
- __le32 eiv;
+ __le32 iv[2];
dma_addr_t skb_dma;
@@ -143,11 +146,15 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
* @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value.
* @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value.
* @RXDONE_MY_BSS: Does this frame originate from device's BSS.
+ * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data.
+ * @RXDONE_CRYPTO_ICV: Driver provided ICV data.
*/
enum rxdone_entry_desc_flags {
RXDONE_SIGNAL_PLCP = 1 << 0,
RXDONE_SIGNAL_BITRATE = 1 << 1,
RXDONE_MY_BSS = 1 << 2,
+ RXDONE_CRYPTO_IV = 1 << 3,
+ RXDONE_CRYPTO_ICV = 1 << 4,
};
/**
@@ -163,8 +170,7 @@ enum rxdone_entry_desc_flags {
* @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
* @cipher: Cipher type used during decryption.
* @cipher_status: Decryption status.
- * @iv: IV data used during decryption.
- * @eiv: EIV data used during decryption.
+ * @iv: IV/EIV data used during decryption.
* @icv: ICV data used during decryption.
*/
struct rxdone_entry_desc {
@@ -177,8 +183,7 @@ struct rxdone_entry_desc {
u8 cipher;
u8 cipher_status;
- __le32 iv;
- __le32 eiv;
+ __le32 iv[2];
__le32 icv;
};
@@ -375,6 +380,8 @@ enum queue_index {
* @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
* @data_size: Maximum data size for the frames in this queue.
* @desc_size: Hardware descriptor size for the data in this queue.
+ * @usb_endpoint: Device endpoint used for communication (USB only)
+ * @usb_maxpacket: Max packet size for given endpoint (USB only)
*/
struct data_queue {
struct rt2x00_dev *rt2x00dev;
@@ -396,6 +403,9 @@ struct data_queue {
unsigned short data_size;
unsigned short desc_size;
+
+ unsigned short usb_endpoint;
+ unsigned short usb_maxpacket;
};
/**
@@ -439,6 +449,19 @@ struct data_queue_desc {
&(__dev)->tx[(__dev)->ops->tx_queues]
/**
+ * queue_next - Return pointer to next queue in list (HELPER MACRO).
+ * @__queue: Current queue for which we need the next queue
+ *
+ * Using the current queue address we take the address directly
+ * after the queue to take the next queue. Note that this macro
+ * should be used carefully since it does not protect against
+ * moving past the end of the list. (See macros &queue_end and
+ * &tx_queue_end for determining the end of the queue).
+ */
+#define queue_next(__queue) \
+ &(__queue)[1]
+
+/**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO).
* @__entry: Pointer where the current queue entry will be stored in.
* @__start: Start queue pointer.
@@ -448,8 +471,8 @@ struct data_queue_desc {
*/
#define queue_loop(__entry, __start, __end) \
for ((__entry) = (__start); \
- prefetch(&(__entry)[1]), (__entry) != (__end); \
- (__entry) = &(__entry)[1])
+ prefetch(queue_next(__entry)), (__entry) != (__end);\
+ (__entry) = queue_next(__entry))
/**
* queue_for_each - Loop through all queues
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index b73a7e0aeed..83df312ac56 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
{
int status;
- BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex));
+ BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex));
/*
* Check for Cache availability.
@@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
{
int status;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
+ mutex_lock(&rt2x00dev->csr_mutex);
status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
requesttype, offset, buffer,
buffer_length, timeout);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
+ mutex_unlock(&rt2x00dev->csr_mutex);
return status;
}
@@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
unsigned char *tb;
u16 off, len, bsize;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
+ mutex_lock(&rt2x00dev->csr_mutex);
tb = (char *)buffer;
off = offset;
@@ -148,12 +148,34 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
off += bsize;
}
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
+ mutex_unlock(&rt2x00dev->csr_mutex);
return status;
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00usb_register_read_lock(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
/*
* TX data handlers.
*/
@@ -212,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
* length of the data to usb_fill_bulk_urb. Pass the skb
* to the driver to determine what the length should be.
*/
- length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);
usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, 1),
+ usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
@@ -351,28 +373,96 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
/*
* Device initialization handlers.
*/
-void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+void rt2x00usb_clear_entry(struct queue_entry *entry)
{
- struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct usb_device *usb_dev =
+ to_usb_device_intf(entry->queue->rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ int pipe;
- usb_fill_bulk_urb(entry_priv->urb, usb_dev,
- usb_rcvbulkpipe(usb_dev, 1),
- entry->skb->data, entry->skb->len,
- rt2x00usb_interrupt_rxdone, entry);
+ if (entry->queue->qid == QID_RX) {
+ pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ } else {
+ entry->flags = 0;
+ }
}
-EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
+EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
-void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+ struct usb_endpoint_descriptor *ep_desc)
{
- entry->flags = 0;
+ struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+ int pipe;
+
+ queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+ if (queue->qid == QID_RX) {
+ pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+ } else {
+ pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+ queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+ }
+
+ if (!queue->usb_maxpacket)
+ queue->usb_maxpacket = 1;
+}
+
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
+{
+ struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+ struct usb_host_interface *intf_desc = intf->cur_altsetting;
+ struct usb_endpoint_descriptor *ep_desc;
+ struct data_queue *queue = rt2x00dev->tx;
+ struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+ unsigned int i;
+
+ /*
+ * Walk through all available endpoints to search for "bulk in"
+ * and "bulk out" endpoints. When we find such endpoints collect
+ * the information we need from the descriptor and assign it
+ * to the queue.
+ */
+ for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &intf_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc)) {
+ rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+ } else if (usb_endpoint_is_bulk_out(ep_desc)) {
+ rt2x00usb_assign_endpoint(queue, ep_desc);
+
+ if (queue != queue_end(rt2x00dev))
+ queue = queue_next(queue);
+ tx_ep_desc = ep_desc;
+ }
+ }
+
+ /*
+ * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+ */
+ if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+ ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+ return -EPIPE;
+ }
+
+ /*
+ * It might be possible not all queues have a dedicated endpoint.
+ * Loop through all TX queues and copy the endpoint information
+ * which we have gathered from already assigned endpoints.
+ */
+ txall_queue_for_each(rt2x00dev, queue) {
+ if (!queue->usb_endpoint)
+ rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+ }
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
@@ -445,6 +535,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
int status;
/*
+ * Find endpoints for each queue
+ */
+ status = rt2x00usb_find_endpoints(rt2x00dev);
+ if (status)
+ goto exit;
+
+ /*
* Allocate DMA
*/
queue_for_each(rt2x00dev, queue) {
@@ -534,12 +631,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->dev = &usb_intf->dev;
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
- mutex_init(&rt2x00dev->usb_cache_mutex);
-
- rt2x00dev->usb_maxpacket =
- usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
- if (!rt2x00dev->usb_maxpacket)
- rt2x00dev->usb_maxpacket = 1;
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 3b4a67417f9..2bd4ac855f5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
REGISTER_TIMEOUT16(length));
}
+/**
+ * rt2x00usb_regbusy_read - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_read_lock - Read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+/**
+ * rt2x00usb_register_multiread - Read 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Pointer to where register contents should be stored
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length,
+ REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_register_write - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_write_lock - Write 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_req_buff_lock().
+ */
+static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(reg), REGISTER_TIMEOUT);
+}
+
+/**
+ * rt2x00usb_register_multiwrite - Write 32bit register words
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @value: Data which should be written
+ * @length: Length of the data
+ *
+ * This function is a simple wrapper for 32bit register access
+ * through rt2x00usb_vendor_request_buff().
+ */
+static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length,
+ REGISTER_TIMEOUT32(length));
+}
+
+/**
+ * rt2x00usb_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ struct rt2x00_field32 field,
+ u32 *reg);
+
/*
* Radio handlers
*/
@@ -286,10 +422,7 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
/*
* Device initialization handlers.
*/
-void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
-void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry);
+void rt2x00usb_clear_entry(struct queue_entry *entry);
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index a461620b489..987e89009f7 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -55,45 +55,36 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* the access attempt is considered to have failed,
* and we will print an error.
*/
-static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+ H2M_MAILBOX_CSR_OWNER, (__reg))
static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the data into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ }
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -101,66 +92,58 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- return;
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the request into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt61pci_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
- return;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
}
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
+ mutex_lock(&rt2x00dev->csr_mutex);
- ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
- return;
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
- rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
- rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
- rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
#ifdef CONFIG_RT2X00_LIB_LEDS
@@ -175,25 +158,27 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
+ mutex_lock(&rt2x00dev->csr_mutex);
- if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) {
- ERROR(rt2x00dev, "mcu request error. "
- "Request 0x%02x failed for token 0x%02x.\n",
- command, token);
- return;
+ /*
+ * Wait until the MCU becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
}
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
- rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+ mutex_unlock(&rt2x00dev->csr_mutex);
- rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
- rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
- rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
- rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
}
#endif /* CONFIG_RT2X00_LIB_LEDS */
@@ -228,43 +213,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 *data)
-{
- rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 data)
-{
- rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
static const struct rt2x00debug rt61pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt61pci_read_csr,
- .write = rt61pci_write_csr,
+ .read = rt2x00pci_register_read,
+ .write = rt2x00pci_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
.word_count = CSR_REG_SIZE / sizeof(u32),
},
.eeprom = {
.read = rt2x00_eeprom_read,
.write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
.word_size = sizeof(u16),
.word_count = EEPROM_SIZE / sizeof(u16),
},
.bbp = {
.read = rt61pci_bbp_read,
.write = rt61pci_bbp_write,
+ .word_base = BBP_BASE,
.word_size = sizeof(u8),
.word_count = BBP_SIZE / sizeof(u8),
},
.rf = {
.read = rt2x00_rf_read,
.write = rt61pci_rf_write,
+ .word_base = RF_BASE,
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
@@ -643,95 +619,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-
-static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_conf *libconf)
-{
- u16 eeprom;
- short lna_gain = 0;
-
- if (libconf->band == IEEE80211_BAND_2GHZ) {
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
- lna_gain += 14;
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
- lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
- } else {
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
- lna_gain += 14;
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
- lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
- }
-
- rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int basic_rate_mask)
-{
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
- struct rf_channel *rf, const int txpower)
-{
- u8 r3;
- u8 r94;
- u8 smart;
- rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
- rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
- smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527));
-
- rt61pci_bbp_read(rt2x00dev, 3, &r3);
- rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
- rt61pci_bbp_write(rt2x00dev, 3, r3);
-
- r94 = 6;
- if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
- r94 += txpower - MAX_TXPOWER;
- else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
- r94 += txpower;
- rt61pci_bbp_write(rt2x00dev, 94, r94);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
- rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
- rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
- rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
- rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
- udelay(200);
-
- rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
- rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
- rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
- rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
- udelay(200);
-
- rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
- rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
- rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
- rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
- msleep(1);
-}
-
-static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
- const int txpower)
-{
- struct rf_channel rf;
-
- rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
- rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
- rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
- rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
- rt61pci_config_channel(rt2x00dev, &rf, txpower);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
}
static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -906,8 +805,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
{ 98, { 0x48, 0x48 } },
};
-static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
{
const struct antenna_sel *sel;
unsigned int lna;
@@ -954,20 +853,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
}
}
-static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u16 eeprom;
+ short lna_gain = 0;
+
+ if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ lna_gain += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ lna_gain += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ }
+
+ rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf)
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
- rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
- rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
- rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -990,16 +974,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
/* Always recalculate LNA gain before changing configuration */
rt61pci_config_lna_gain(rt2x00dev, libconf);
- if (flags & CONFIG_UPDATE_PHYMODE)
- rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
- if (flags & CONFIG_UPDATE_CHANNEL)
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt61pci_config_channel(rt2x00dev, &libconf->rf,
libconf->conf->power_level);
- if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+ !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
- if (flags & CONFIG_UPDATE_ANTENNA)
- rt61pci_config_antenna(rt2x00dev, &libconf->ant);
- if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt61pci_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
rt61pci_config_duration(rt2x00dev, libconf);
}
@@ -1263,33 +1246,44 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
/*
* Initialization functions.
*/
-static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static bool rt61pci_get_entry_state(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 5, &word);
- rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
- skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 5, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+
+ return rt2x00_get_field32(word, RXD_W0_OWNER_NIC);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ rt2x00_get_field32(word, TXD_W0_VALID));
+ }
}
-static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+static void rt61pci_clear_entry(struct queue_entry *entry)
{
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
- rt2x00_desc_read(entry_priv->desc, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_VALID, 0);
- rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(entry_priv->desc, 0, word);
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 5, &word);
+ rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+ skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 5, word);
+
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+ }
}
static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -1784,8 +1778,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 2, word);
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
- _rt2x00_desc_write(txd, 3, skbdesc->iv);
- _rt2x00_desc_write(txd, 4, skbdesc->eiv);
+ _rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+ _rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
}
rt2x00_desc_read(txd, 5, &word);
@@ -1934,7 +1928,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
}
static void rt61pci_fill_rxdone(struct queue_entry *entry,
- struct rxdone_entry_desc *rxdesc)
+ struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1955,9 +1949,12 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
}
if (rxdesc->cipher != CIPHER_NONE) {
- _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv);
- _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv);
+ _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]);
+ _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]);
+ rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
_rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv);
+ rxdesc->dev_flags |= RXDONE_CRYPTO_ICV;
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
@@ -2175,10 +2172,8 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2630,20 +2625,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry, u32 long_retry)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
- rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-
- return 0;
-}
-
static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
@@ -2726,7 +2707,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
- .set_retry_limit = rt61pci_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
@@ -2741,8 +2721,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.load_firmware = rt61pci_load_firmware,
.initialize = rt2x00pci_initialize,
.uninitialize = rt2x00pci_uninitialize,
- .init_rxentry = rt61pci_init_rxentry,
- .init_txentry = rt61pci_init_txentry,
+ .get_entry_state = rt61pci_get_entry_state,
+ .clear_entry = rt61pci_clear_entry,
.set_device_state = rt61pci_set_device_state,
.rfkill_poll = rt61pci_rfkill_poll,
.link_stats = rt61pci_link_stats,
@@ -2758,6 +2738,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.config_filter = rt61pci_config_filter,
.config_intf = rt61pci_config_intf,
.config_erp = rt61pci_config_erp,
+ .config_ant = rt61pci_config_ant,
.config = rt61pci_config,
};
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 8ec1451308c..65fe3332364 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -48,7 +48,9 @@
#define CSR_REG_SIZE 0x04b0
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0100
+#define BBP_BASE 0x0000
#define BBP_SIZE 0x0080
+#define RF_BASE 0x0000
#define RF_SIZE 0x0014
/*
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 934f8e03c5a..d638a8a5937 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
* Register access.
* All access to the CSR registers will go through the methods
- * rt73usb_register_read and rt73usb_register_write.
+ * rt2x00usb_register_read and rt2x00usb_register_write.
* BBP and RF register require indirect register access,
* and use the CSR registers BBPCSR and RFCSR to achieve this.
* These indirect registers work with busy bits,
@@ -55,113 +55,35 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* between each attampt. When the busy bit is still set at that time,
* the access attempt is considered to have failed,
* and we will print an error.
- * The _lock versions must be used if you already hold the usb_cache_mutex
+ * The _lock versions must be used if you already hold the csr_mutex
*/
-static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 *value)
-{
- __le32 reg;
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
- *value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 *value)
-{
- __le32 reg;
- rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
- *value = le32_to_cpu(reg);
-}
-
-static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
- USB_VENDOR_REQUEST_IN, offset,
- value, length,
- REGISTER_TIMEOUT32(length));
-}
-
-static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 value)
-{
- __le32 reg = cpu_to_le32(value);
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset, u32 value)
-{
- __le32 reg = cpu_to_le32(value);
- rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- &reg, sizeof(u32), REGISTER_TIMEOUT);
-}
-
-static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, offset,
- value, length,
- REGISTER_TIMEOUT32(length));
-}
-
-static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
-{
- u32 reg;
- unsigned int i;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- break;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- return reg;
-}
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u32 reg;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Wait until the BBP becomes ready.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
-
- /*
- * Write the data into the BBP.
- */
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
-
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+ }
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -169,123 +91,95 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
-
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * Write the request into the BBP.
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
*/
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
- rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
- rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
- /*
- * Wait until the BBP becomes ready.
- */
- reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
- goto exit_fail;
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-
- return;
-
-exit_fail:
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u32 reg;
- unsigned int i;
if (!word)
return;
- mutex_lock(&rt2x00dev->usb_cache_mutex);
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, &reg);
- if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
- goto rf_write;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
- return;
-
-rf_write:
- reg = 0;
- rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ mutex_lock(&rt2x00dev->csr_mutex);
/*
- * RF5225 and RF2527 contain 21 bits per RF register value,
- * all others contain 20 bits.
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
*/
- rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
- 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527)));
- rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
- rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
-
- rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
- rt2x00_rf_write(rt2x00dev, word, value);
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
-}
-
-#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 *data)
-{
- rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ /*
+ * RF5225 and RF2527 contain 21 bits per RF register value,
+ * all others contain 20 bits.
+ */
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+ 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527)));
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
-static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev,
- const unsigned int word, u32 data)
-{
- rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+ mutex_unlock(&rt2x00dev->csr_mutex);
}
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
static const struct rt2x00debug rt73usb_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt73usb_read_csr,
- .write = rt73usb_write_csr,
+ .read = rt2x00usb_register_read,
+ .write = rt2x00usb_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
.word_count = CSR_REG_SIZE / sizeof(u32),
},
.eeprom = {
.read = rt2x00_eeprom_read,
.write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
.word_size = sizeof(u16),
.word_count = EEPROM_SIZE / sizeof(u16),
},
.bbp = {
.read = rt73usb_bbp_read,
.write = rt73usb_bbp_write,
+ .word_base = BBP_BASE,
.word_size = sizeof(u8),
.word_count = BBP_SIZE / sizeof(u8),
},
.rf = {
.read = rt2x00_rf_read,
.write = rt73usb_rf_write,
+ .word_base = RF_BASE,
.word_size = sizeof(u32),
.word_count = RF_SIZE / sizeof(u32),
},
@@ -341,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg;
- rt73usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
+ rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, &reg);
rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
- rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
+ rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg);
return 0;
}
@@ -387,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = (0xf << crypto->bssidx);
- rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
reg &= mask;
if (reg && reg == mask)
@@ -424,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
field.bit_offset = (3 * key->hw_key_idx);
field.bit_mask = 0x7 << field.bit_offset;
- rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR1, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg);
} else {
field.bit_offset = (3 * (key->hw_key_idx - 8));
field.bit_mask = 0x7 << field.bit_offset;
- rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR5, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg);
}
/*
@@ -456,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = 1 << key->hw_key_idx;
- rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR0, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg);
return 0;
}
@@ -486,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* When both registers are full, we drop the key,
* otherwise we use the first invalid entry.
*/
- rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
if (reg && reg == ~0) {
key->hw_key_idx = 32;
- rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
if (reg && reg == ~0)
return -ENOSPC;
}
@@ -517,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* Send the address and cipher type to the hardware register.
* This data fits within the CSR cache size, so we can use
- * rt73usb_register_multiwrite() directly.
+ * rt2x00usb_register_multiwrite() directly.
*/
memset(&addr_entry, 0, sizeof(addr_entry));
memcpy(&addr_entry, crypto->address, ETH_ALEN);
addr_entry.cipher = crypto->cipher;
reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
- rt73usb_register_multiwrite(rt2x00dev, reg,
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
&addr_entry, sizeof(addr_entry));
/*
@@ -532,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* without this received frames will not be decrypted
* by the hardware.
*/
- rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR4, &reg);
reg |= (1 << crypto->bssidx);
- rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg);
/*
* The driver does not support the IV/EIV generation
@@ -557,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
if (key->hw_key_idx < 32) {
mask = 1 << key->hw_key_idx;
- rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR2, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg);
} else {
mask = 1 << (key->hw_key_idx - 32);
- rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, SEC_CSR3, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg);
}
return 0;
@@ -588,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
* and broadcast frames will always be accepted since
* there is no filter for it at this time.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
@@ -606,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
!(filter_flags & FIF_CONTROL));
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -625,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
* bits which (when set to 0) will invalidate the entire beacon.
*/
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt73usb_register_write(rt2x00dev, beacon_base, 0);
+ rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
/*
* Enable synchronisation.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
@@ -642,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg);
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2,
+ rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2,
conf->mac, sizeof(conf->mac));
}
@@ -651,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg);
- rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4,
+ rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4,
conf->bssid, sizeof(conf->bssid));
}
}
@@ -661,95 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
- struct rt2x00lib_conf *libconf)
-{
- u16 eeprom;
- short lna_gain = 0;
-
- if (libconf->band == IEEE80211_BAND_2GHZ) {
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
- lna_gain += 14;
-
- rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
- lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
- } else {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
- lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
- }
-
- rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int basic_rate_mask)
-{
- rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
- struct rf_channel *rf, const int txpower)
-{
- u8 r3;
- u8 r94;
- u8 smart;
-
- rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
- rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
- smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF2527));
-
- rt73usb_bbp_read(rt2x00dev, 3, &r3);
- rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
- rt73usb_bbp_write(rt2x00dev, 3, r3);
-
- r94 = 6;
- if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
- r94 += txpower - MAX_TXPOWER;
- else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
- r94 += txpower;
- rt73usb_bbp_write(rt2x00dev, 94, r94);
-
- rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
- rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
- rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
- rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
- rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
- rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
- rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
- rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
- rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
- rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
- rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
- rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
- udelay(10);
-}
-
-static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
- const int txpower)
-{
- struct rf_channel rf;
-
- rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
- rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
- rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
- rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
-
- rt73usb_config_channel(rt2x00dev, &rf, txpower);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg);
}
static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -869,8 +694,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
{ 98, { 0x48, 0x48 } },
};
-static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
- struct antenna_setup *ant)
+static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
{
const struct antenna_sel *sel;
unsigned int lna;
@@ -895,14 +720,14 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
- rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, PHY_CSR0, &reg);
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
(rt2x00dev->curr_band == IEEE80211_BAND_2GHZ));
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
(rt2x00dev->curr_band == IEEE80211_BAND_5GHZ));
- rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
rt2x00_rf(&rt2x00dev->chip, RF5225))
@@ -912,33 +737,111 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
rt73usb_config_antenna_2x(rt2x00dev, ant);
}
-static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf)
{
+ u16 eeprom;
+ short lna_gain = 0;
+
+ if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ lna_gain += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ } else {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ }
+
+ rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
u32 reg;
- rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
- rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
- rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
- rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
- rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
- rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
- rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
libconf->conf->beacon_int * 16);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
@@ -948,16 +851,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
/* Always recalculate LNA gain before changing configuration */
rt73usb_config_lna_gain(rt2x00dev, libconf);
- if (flags & CONFIG_UPDATE_PHYMODE)
- rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
- if (flags & CONFIG_UPDATE_CHANNEL)
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt73usb_config_channel(rt2x00dev, &libconf->rf,
libconf->conf->power_level);
- if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+ !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
- if (flags & CONFIG_UPDATE_ANTENNA)
- rt73usb_config_antenna(rt2x00dev, &libconf->ant);
- if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt73usb_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
rt73usb_config_duration(rt2x00dev, libconf);
}
@@ -972,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update FCS error count from register.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
/*
* Update False CCA count from register.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
@@ -1138,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
* Wait for stable hardware.
*/
for (i = 0; i < 100; i++) {
- rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg)
break;
msleep(1);
@@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
@@ -1195,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg);
/*
* CCK TXD BBP registers
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
@@ -1209,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg);
/*
* OFDM TXD BBP registers
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
- rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
- rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
- rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
- rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR6, &reg);
rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
- rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg);
- rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY;
- rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
/*
* Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
*/
- rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
- rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
- rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
reg = 0x000023b0;
if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
rt2x00_rf(&rt2x00dev->chip, RF2527))
rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
- rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
- rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
- rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
- rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
- rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
- rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg);
/*
* Clear all beacons
@@ -1287,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
* the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon.
*/
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
/*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
*/
- rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
- rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
- rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, STA_CSR2, &reg);
/*
* Reset MAC and BBP registers.
*/
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
- rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
- rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg);
return 0;
}
@@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
(state == STATE_RADIO_RX_OFF) ||
(state == STATE_RADIO_RX_OFF_LINK));
- rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1415,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
/*
* Disable synchronisation.
*/
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0);
rt2x00usb_disable_radio(rt2x00dev);
}
@@ -1433,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
put_to_sleep = (state != STATE_AWAKE);
- rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
- rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg);
/*
* Device is not guaranteed to be in the requested state yet.
@@ -1444,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
* device has entered the correct state.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR12, &reg);
state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
if (state == !put_to_sleep)
return 0;
@@ -1526,8 +1428,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 2, word);
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
- _rt2x00_desc_write(txd, 3, skbdesc->iv);
- _rt2x00_desc_write(txd, 4, skbdesc->eiv);
+ _rt2x00_desc_write(txd, 3, skbdesc->iv[0]);
+ _rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
}
rt2x00_desc_read(txd, 5, &word);
@@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Write entire beacon with descriptor to register.
@@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
entry->skb = NULL;
}
-static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb)
+static int rt73usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -1615,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
* The length _must_ be a multiple of 4,
* but it must _not_ be a multiple of the USB packet size.
*/
- length = roundup(skb->len, 4);
- length += (4 * !(length % rt2x00dev->usb_maxpacket));
+ length = roundup(entry->skb->len, 4);
+ length += (4 * !(length % entry->queue->usb_maxpacket));
return length;
}
@@ -1635,14 +1536,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
* For Wi-Fi faily generated beacons between participating stations.
* Set TBTT phase adaptive adjustment step to 8us (default 16us)
*/
- rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
}
@@ -1685,7 +1586,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
}
static void rt73usb_fill_rxdone(struct queue_entry *entry,
- struct rxdone_entry_desc *rxdesc)
+ struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@@ -1717,9 +1618,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
}
if (rxdesc->cipher != CIPHER_NONE) {
- _rt2x00_desc_read(rxd, 2, &rxdesc->iv);
- _rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
+ _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
+ _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]);
+ rxdesc->dev_flags |= RXDONE_CRYPTO_IV;
+
_rt2x00_desc_read(rxd, 4, &rxdesc->icv);
+ rxdesc->dev_flags |= RXDONE_CRYPTO_ICV;
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
@@ -1781,10 +1685,8 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1883,7 +1785,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
- rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) {
@@ -2211,20 +2113,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* IEEE80211 stack callback functions.
*/
-static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
- u32 short_retry, u32 long_retry)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- u32 reg;
-
- rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
- rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
- rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-
- return 0;
-}
-
static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
const struct ieee80211_tx_queue_params *params)
{
@@ -2251,33 +2139,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
field.bit_offset = queue_idx * 16;
field.bit_mask = 0xffff << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
- rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+ rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
} else if (queue_idx < 4) {
field.bit_offset = (queue_idx - 2) * 16;
field.bit_mask = 0xffff << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
- rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+ rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
}
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
- rt73usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->aifs);
- rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg);
- rt73usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_min);
- rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg);
- rt73usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
+ rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_max);
- rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg);
+ rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0;
}
@@ -2295,9 +2183,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
u64 tsf;
u32 reg;
- rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
- rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
return tsf;
@@ -2317,7 +2205,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.configure_filter = rt2x00mac_configure_filter,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
- .set_retry_limit = rt73usb_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
@@ -2331,8 +2218,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.load_firmware = rt73usb_load_firmware,
.initialize = rt2x00usb_initialize,
.uninitialize = rt2x00usb_uninitialize,
- .init_rxentry = rt2x00usb_init_rxentry,
- .init_txentry = rt2x00usb_init_txentry,
+ .clear_entry = rt2x00usb_clear_entry,
.set_device_state = rt73usb_set_device_state,
.link_stats = rt73usb_link_stats,
.reset_tuner = rt73usb_reset_tuner,
@@ -2348,6 +2234,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.config_filter = rt73usb_config_filter,
.config_intf = rt73usb_config_intf,
.config_erp = rt73usb_config_erp,
+ .config_ant = rt73usb_config_ant,
.config = rt73usb_config,
};
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 868386c457f..46e1405eb0e 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -48,7 +48,9 @@
#define CSR_REG_SIZE 0x04b0
#define EEPROM_BASE 0x0000
#define EEPROM_SIZE 0x0100
+#define BBP_BASE 0x0000
#define BBP_SIZE 0x0080
+#define RF_BASE 0x0000
#define RF_SIZE 0x0014
/*
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
new file mode 100644
index 00000000000..c113b3e6904
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -0,0 +1,7 @@
+rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
+rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
+
+obj-$(CONFIG_RTL8180) += rtl8180.o
+obj-$(CONFIG_RTL8187) += rtl8187.o
+
+
diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
index 8721282a818..8721282a818 100644
--- a/drivers/net/wireless/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180.h
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index df7e78ee8a8..5f887fb137a 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
skb->len, PCI_DMA_TODEVICE);
info = IEEE80211_SKB_CB(skb);
- memset(&info->status, 0, sizeof(info->status));
+ ieee80211_tx_info_clear_status(info);
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
- if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
- info->flags |= IEEE80211_TX_STAT_ACK;
- else
- info->status.excessive_retries = 1;
- }
- info->status.retry_count = flags & 0xFF;
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+
+ info->status.rates[0].count = (flags & 0xFF) + 1;
ieee80211_tx_status_irqsafe(dev, skb);
if (ring->entries - skb_queue_len(&ring->queue) == 2)
@@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
unsigned int idx, prio;
dma_addr_t mapping;
u32 tx_flags;
+ u8 rc_flags;
u16 plcp_len = 0;
__le16 rts_duration = 0;
@@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
RTL818X_TX_DESC_FLAG_NO_ENC;
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ rc_flags = info->control.rates[0].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
}
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
info);
@@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
entry->plcp_len = cpu_to_le16(plcp_len);
entry->tx_buf = cpu_to_le32(mapping);
entry->frame_len = cpu_to_le32(skb->len);
- entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
+ entry->flags2 = info->control.rates[1].idx >= 0 ?
ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
- entry->retry_limit = info->control.retry_limit;
+ entry->retry_limit = info->control.rates[0].count;
entry->flags = cpu_to_le32(tx_flags);
__skb_queue_tail(&ring->queue, skb);
if (ring->entries - skb_queue_len(&ring->queue) < 2)
@@ -692,9 +692,10 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev,
priv->vif = NULL;
}
-static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
{
struct rtl8180_priv *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
priv->rf->set_chan(dev, conf);
@@ -719,6 +720,17 @@ static int rtl8180_config_interface(struct ieee80211_hw *dev,
return 0;
}
+static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct rtl8180_priv *priv = dev->priv;
+
+ if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
+ priv->rf->conf_erp(dev, info);
+}
+
static void rtl8180_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -759,6 +771,7 @@ static const struct ieee80211_ops rtl8180_ops = {
.remove_interface = rtl8180_remove_interface,
.config = rtl8180_config,
.config_interface = rtl8180_config_interface,
+ .bss_info_changed = rtl8180_bss_info_changed,
.configure_filter = rtl8180_configure_filter,
};
@@ -806,7 +819,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
const char *chip_name, *rf_name = NULL;
u32 reg;
u16 eeprom_val;
- DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if (err) {
@@ -855,7 +867,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
priv = dev->priv;
priv->pdev = pdev;
- dev->max_altrates = 1;
+ dev->max_rates = 2;
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
@@ -1002,8 +1014,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
goto err_iounmap;
}
- printk(KERN_INFO "%s: hwaddr %s, %s + %s\n",
- wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+ printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
chip_name, priv->rf->name);
return 0;
diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
index 947ee55f18b..947ee55f18b 100644
--- a/drivers/net/wireless/rtl8180_grf5101.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c
diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h
index 76647111bcf..76647111bcf 100644
--- a/drivers/net/wireless/rtl8180_grf5101.h
+++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h
diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
index 6c825fd7f3b..6c825fd7f3b 100644
--- a/drivers/net/wireless/rtl8180_max2820.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c
diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h
index 61cf6d1e7d5..61cf6d1e7d5 100644
--- a/drivers/net/wireless/rtl8180_max2820.h
+++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.h
diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
index cd22781728a..4d2be0d9672 100644
--- a/drivers/net/wireless/rtl8180_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c
@@ -725,8 +725,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]);
msleep(10);
+}
+
+static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev,
+ struct ieee80211_bss_conf *info)
+{
+ struct rtl8180_priv *priv = dev->priv;
- if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+ if (info->use_short_slot) {
rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
@@ -745,14 +751,16 @@ static const struct rtl818x_rf_ops rtl8225_ops = {
.name = "rtl8225",
.init = rtl8225_rf_init,
.stop = rtl8225_rf_stop,
- .set_chan = rtl8225_rf_set_channel
+ .set_chan = rtl8225_rf_set_channel,
+ .conf_erp = rtl8225_rf_conf_erp,
};
static const struct rtl818x_rf_ops rtl8225z2_ops = {
.name = "rtl8225z2",
.init = rtl8225z2_rf_init,
.stop = rtl8225_rf_stop,
- .set_chan = rtl8225_rf_set_channel
+ .set_chan = rtl8225_rf_set_channel,
+ .conf_erp = rtl8225_rf_conf_erp,
};
const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h
index 310013a2d72..310013a2d72 100644
--- a/drivers/net/wireless/rtl8180_rtl8225.h
+++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h
diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
index cea4e0ccb92..cea4e0ccb92 100644
--- a/drivers/net/wireless/rtl8180_sa2400.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c
diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h
index a4aaa0d413f..a4aaa0d413f 100644
--- a/drivers/net/wireless/rtl8180_sa2400.h
+++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index e82bb4d289e..3b1e1c2aad2 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -99,8 +99,8 @@ struct rtl8187_priv {
struct ieee80211_supported_band band;
struct usb_device *udev;
u32 rx_conf;
+ struct usb_anchor anchored;
u16 txpwr_base;
- u16 seqno;
u8 asic_rev;
u8 is_rtl8187b;
enum {
@@ -112,6 +112,12 @@ struct rtl8187_priv {
u8 signal;
u8 quality;
u8 noise;
+ u8 slot_time;
+ u8 aifsn[4];
+ struct {
+ __le64 buf;
+ struct sk_buff_head queue;
+ } b_tx_status;
};
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 69eb0132593..00ce3ef39ab 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -7,6 +7,11 @@
* Based on the r8187 driver, which is:
* Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
*
+ * The driver was extended to the RTL8187B in 2008 by:
+ * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ * Hin-Tak Leung <htl10@users.sourceforge.net>
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
* Magic delays and register offsets below are taken from the original
* r8187 driver sources. Thanks to Realtek for their support!
*
@@ -27,6 +32,9 @@
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_AUTHOR("Herton Ronaldo Krzesinski <herton@mandriva.com.br>");
+MODULE_AUTHOR("Hin-Tak Leung <htl10@users.sourceforge.net>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
MODULE_LICENSE("GPL");
@@ -91,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
static void rtl8187_iowrite_async_cb(struct urb *urb)
{
kfree(urb->context);
- usb_free_urb(urb);
}
static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
@@ -128,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
(unsigned char *)dr, buf, len,
rtl8187_iowrite_async_cb, buf);
+ usb_anchor_urb(urb, &priv->anchored);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
kfree(buf);
- usb_free_urb(urb);
+ usb_unanchor_urb(urb);
}
+ usb_free_urb(urb);
}
static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
@@ -155,30 +164,45 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
-
- msleep(1);
}
static void rtl8187_tx_cb(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *)urb->context;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hw *hw = info->driver_data[0];
+ struct ieee80211_hw *hw = info->rate_driver_data[0];
struct rtl8187_priv *priv = hw->priv;
- usb_free_urb(info->driver_data[1]);
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
sizeof(struct rtl8187_tx_hdr));
- memset(&info->status, 0, sizeof(info->status));
- info->flags |= IEEE80211_TX_STAT_ACK;
- ieee80211_tx_status_irqsafe(hw, skb);
+ ieee80211_tx_info_clear_status(info);
+
+ if (!urb->status &&
+ !(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ priv->is_rtl8187b) {
+ skb_queue_tail(&priv->b_tx_status.queue, skb);
+
+ /* queue is "full", discard last items */
+ while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
+ struct sk_buff *old_skb;
+
+ dev_dbg(&priv->udev->dev,
+ "transmit status queue full\n");
+
+ old_skb = skb_dequeue(&priv->b_tx_status.queue);
+ ieee80211_tx_status_irqsafe(hw, old_skb);
+ }
+ } else {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status_irqsafe(hw, skb);
+ }
}
static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct rtl8187_priv *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
unsigned int ep;
void *buf;
struct urb *urb;
@@ -189,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
kfree_skb(skb);
- return 0;
+ return -ENOMEM;
}
flags = skb->len;
@@ -198,12 +222,12 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
flags |= RTL818X_TX_DESC_FLAG_RTS;
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
rts_dur = ieee80211_rts_duration(dev, priv->vif,
skb->len, info);
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
flags |= RTL818X_TX_DESC_FLAG_CTS;
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
}
@@ -214,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
hdr->flags = cpu_to_le32(flags);
hdr->len = 0;
hdr->rts_duration = rts_dur;
- hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+ hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
buf = hdr;
ep = 2;
@@ -232,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
memset(hdr, 0, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags);
hdr->rts_duration = rts_dur;
- hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+ hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
hdr->tx_duration =
ieee80211_generic_frame_duration(dev, priv->vif,
skb->len, txrate);
@@ -244,32 +268,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
ep = epmap[skb_get_queue_mapping(skb)];
}
- /* FIXME: The sequence that follows is needed for this driver to
- * work with mac80211 since "mac80211: fix TX sequence numbers".
- * As with the temporary code in rt2x00, changes will be needed
- * to get proper sequence numbers on beacons. In addition, this
- * patch places the sequence number in the hardware state, which
- * limits us to a single virtual state.
- */
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- priv->seqno += 0x10;
- ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
- }
-
- info->driver_data[0] = dev;
- info->driver_data[1] = urb;
+ info->rate_driver_data[0] = dev;
+ info->rate_driver_data[1] = urb;
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
buf, skb->len, rtl8187_tx_cb, skb);
+ usb_anchor_urb(urb, &priv->anchored);
rc = usb_submit_urb(urb, GFP_ATOMIC);
if (rc < 0) {
- usb_free_urb(urb);
+ usb_unanchor_urb(urb);
kfree_skb(skb);
}
+ usb_free_urb(urb);
- return 0;
+ return rc;
}
static void rtl8187_rx_cb(struct urb *urb)
@@ -282,50 +294,35 @@ static void rtl8187_rx_cb(struct urb *urb)
int rate, signal;
u32 flags;
u32 quality;
+ unsigned long f;
- spin_lock(&priv->rx_queue.lock);
+ spin_lock_irqsave(&priv->rx_queue.lock, f);
if (skb->next)
__skb_unlink(skb, &priv->rx_queue);
else {
- spin_unlock(&priv->rx_queue.lock);
+ spin_unlock_irqrestore(&priv->rx_queue.lock, f);
return;
}
- spin_unlock(&priv->rx_queue.lock);
+ spin_unlock_irqrestore(&priv->rx_queue.lock, f);
+ skb_put(skb, urb->actual_length);
if (unlikely(urb->status)) {
- usb_free_urb(urb);
dev_kfree_skb_irq(skb);
return;
}
- skb_put(skb, urb->actual_length);
if (!priv->is_rtl8187b) {
struct rtl8187_rx_hdr *hdr =
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
flags = le32_to_cpu(hdr->flags);
- signal = hdr->signal & 0x7f;
+ /* As with the RTL8187B below, the AGC is used to calculate
+ * signal strength and quality. In this case, the scaling
+ * constants are derived from the output of p54usb.
+ */
+ quality = 130 - ((41 * hdr->agc) >> 6);
+ signal = -4 - ((27 * hdr->agc) >> 6);
rx_status.antenna = (hdr->signal >> 7) & 1;
- rx_status.noise = hdr->noise;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
- priv->quality = signal;
- rx_status.qual = priv->quality;
- priv->noise = hdr->noise;
- rate = (flags >> 20) & 0xF;
- if (rate > 3) { /* OFDM rate */
- if (signal > 90)
- signal = 90;
- else if (signal < 25)
- signal = 25;
- signal = 90 - signal;
- } else { /* CCK rate */
- if (signal > 95)
- signal = 95;
- else if (signal < 30)
- signal = 30;
- signal = 95 - signal;
- }
- rx_status.signal = signal;
- priv->signal = signal;
} else {
struct rtl8187b_rx_hdr *hdr =
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
@@ -343,18 +340,18 @@ static void rtl8187_rx_cb(struct urb *urb)
*/
flags = le32_to_cpu(hdr->flags);
quality = 170 - hdr->agc;
- if (quality > 100)
- quality = 100;
signal = 14 - hdr->agc / 2;
- rx_status.qual = quality;
- priv->quality = quality;
- rx_status.signal = signal;
- priv->signal = signal;
rx_status.antenna = (hdr->rssi >> 7) & 1;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
- rate = (flags >> 20) & 0xF;
}
+ if (quality > 100)
+ quality = 100;
+ rx_status.qual = quality;
+ priv->quality = quality;
+ rx_status.signal = signal;
+ priv->signal = signal;
+ rate = (flags >> 20) & 0xF;
skb_trim(skb, flags & 0x0FFF);
rx_status.rate_idx = rate;
rx_status.freq = dev->conf.channel->center_freq;
@@ -366,7 +363,6 @@ static void rtl8187_rx_cb(struct urb *urb)
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
- usb_free_urb(urb);
/* TODO check rx queue length and refill *somewhere* */
return;
}
@@ -378,24 +374,32 @@ static void rtl8187_rx_cb(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
- usb_submit_urb(urb, GFP_ATOMIC);
+ usb_anchor_urb(urb, &priv->anchored);
+ if (usb_submit_urb(urb, GFP_ATOMIC)) {
+ usb_unanchor_urb(urb);
+ skb_unlink(skb, &priv->rx_queue);
+ dev_kfree_skb_irq(skb);
+ }
}
static int rtl8187_init_urbs(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
- struct urb *entry;
+ struct urb *entry = NULL;
struct sk_buff *skb;
struct rtl8187_rx_info *info;
+ int ret = 0;
while (skb_queue_len(&priv->rx_queue) < 8) {
skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
- if (!skb)
- break;
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err;
+ }
entry = usb_alloc_urb(0, GFP_KERNEL);
if (!entry) {
- kfree_skb(skb);
- break;
+ ret = -ENOMEM;
+ goto err;
}
usb_fill_bulk_urb(entry, priv->udev,
usb_rcvbulkpipe(priv->udev,
@@ -406,10 +410,129 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
info->urb = entry;
info->dev = dev;
skb_queue_tail(&priv->rx_queue, skb);
- usb_submit_urb(entry, GFP_KERNEL);
+ usb_anchor_urb(entry, &priv->anchored);
+ ret = usb_submit_urb(entry, GFP_KERNEL);
+ if (ret) {
+ skb_unlink(skb, &priv->rx_queue);
+ usb_unanchor_urb(entry);
+ goto err;
+ }
+ usb_free_urb(entry);
}
+ return ret;
- return 0;
+err:
+ usb_free_urb(entry);
+ kfree_skb(skb);
+ usb_kill_anchored_urbs(&priv->anchored);
+ return ret;
+}
+
+static void rtl8187b_status_cb(struct urb *urb)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context;
+ struct rtl8187_priv *priv = hw->priv;
+ u64 val;
+ unsigned int cmd_type;
+
+ if (unlikely(urb->status))
+ return;
+
+ /*
+ * Read from status buffer:
+ *
+ * bits [30:31] = cmd type:
+ * - 0 indicates tx beacon interrupt
+ * - 1 indicates tx close descriptor
+ *
+ * In the case of tx beacon interrupt:
+ * [0:9] = Last Beacon CW
+ * [10:29] = reserved
+ * [30:31] = 00b
+ * [32:63] = Last Beacon TSF
+ *
+ * If it's tx close descriptor:
+ * [0:7] = Packet Retry Count
+ * [8:14] = RTS Retry Count
+ * [15] = TOK
+ * [16:27] = Sequence No
+ * [28] = LS
+ * [29] = FS
+ * [30:31] = 01b
+ * [32:47] = unused (reserved?)
+ * [48:63] = MAC Used Time
+ */
+ val = le64_to_cpu(priv->b_tx_status.buf);
+
+ cmd_type = (val >> 30) & 0x3;
+ if (cmd_type == 1) {
+ unsigned int pkt_rc, seq_no;
+ bool tok;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *ieee80211hdr;
+ unsigned long flags;
+
+ pkt_rc = val & 0xFF;
+ tok = val & (1 << 15);
+ seq_no = (val >> 16) & 0xFFF;
+
+ spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags);
+ skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) {
+ ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+
+ /*
+ * While testing, it was discovered that the seq_no
+ * doesn't actually contains the sequence number.
+ * Instead of returning just the 12 bits of sequence
+ * number, hardware is returning entire sequence control
+ * (fragment number plus sequence number) in a 12 bit
+ * only field overflowing after some time. As a
+ * workaround, just consider the lower bits, and expect
+ * it's unlikely we wrongly ack some sent data
+ */
+ if ((le16_to_cpu(ieee80211hdr->seq_ctrl)
+ & 0xFFF) == seq_no)
+ break;
+ }
+ if (skb != (struct sk_buff *) &priv->b_tx_status.queue) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ __skb_unlink(skb, &priv->b_tx_status.queue);
+ if (tok)
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.rates[0].count = pkt_rc + 1;
+
+ ieee80211_tx_status_irqsafe(hw, skb);
+ }
+ spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
+ }
+
+ usb_anchor_urb(urb, &priv->anchored);
+ if (usb_submit_urb(urb, GFP_ATOMIC))
+ usb_unanchor_urb(urb);
+}
+
+static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ struct urb *entry;
+ int ret = 0;
+
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
+ &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
+ rtl8187b_status_cb, dev);
+
+ usb_anchor_urb(entry, &priv->anchored);
+ ret = usb_submit_urb(entry, GFP_KERNEL);
+ if (ret)
+ usb_unanchor_urb(entry);
+ usb_free_urb(entry);
+
+ return ret;
}
static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
@@ -687,7 +810,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
- msleep(1100);
+ msleep(100);
priv->rf->init(dev);
@@ -721,6 +844,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1);
+ priv->slot_time = 0x9;
+ priv->aifsn[0] = 2; /* AIFSN[AC_VO] */
+ priv->aifsn[1] = 2; /* AIFSN[AC_VI] */
+ priv->aifsn[2] = 7; /* AIFSN[AC_BK] */
+ priv->aifsn[3] = 3; /* AIFSN[AC_BE] */
+ rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
+
return 0;
}
@@ -736,6 +866,9 @@ static int rtl8187_start(struct ieee80211_hw *dev)
return ret;
mutex_lock(&priv->conf_mutex);
+
+ init_usb_anchor(&priv->anchored);
+
if (priv->is_rtl8187b) {
reg = RTL818X_RX_CONF_MGMT |
RTL818X_RX_CONF_DATA |
@@ -757,6 +890,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 0 /* long retry limit */) |
(7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev);
+ rtl8187b_init_status_urb(dev);
mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -809,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev)
static void rtl8187_stop(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
- struct rtl8187_rx_info *info;
struct sk_buff *skb;
u32 reg;
@@ -828,11 +961,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
- while ((skb = skb_dequeue(&priv->rx_queue))) {
- info = (struct rtl8187_rx_info *)skb->cb;
- usb_kill_urb(info->urb);
- kfree_skb(skb);
- }
+ while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
+ dev_kfree_skb_any(skb);
+
+ usb_kill_anchored_urbs(&priv->anchored);
mutex_unlock(&priv->conf_mutex);
}
@@ -876,9 +1008,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
mutex_unlock(&priv->conf_mutex);
}
-static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
{
struct rtl8187_priv *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
u32 reg;
mutex_lock(&priv->conf_mutex);
@@ -889,27 +1022,10 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
*/
rtl818x_iowrite32(priv, &priv->map->TX_CONF,
reg | RTL818X_TX_CONF_LOOPBACK_MAC);
- msleep(10);
priv->rf->set_chan(dev, conf);
msleep(10);
rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
- if (!priv->is_rtl8187b) {
- rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
-
- if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
- rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
- rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
- rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
- } else {
- rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
- rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
- rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
- rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
- }
- }
-
rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
@@ -944,6 +1060,89 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
return 0;
}
+/*
+ * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for
+ * example. Thus we have to use raw values for AC_*_PARAM register addresses.
+ */
+static __le32 *rtl8187b_ac_addr[4] = {
+ (__le32 *) 0xFFF0, /* AC_VO */
+ (__le32 *) 0xFFF4, /* AC_VI */
+ (__le32 *) 0xFFFC, /* AC_BK */
+ (__le32 *) 0xFFF8, /* AC_BE */
+};
+
+#define SIFS_TIME 0xa
+
+static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot,
+ bool use_short_preamble)
+{
+ if (priv->is_rtl8187b) {
+ u8 difs, eifs;
+ u16 ack_timeout;
+ int queue;
+
+ if (use_short_slot) {
+ priv->slot_time = 0x9;
+ difs = 0x1c;
+ eifs = 0x53;
+ } else {
+ priv->slot_time = 0x14;
+ difs = 0x32;
+ eifs = 0x5b;
+ }
+ rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+ rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, difs);
+
+ /*
+ * BRSR+1 on 8187B is in fact EIFS register
+ * Value in units of 4 us
+ */
+ rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs);
+
+ /*
+ * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout
+ * register. In units of 4 us like eifs register
+ * ack_timeout = ack duration + plcp + difs + preamble
+ */
+ ack_timeout = 112 + 48 + difs;
+ if (use_short_preamble)
+ ack_timeout += 72;
+ else
+ ack_timeout += 144;
+ rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER,
+ DIV_ROUND_UP(ack_timeout, 4));
+
+ for (queue = 0; queue < 4; queue++)
+ rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue],
+ priv->aifsn[queue] * priv->slot_time +
+ SIFS_TIME);
+ } else {
+ rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+ if (use_short_slot) {
+ rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+ rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
+ } else {
+ rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+ rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
+ }
+ }
+}
+
+static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE))
+ rtl8187_conf_erp(priv, info->use_short_slot,
+ info->use_short_preamble);
+}
+
static void rtl8187_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -976,6 +1175,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
}
+static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u8 cw_min, cw_max;
+
+ if (queue > 3)
+ return -EINVAL;
+
+ cw_min = fls(params->cw_min);
+ cw_max = fls(params->cw_max);
+
+ if (priv->is_rtl8187b) {
+ priv->aifsn[queue] = params->aifs;
+
+ /*
+ * This is the structure of AC_*_PARAM registers in 8187B:
+ * - TXOP limit field, bit offset = 16
+ * - ECWmax, bit offset = 12
+ * - ECWmin, bit offset = 8
+ * - AIFS, bit offset = 0
+ */
+ rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue],
+ (params->txop << 16) | (cw_max << 12) |
+ (cw_min << 8) | (params->aifs *
+ priv->slot_time + SIFS_TIME));
+ } else {
+ if (queue != 0)
+ return -EINVAL;
+
+ rtl818x_iowrite8(priv, &priv->map->CW_VAL,
+ cw_min | (cw_max << 4));
+ }
+ return 0;
+}
+
static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx,
.start = rtl8187_start,
@@ -984,7 +1219,9 @@ static const struct ieee80211_ops rtl8187_ops = {
.remove_interface = rtl8187_remove_interface,
.config = rtl8187_config,
.config_interface = rtl8187_config_interface,
+ .bss_info_changed = rtl8187_bss_info_changed,
.configure_filter = rtl8187_configure_filter,
+ .conf_tx = rtl8187_conf_tx
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1029,7 +1266,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
const char *chip_name;
u16 txpwr, reg;
int err, i;
- DECLARE_MAC_BUF(mac);
dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
if (!dev) {
@@ -1065,6 +1301,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->mode = NL80211_IFTYPE_MONITOR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS;
eeprom.data = dev;
@@ -1180,16 +1417,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
(*channel++).hw_value = txpwr >> 8;
}
- if (priv->is_rtl8187b) {
- printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
- "is EXPERIMENTAL, and could damage your\n"
- " hardware, use at your own risk\n");
- dev->flags |= IEEE80211_HW_SIGNAL_DBM;
- } else {
- dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
- dev->max_signal = 65;
- }
+ if (priv->is_rtl8187b)
+ printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
+ /*
+ * XXX: Once this driver supports anything that requires
+ * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ.
+ */
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
@@ -1211,9 +1445,10 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
goto err_free_dev;
}
mutex_init(&priv->conf_mutex);
+ skb_queue_head_init(&priv->b_tx_status.queue);
- printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
- wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+ printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
chip_name, priv->asic_rev, priv->rf->name);
return 0;
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
index 1bae8990341..4e75e8e7fa9 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
- msleep(2);
}
static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
@@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
- msleep(2);
}
static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
@@ -333,21 +331,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
struct rtl8187_priv *priv = dev->priv;
int i;
- rtl8225_write(dev, 0x0, 0x067); msleep(1);
- rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
- rtl8225_write(dev, 0x2, 0x44D); msleep(1);
- rtl8225_write(dev, 0x3, 0x441); msleep(1);
- rtl8225_write(dev, 0x4, 0x486); msleep(1);
- rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
- rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
- rtl8225_write(dev, 0x7, 0x82A); msleep(1);
- rtl8225_write(dev, 0x8, 0x01F); msleep(1);
- rtl8225_write(dev, 0x9, 0x334); msleep(1);
- rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
- rtl8225_write(dev, 0xB, 0x391); msleep(1);
- rtl8225_write(dev, 0xC, 0x050); msleep(1);
- rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
- rtl8225_write(dev, 0xE, 0x029); msleep(1);
+ rtl8225_write(dev, 0x0, 0x067);
+ rtl8225_write(dev, 0x1, 0xFE0);
+ rtl8225_write(dev, 0x2, 0x44D);
+ rtl8225_write(dev, 0x3, 0x441);
+ rtl8225_write(dev, 0x4, 0x486);
+ rtl8225_write(dev, 0x5, 0xBC0);
+ rtl8225_write(dev, 0x6, 0xAE6);
+ rtl8225_write(dev, 0x7, 0x82A);
+ rtl8225_write(dev, 0x8, 0x01F);
+ rtl8225_write(dev, 0x9, 0x334);
+ rtl8225_write(dev, 0xA, 0xFD4);
+ rtl8225_write(dev, 0xB, 0x391);
+ rtl8225_write(dev, 0xC, 0x050);
+ rtl8225_write(dev, 0xD, 0x6DB);
+ rtl8225_write(dev, 0xE, 0x029);
rtl8225_write(dev, 0xF, 0x914); msleep(100);
rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
@@ -375,91 +373,89 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
- msleep(1);
rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
- msleep(1);
}
msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+ rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+ rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+ rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+ rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
+ rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+ rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
+ rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+ rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+ rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+ rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
+ rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+ rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+ rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
+ rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+ rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+ rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+ rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+ rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
+ rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+ rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+ rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+ rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
- rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
- rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
- rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
- rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
- rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
- rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
- rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
- rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x00, 0x98);
+ rtl8225_write_phy_cck(dev, 0x03, 0x20);
+ rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+ rtl8225_write_phy_cck(dev, 0x05, 0x12);
+ rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+ rtl8225_write_phy_cck(dev, 0x07, 0x78);
+ rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+ rtl8225_write_phy_cck(dev, 0x11, 0x88);
+ rtl8225_write_phy_cck(dev, 0x12, 0x47);
rtl8225_write_phy_cck(dev, 0x13, 0xd0);
rtl8225_write_phy_cck(dev, 0x19, 0x00);
rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
rtl8225_write_phy_cck(dev, 0x1b, 0x08);
rtl8225_write_phy_cck(dev, 0x40, 0x86);
- rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
- rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
- rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
- rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
- rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
- rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
- rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
- rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+ rtl8225_write_phy_cck(dev, 0x42, 0x15);
+ rtl8225_write_phy_cck(dev, 0x43, 0x18);
+ rtl8225_write_phy_cck(dev, 0x44, 0x1f);
+ rtl8225_write_phy_cck(dev, 0x45, 0x1e);
+ rtl8225_write_phy_cck(dev, 0x46, 0x1a);
+ rtl8225_write_phy_cck(dev, 0x47, 0x15);
+ rtl8225_write_phy_cck(dev, 0x48, 0x10);
+ rtl8225_write_phy_cck(dev, 0x49, 0x0a);
+ rtl8225_write_phy_cck(dev, 0x4a, 0x05);
+ rtl8225_write_phy_cck(dev, 0x4b, 0x02);
+ rtl8225_write_phy_cck(dev, 0x4c, 0x05);
rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
rtl8225_rf_set_tx_power(dev, 1);
/* RX antenna default to A */
- rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
- rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */
rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
msleep(1);
@@ -629,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
- rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+ rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
msleep(1);
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
@@ -687,22 +683,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
struct rtl8187_priv *priv = dev->priv;
int i;
- rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
- rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
- rtl8225_write(dev, 0x2, 0x44D); msleep(1);
- rtl8225_write(dev, 0x3, 0x441); msleep(1);
- rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
- rtl8225_write(dev, 0x5, 0xC72); msleep(1);
- rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
- rtl8225_write(dev, 0x7, 0x82A); msleep(1);
- rtl8225_write(dev, 0x8, 0x03F); msleep(1);
- rtl8225_write(dev, 0x9, 0x335); msleep(1);
- rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
- rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
- rtl8225_write(dev, 0xc, 0x850); msleep(1);
- rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
- rtl8225_write(dev, 0xe, 0x02B); msleep(1);
- rtl8225_write(dev, 0xf, 0x114); msleep(100);
+ rtl8225_write(dev, 0x0, 0x2BF);
+ rtl8225_write(dev, 0x1, 0xEE0);
+ rtl8225_write(dev, 0x2, 0x44D);
+ rtl8225_write(dev, 0x3, 0x441);
+ rtl8225_write(dev, 0x4, 0x8C3);
+ rtl8225_write(dev, 0x5, 0xC72);
+ rtl8225_write(dev, 0x6, 0x0E6);
+ rtl8225_write(dev, 0x7, 0x82A);
+ rtl8225_write(dev, 0x8, 0x03F);
+ rtl8225_write(dev, 0x9, 0x335);
+ rtl8225_write(dev, 0xa, 0x9D4);
+ rtl8225_write(dev, 0xb, 0x7BB);
+ rtl8225_write(dev, 0xc, 0x850);
+ rtl8225_write(dev, 0xd, 0xCDF);
+ rtl8225_write(dev, 0xe, 0x02B);
+ rtl8225_write(dev, 0xf, 0x114);
+ msleep(100);
rtl8225_write(dev, 0x0, 0x1B7);
@@ -736,94 +733,92 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
- msleep(1);
rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
- msleep(1);
}
msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+ rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+ rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+ rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+ rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
+ rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+ rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
- rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
- rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+ rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+ rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+ rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
+ rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+ rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+ rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+ rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
+ rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+ rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
+ rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+ rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+ rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+ rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
+ rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+ rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
+ rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+ rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+ rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
- rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
- rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
- rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
- rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
- rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
- rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
- rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
- rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x00, 0x98);
+ rtl8225_write_phy_cck(dev, 0x03, 0x20);
+ rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+ rtl8225_write_phy_cck(dev, 0x05, 0x12);
+ rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+ rtl8225_write_phy_cck(dev, 0x07, 0x78);
+ rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+ rtl8225_write_phy_cck(dev, 0x11, 0x88);
+ rtl8225_write_phy_cck(dev, 0x12, 0x47);
rtl8225_write_phy_cck(dev, 0x13, 0xd0);
rtl8225_write_phy_cck(dev, 0x19, 0x00);
rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
rtl8225_write_phy_cck(dev, 0x1b, 0x08);
rtl8225_write_phy_cck(dev, 0x40, 0x86);
- rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
- rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
- rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
- rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
- rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
- rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
- rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
- rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
- rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
- rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+ rtl8225_write_phy_cck(dev, 0x42, 0x15);
+ rtl8225_write_phy_cck(dev, 0x43, 0x18);
+ rtl8225_write_phy_cck(dev, 0x44, 0x36);
+ rtl8225_write_phy_cck(dev, 0x45, 0x35);
+ rtl8225_write_phy_cck(dev, 0x46, 0x2e);
+ rtl8225_write_phy_cck(dev, 0x47, 0x25);
+ rtl8225_write_phy_cck(dev, 0x48, 0x1c);
+ rtl8225_write_phy_cck(dev, 0x49, 0x12);
+ rtl8225_write_phy_cck(dev, 0x4a, 0x09);
+ rtl8225_write_phy_cck(dev, 0x4b, 0x04);
+ rtl8225_write_phy_cck(dev, 0x4c, 0x05);
rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
rtl8225z2_rf_set_tx_power(dev, 1);
/* RX antenna default to A */
- rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
- rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */
rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
msleep(1);
@@ -835,40 +830,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
struct rtl8187_priv *priv = dev->priv;
int i;
- rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
- rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
- rtl8225_write(dev, 0x2, 0x44D); msleep(1);
- rtl8225_write(dev, 0x3, 0x441); msleep(1);
- rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
- rtl8225_write(dev, 0x5, 0xC72); msleep(1);
- rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
- rtl8225_write(dev, 0x7, 0x82A); msleep(1);
- rtl8225_write(dev, 0x8, 0x03F); msleep(1);
- rtl8225_write(dev, 0x9, 0x335); msleep(1);
- rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
- rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
- rtl8225_write(dev, 0xc, 0x850); msleep(1);
- rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
- rtl8225_write(dev, 0xe, 0x02B); msleep(1);
- rtl8225_write(dev, 0xf, 0x114); msleep(1);
-
- rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
+ rtl8225_write(dev, 0x0, 0x0B7);
+ rtl8225_write(dev, 0x1, 0xEE0);
+ rtl8225_write(dev, 0x2, 0x44D);
+ rtl8225_write(dev, 0x3, 0x441);
+ rtl8225_write(dev, 0x4, 0x8C3);
+ rtl8225_write(dev, 0x5, 0xC72);
+ rtl8225_write(dev, 0x6, 0x0E6);
+ rtl8225_write(dev, 0x7, 0x82A);
+ rtl8225_write(dev, 0x8, 0x03F);
+ rtl8225_write(dev, 0x9, 0x335);
+ rtl8225_write(dev, 0xa, 0x9D4);
+ rtl8225_write(dev, 0xb, 0x7BB);
+ rtl8225_write(dev, 0xc, 0x850);
+ rtl8225_write(dev, 0xd, 0xCDF);
+ rtl8225_write(dev, 0xe, 0x02B);
+ rtl8225_write(dev, 0xf, 0x114);
+
+ rtl8225_write(dev, 0x0, 0x1B7);
for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
- rtl8225_write(dev, 0x1, i + 1); msleep(1);
- rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
+ rtl8225_write(dev, 0x1, i + 1);
+ rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
}
- rtl8225_write(dev, 0x3, 0x080); msleep(1);
- rtl8225_write(dev, 0x5, 0x004); msleep(1);
- rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
- msleep(3000);
+ rtl8225_write(dev, 0x3, 0x080);
+ rtl8225_write(dev, 0x5, 0x004);
+ rtl8225_write(dev, 0x0, 0x0B7);
- rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
- msleep(2000);
+ rtl8225_write(dev, 0x2, 0xC4D);
- rtl8225_write(dev, 0x2, 0x44D); msleep(1);
- rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+ rtl8225_write(dev, 0x2, 0x44D);
+ rtl8225_write(dev, 0x0, 0x2BF);
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
@@ -885,24 +878,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++)
rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]);
- rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
- rtl818x_iowrite8(priv, &priv->map->SLOT, 9);
- rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28);
- rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28);
- rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28);
- rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28);
- rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B);
- rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
- rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
-
- rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
- rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
- rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
+ rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
+ rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
+ rtl8225_write_phy_cck(dev, 0xc1, 0x88);
}
static void rtl8225_rf_stop(struct ieee80211_hw *dev)
@@ -910,7 +889,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
u8 reg;
struct rtl8187_priv *priv = dev->priv;
- rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+ rtl8225_write(dev, 0x4, 0x1f);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
index 20c5b6ead0f..20c5b6ead0f 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.h
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index 3538b15211b..34a5555cc19 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -191,6 +191,7 @@ struct rtl818x_rf_ops {
void (*init)(struct ieee80211_hw *);
void (*stop)(struct ieee80211_hw *);
void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
+ void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *);
};
/* Tx/Rx flags are common between RTL818X chips */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 417e9e675fa..dd0de3a9ed4 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1234,7 +1234,7 @@ static void ResetRadio(struct strip *strip_info)
static void strip_write_some_more(struct tty_struct *tty)
{
- struct strip *strip_info = (struct strip *) tty->disc_data;
+ struct strip *strip_info = tty->disc_data;
/* First make sure we're connected. */
if (!strip_info || strip_info->magic != STRIP_MAGIC ||
@@ -1252,7 +1252,7 @@ static void strip_write_some_more(struct tty_struct *tty)
#endif
} else { /* Else start transmission of another packet */
- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
strip_unlock(strip_info);
}
}
@@ -1455,8 +1455,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
*/
strip_info->tx_head = strip_info->tx_buff;
strip_info->tx_left = ptr - strip_info->tx_buff;
- strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-
+ set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags);
/*
* 4. Debugging check to make sure we're not overflowing the buffer.
*/
@@ -1997,7 +1996,6 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header * header,
#ifdef EXT_COUNTERS
strip_info->rx_bytes += packetlen;
#endif
- skb->dev->last_rx = jiffies;
netif_rx(skb);
}
}
@@ -2261,7 +2259,7 @@ static void process_message(struct strip *strip_info)
static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
- struct strip *strip_info = (struct strip *) tty->disc_data;
+ struct strip *strip_info = tty->disc_data;
const unsigned char *end = cp + count;
if (!strip_info || strip_info->magic != STRIP_MAGIC
@@ -2455,8 +2453,7 @@ static int strip_close_low(struct net_device *dev)
if (strip_info->tty == NULL)
return -EBUSY;
- strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
+ clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags);
netif_stop_queue(dev);
/*
@@ -2490,7 +2487,6 @@ static void strip_dev_setup(struct net_device *dev)
*/
dev->trans_start = 0;
- dev->last_rx = 0;
dev->tx_queue_len = 30; /* Drop after 30 frames queued */
dev->flags = 0;
@@ -2498,7 +2494,7 @@ static void strip_dev_setup(struct net_device *dev)
dev->type = ARPHRD_METRICOM; /* dtang */
dev->hard_header_len = sizeof(STRIP_Header);
/*
- * dev->priv Already holds a pointer to our struct strip
+ * netdev_priv(dev) Already holds a pointer to our struct strip
*/
*(MetricomAddress *) & dev->broadcast = broadcast_address;
@@ -2598,7 +2594,7 @@ static struct strip *strip_alloc(void)
static int strip_open(struct tty_struct *tty)
{
- struct strip *strip_info = (struct strip *) tty->disc_data;
+ struct strip *strip_info = tty->disc_data;
/*
* First make sure we're not already connected.
@@ -2669,7 +2665,7 @@ static int strip_open(struct tty_struct *tty)
static void strip_close(struct tty_struct *tty)
{
- struct strip *strip_info = (struct strip *) tty->disc_data;
+ struct strip *strip_info = tty->disc_data;
/*
* First make sure we're connected.
@@ -2695,7 +2691,7 @@ static void strip_close(struct tty_struct *tty)
static int strip_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct strip *strip_info = (struct strip *) tty->disc_data;
+ struct strip *strip_info = tty->disc_data;
/*
* First make sure we're connected.
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index e939a73ff79..832679396b6 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -134,7 +134,7 @@ static inline void wv_16_on(unsigned long ioaddr, u16 hacr)
*/
static inline void wv_ints_off(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
lp->hacr &= ~HACR_INTRON;
@@ -148,7 +148,7 @@ static inline void wv_ints_off(struct net_device * dev)
*/
static inline void wv_ints_on(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
lp->hacr |= HACR_INTRON;
@@ -526,7 +526,7 @@ static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n)
*/
static void wv_ack(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 scb_cs;
int i;
@@ -568,7 +568,7 @@ static void wv_ack(struct net_device * dev)
*/
static int wv_synchronous_cmd(struct net_device * dev, const char *str)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 scb_cmd;
ach_t cb;
@@ -824,7 +824,7 @@ if (lp->tx_n_in_use > 0)
*/
static void wv_82586_reconfig(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
/* Arm the flag, will be cleard in wv_82586_config() */
@@ -859,8 +859,6 @@ static void wv_82586_reconfig(struct net_device * dev)
*/
static void wv_psa_show(psa_t * p)
{
- DECLARE_MAC_BUF(mac);
-
printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -872,13 +870,10 @@ static void wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_unused0[]: %s\n",
- print_mac(mac, p->psa_unused0));
+ printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0);
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
- print_mac(mac, p->psa_univ_mac_addr));
- printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
- print_mac(mac, p->psa_local_mac_addr));
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr);
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr);
printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
@@ -927,7 +922,7 @@ static void wv_psa_show(psa_t * p)
static void wv_mmc_show(struct net_device * dev)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
mmr_t m;
/* Basic check */
@@ -1107,8 +1102,6 @@ static void wv_scb_show(unsigned long ioaddr)
*/
static void wv_ru_show(struct net_device * dev)
{
- /* net_local *lp = (net_local *) dev->priv; */
-
printk(KERN_DEBUG
"##### WaveLAN i82586 receiver unit status: #####\n");
printk(KERN_DEBUG "ru:");
@@ -1153,7 +1146,7 @@ static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p
*/
static void wv_cu_show(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned int i;
u16 p;
@@ -1195,7 +1188,7 @@ static void wv_local_show(struct net_device * dev)
{
net_local *lp;
- lp = (net_local *) dev->priv;
+ lp = netdev_priv(dev);
printk(KERN_DEBUG "local:");
printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
@@ -1220,14 +1213,13 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */
{ /* Name of the function */
int i;
int maxi;
- DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
- "%s: %s(): dest %s, length %d\n",
- msg1, msg2, print_mac(mac, p), length);
+ "%s: %s(): dest %pM, length %d\n",
+ msg1, msg2, p, length);
printk(KERN_DEBUG
- "%s: %s(): src %s, type 0x%02X%02X\n",
- msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
+ "%s: %s(): src %pM, type 0x%02X%02X\n",
+ msg1, msg2, &p[6], p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1256,11 +1248,8 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */
static void wv_init_info(struct net_device * dev)
{
short ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
-#ifdef DEBUG_BASIC_SHOW
- DECLARE_MAC_BUF(mac);
-#endif
/* Read the parameter storage area */
psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1277,8 +1266,8 @@ static void wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff. */
- printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d",
- dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq);
+ printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d",
+ dev->name, ioaddr, dev->dev_addr, dev->irq);
/* Print current network ID. */
if (psa.psa_nwid_select)
@@ -1369,7 +1358,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev)
printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
#endif
- return (&((net_local *) dev->priv)->stats);
+ return &((net_local *)netdev_priv(dev))->stats;
}
/*------------------------------------------------------------------*/
@@ -1382,7 +1371,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev)
*/
static void wavelan_set_multicast_list(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
@@ -1716,7 +1705,7 @@ static inline void wl_spy_gather(struct net_device * dev,
*/
static inline void wl_his_gather(struct net_device * dev, u8 * stats)
{ /* Statistics to gather */
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
u8 level = stats[0] & MMR_SIGNAL_LVL;
int i;
@@ -1753,7 +1742,7 @@ static int wavelan_set_nwid(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
mm_t m;
unsigned long flags;
@@ -1812,7 +1801,7 @@ static int wavelan_get_nwid(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
@@ -1844,7 +1833,7 @@ static int wavelan_set_freq(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
unsigned long flags;
int ret;
@@ -1874,7 +1863,7 @@ static int wavelan_get_freq(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
@@ -1920,7 +1909,7 @@ static int wavelan_set_sens(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
@@ -1956,7 +1945,7 @@ static int wavelan_get_sens(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
@@ -1987,7 +1976,7 @@ static int wavelan_set_encode(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
unsigned long flags;
psa_t psa;
int ret = 0;
@@ -2057,7 +2046,7 @@ static int wavelan_get_encode(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
@@ -2104,7 +2093,7 @@ static int wavelan_get_range(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
@@ -2179,7 +2168,7 @@ static int wavelan_set_qthr(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
@@ -2211,7 +2200,7 @@ static int wavelan_get_qthr(struct net_device *dev,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
psa_t psa;
unsigned long flags;
@@ -2239,7 +2228,7 @@ static int wavelan_set_histo(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
/* Check the number of intervals. */
if (wrqu->data.length > 16) {
@@ -2282,7 +2271,7 @@ static int wavelan_get_histo(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- net_local *lp = (net_local *) dev->priv; /* lp is not unused */
+ net_local *lp = netdev_priv(dev); /* lp is not unused */
/* Set the number of intervals. */
wrqu->data.length = lp->his_number;
@@ -2386,7 +2375,7 @@ static const struct iw_handler_def wavelan_handler_def =
static iw_stats *wavelan_get_wireless_stats(struct net_device * dev)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
mmr_t m;
iw_stats *wstats;
unsigned long flags;
@@ -2461,7 +2450,7 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev)
static void
wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
struct sk_buff *skb;
@@ -2537,7 +2526,6 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
netif_rx(skb);
/* Keep statistics up to date */
- dev->last_rx = jiffies;
lp->stats.rx_packets++;
lp->stats.rx_bytes += sksize;
@@ -2556,7 +2544,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
static void wv_receive(struct net_device * dev)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
fd_t fd;
rbd_t rbd;
int nreaped = 0;
@@ -2738,7 +2726,7 @@ static void wv_receive(struct net_device * dev)
*/
static int wv_packet_write(struct net_device * dev, void *buf, short length)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
unsigned short txblock;
unsigned short txpred;
@@ -2869,7 +2857,7 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length)
*/
static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
char data[ETH_ZLEN];
@@ -2937,7 +2925,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
static int wv_mmc_init(struct net_device * dev)
{
unsigned long ioaddr = dev->base_addr;
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
psa_t psa;
mmw_t m;
int configured;
@@ -3108,7 +3096,7 @@ static int wv_mmc_init(struct net_device * dev)
*/
static int wv_ru_start(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 scb_cs;
fd_t fd;
@@ -3200,7 +3188,7 @@ static int wv_ru_start(struct net_device * dev)
*/
static int wv_cu_start(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
int i;
u16 txblock;
@@ -3301,7 +3289,7 @@ static int wv_cu_start(struct net_device * dev)
*/
static int wv_82586_start(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
scp_t scp; /* system configuration pointer */
iscp_t iscp; /* intermediate scp */
@@ -3433,7 +3421,7 @@ static int wv_82586_start(struct net_device * dev)
*/
static void wv_82586_config(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
unsigned short txblock;
unsigned short txpred;
@@ -3565,15 +3553,11 @@ static void wv_82586_config(struct net_device * dev)
WAVELAN_ADDR_SIZE >> 1);
#ifdef DEBUG_CONFIG_INFO
- {
- DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
"%s: wv_82586_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for (dmi = dev->mc_list; dmi; dmi = dmi->next)
- printk(KERN_DEBUG " %s\n",
- print_mac(mac, dmi->dmi_addr));
- }
+ printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
#endif
}
@@ -3613,7 +3597,7 @@ static void wv_82586_config(struct net_device * dev)
*/
static void wv_82586_stop(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 scb_cmd;
@@ -3650,7 +3634,7 @@ static void wv_82586_stop(struct net_device * dev)
*/
static int wv_hw_reset(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
#ifdef DEBUG_CONFIG_TRACE
@@ -3751,7 +3735,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id)
printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
#endif
- lp = (net_local *) dev->priv;
+ lp = netdev_priv(dev);
ioaddr = dev->base_addr;
#ifdef DEBUG_INTERRUPT_INFO
@@ -3894,7 +3878,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id)
*/
static void wavelan_watchdog(struct net_device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = netdev_priv(dev);
u_long ioaddr = dev->base_addr;
unsigned long flags;
unsigned int nreaped;
@@ -3974,7 +3958,7 @@ static void wavelan_watchdog(struct net_device * dev)
*/
static int wavelan_open(struct net_device * dev)
{
- net_local * lp = (net_local *)dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
#ifdef DEBUG_CALLBACK_TRACE
@@ -4029,7 +4013,7 @@ static int wavelan_open(struct net_device * dev)
*/
static int wavelan_close(struct net_device * dev)
{
- net_local *lp = (net_local *) dev->priv;
+ net_local *lp = netdev_priv(dev);
unsigned long flags;
#ifdef DEBUG_CALLBACK_TRACE
@@ -4128,8 +4112,8 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
dev->if_port = 0;
/* Initialize device structures */
- memset(dev->priv, 0, sizeof(net_local));
- lp = (net_local *) dev->priv;
+ memset(netdev_priv(dev), 0, sizeof(net_local));
+ lp = netdev_priv(dev);
/* Back link to the device structure. */
lp->dev = dev;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index e124b1d6267..de717f8ffd6 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1020,7 +1020,6 @@ wv_82593_reconfig(struct net_device * dev)
static void
wv_psa_show(psa_t * p)
{
- DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -1034,13 +1033,10 @@ wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_unused0[]: %s\n",
- print_mac(mac, p->psa_unused0));
+ printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0);
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
- print_mac(mac, p->psa_univ_mac_addr));
- printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
- print_mac(mac, p->psa_local_mac_addr));
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr);
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr);
printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
@@ -1238,12 +1234,11 @@ wv_packet_info(u_char * p, /* Packet to dump */
{
int i;
int maxi;
- DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n",
- msg1, msg2, print_mac(mac, p), length);
- printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n",
- msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
+ printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n",
+ msg1, msg2, p, length);
+ printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n",
+ msg1, msg2, &p[6], p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1274,7 +1269,6 @@ wv_init_info(struct net_device * dev)
{
unsigned int base = dev->base_addr;
psa_t psa;
- DECLARE_MAC_BUF(mac);
/* Read the parameter storage area */
psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1291,10 +1285,8 @@ wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff */
- printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, "
- "hw_addr %s",
- dev->name, base, dev->irq,
- print_mac(mac, dev->dev_addr));
+ printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM",
+ dev->name, base, dev->irq, dev->dev_addr);
/* Print current network id */
if(psa.psa_nwid_select)
@@ -2243,13 +2235,7 @@ static int wavelan_set_wap(struct net_device *dev,
char *extra)
{
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
- wrqu->ap_addr.sa_data[0],
- wrqu->ap_addr.sa_data[1],
- wrqu->ap_addr.sa_data[2],
- wrqu->ap_addr.sa_data[3],
- wrqu->ap_addr.sa_data[4],
- wrqu->ap_addr.sa_data[5]);
+ printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data);
#endif /* DEBUG_IOCTL_INFO */
return -EOPNOTSUPP;
@@ -2892,7 +2878,6 @@ wv_packet_read(struct net_device * dev,
netif_rx(skb);
/* Keep stats up to date */
- dev->last_rx = jiffies;
lp->stats.rx_packets++;
lp->stats.rx_bytes += sksize;
@@ -3647,12 +3632,10 @@ wv_82593_config(struct net_device * dev)
int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
#ifdef DEBUG_CONFIG_INFO
- DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for(dmi=dev->mc_list; dmi; dmi=dmi->next)
- printk(KERN_DEBUG " %s\n",
- print_mac(mac, dmi->dmi_addr));
+ printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
#endif
/* Initialize adapter's ethernet multicast addresses */
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 65ceb088f70..59bb3a55ab4 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -2,7 +2,7 @@
#define __WL3501_H__
#include <linux/spinlock.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
/* define for WLA 2.0 */
#define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr {
struct wl3501_80211_tx_hdr {
struct wl3501_80211_tx_plcp_hdr pclp_hdr;
- struct ieee80211_hdr_4addr mac_hdr;
+ struct ieee80211_hdr mac_hdr;
} __attribute__ ((packed));
/*
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 68789c6e1ce..c99a1b6b948 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -860,10 +860,9 @@ static int wl3501_esbq_confirm(struct wl3501_card *this)
static void wl3501_online(struct net_device *dev)
{
struct wl3501_card *this = netdev_priv(dev);
- DECLARE_MAC_BUF(mac);
- printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n",
- dev->name, print_mac(mac, this->bssid));
+ printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n",
+ dev->name, this->bssid);
netif_wake_queue(dev);
}
@@ -1014,7 +1013,6 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev,
wl3501_receive(this, skb->data, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
- dev->last_rx = jiffies;
this->stats.rx_packets++;
this->stats.rx_bytes += skb->len;
netif_rx(skb);
@@ -1965,7 +1963,6 @@ static int wl3501_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
int i = 0, j, last_fn, last_ret;
struct wl3501_card *this;
- DECLARE_MAC_BUF(mac);
/* Try allocating IO ports. This tries a few fixed addresses. If you
* want, you can also read the card's config table to pick addresses --
@@ -2024,9 +2021,9 @@ static int wl3501_config(struct pcmcia_device *link)
/* print probe information */
printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
- "MAC addr in flash ROM:%s\n",
+ "MAC addr in flash ROM:%pM\n",
dev->name, this->base_addr, (int)dev->irq,
- print_mac(mac, dev->dev_addr));
+ dev->dev_addr);
/*
* Initialize card parameters - added by jss
*/
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index b16ec6e5f0e..b45c27d42fd 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -17,11 +17,11 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
+#include <linux/ieee80211.h>
#include <net/iw_handler.h>
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/firmware.h>
-#include <net/ieee80211.h>
#include "zd1201.h"
static struct usb_device_id zd1201_table[] = {
@@ -328,7 +328,6 @@ static void zd1201_usbrx(struct urb *urb)
memcpy(skb_put(skb, 2), &data[datalen-24], 2);
memcpy(skb_put(skb, len), data, len);
skb->protocol = eth_type_trans(skb, zd->dev);
- skb->dev->last_rx = jiffies;
zd->stats.rx_packets++;
zd->stats.rx_bytes += skb->len;
netif_rx(skb);
@@ -346,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb)
frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
if (!frag)
goto resubmit;
- skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
+ skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
if (!skb) {
kfree(frag);
goto resubmit;
@@ -385,7 +384,6 @@ static void zd1201_usbrx(struct urb *urb)
memcpy(skb_put(skb, len), data+8, len);
}
skb->protocol = eth_type_trans(skb, zd->dev);
- skb->dev->last_rx = jiffies;
zd->stats.rx_packets++;
zd->stats.rx_bytes += skb->len;
netif_rx(skb);
@@ -745,7 +743,7 @@ static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
static int zd1201_net_open(struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
/* Start MAC with wildcard if no essid set */
if (!zd->mac_enabled)
@@ -783,7 +781,7 @@ static int zd1201_net_stop(struct net_device *dev)
*/
static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
unsigned char *txbuf = zd->txdata;
int txbuflen, pad = 0, err;
struct urb *urb = zd->tx_urb;
@@ -833,7 +831,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void zd1201_tx_timeout(struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
if (!zd)
return;
@@ -848,7 +846,7 @@ static void zd1201_tx_timeout(struct net_device *dev)
static int zd1201_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
int err;
if (!zd)
@@ -865,21 +863,21 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p)
static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
return &zd->stats;
}
static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
return &zd->iwstats;
}
static void zd1201_set_multicast(struct net_device *dev)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
struct dev_mc_list *mc = dev->mc_list;
unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
int i;
@@ -899,7 +897,7 @@ static void zd1201_set_multicast(struct net_device *dev)
static int zd1201_config_commit(struct net_device *dev,
struct iw_request_info *info, struct iw_point *data, char *essid)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
return zd1201_mac_reset(zd);
}
@@ -914,7 +912,7 @@ static int zd1201_get_name(struct net_device *dev,
static int zd1201_set_freq(struct net_device *dev,
struct iw_request_info *info, struct iw_freq *freq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short channel = 0;
int err;
@@ -939,7 +937,7 @@ static int zd1201_set_freq(struct net_device *dev,
static int zd1201_get_freq(struct net_device *dev,
struct iw_request_info *info, struct iw_freq *freq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short channel;
int err;
@@ -955,7 +953,7 @@ static int zd1201_get_freq(struct net_device *dev,
static int zd1201_set_mode(struct net_device *dev,
struct iw_request_info *info, __u32 *mode, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short porttype, monitor = 0;
unsigned char buffer[IW_ESSID_MAX_SIZE+2];
int err;
@@ -1017,7 +1015,7 @@ static int zd1201_set_mode(struct net_device *dev,
static int zd1201_get_mode(struct net_device *dev,
struct iw_request_info *info, __u32 *mode, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short porttype;
int err;
@@ -1093,7 +1091,7 @@ static int zd1201_get_range(struct net_device *dev,
static int zd1201_get_wap(struct net_device *dev,
struct iw_request_info *info, struct sockaddr *ap_addr, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
unsigned char buffer[6];
if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
@@ -1121,7 +1119,7 @@ static int zd1201_set_scan(struct net_device *dev,
static int zd1201_get_scan(struct net_device *dev,
struct iw_request_info *info, struct iw_point *srq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
int err, i, j, enabled_save;
struct iw_event iwe;
char *cev = extra;
@@ -1213,7 +1211,7 @@ static int zd1201_get_scan(struct net_device *dev,
static int zd1201_set_essid(struct net_device *dev,
struct iw_request_info *info, struct iw_point *data, char *essid)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
if (data->length > IW_ESSID_MAX_SIZE)
return -EINVAL;
@@ -1228,7 +1226,7 @@ static int zd1201_set_essid(struct net_device *dev,
static int zd1201_get_essid(struct net_device *dev,
struct iw_request_info *info, struct iw_point *data, char *essid)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
memcpy(essid, zd->essid, zd->essidlen);
data->flags = 1;
@@ -1249,7 +1247,7 @@ static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
static int zd1201_set_rate(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short rate;
int err;
@@ -1282,7 +1280,7 @@ static int zd1201_set_rate(struct net_device *dev,
static int zd1201_get_rate(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short rate;
int err;
@@ -1315,7 +1313,7 @@ static int zd1201_get_rate(struct net_device *dev,
static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *rts, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
int err;
short val = rts->value;
@@ -1335,7 +1333,7 @@ static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *rts, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short rtst;
int err;
@@ -1352,7 +1350,7 @@ static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *frag, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
int err;
short val = frag->value;
@@ -1373,7 +1371,7 @@ static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
struct iw_param *frag, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short fragt;
int err;
@@ -1402,7 +1400,7 @@ static int zd1201_get_retry(struct net_device *dev,
static int zd1201_set_encode(struct net_device *dev,
struct iw_request_info *info, struct iw_point *erq, char *key)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short i;
int err, rid;
@@ -1459,7 +1457,7 @@ static int zd1201_set_encode(struct net_device *dev,
static int zd1201_get_encode(struct net_device *dev,
struct iw_request_info *info, struct iw_point *erq, char *key)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short i;
int err;
@@ -1492,7 +1490,7 @@ static int zd1201_get_encode(struct net_device *dev,
static int zd1201_set_power(struct net_device *dev,
struct iw_request_info *info, struct iw_param *vwrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short enabled, duration, level;
int err;
@@ -1531,7 +1529,7 @@ out:
static int zd1201_get_power(struct net_device *dev,
struct iw_request_info *info, struct iw_param *vwrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short enabled, level, duration;
int err;
@@ -1618,7 +1616,7 @@ static const iw_handler zd1201_iw_handler[] =
static int zd1201_set_hostauth(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
if (!zd->ap)
return -EOPNOTSUPP;
@@ -1629,7 +1627,7 @@ static int zd1201_set_hostauth(struct net_device *dev,
static int zd1201_get_hostauth(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short hostauth;
int err;
@@ -1648,7 +1646,7 @@ static int zd1201_get_hostauth(struct net_device *dev,
static int zd1201_auth_sta(struct net_device *dev,
struct iw_request_info *info, struct sockaddr *sta, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
unsigned char buffer[10];
if (!zd->ap)
@@ -1664,7 +1662,7 @@ static int zd1201_auth_sta(struct net_device *dev,
static int zd1201_set_maxassoc(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
int err;
if (!zd->ap)
@@ -1679,7 +1677,7 @@ static int zd1201_set_maxassoc(struct net_device *dev,
static int zd1201_get_maxassoc(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
- struct zd1201 *zd = (struct zd1201 *)dev->priv;
+ struct zd1201 *zd = netdev_priv(dev);
short maxassoc;
int err;
@@ -1731,6 +1729,7 @@ static int zd1201_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct zd1201 *zd;
+ struct net_device *dev;
struct usb_device *usb;
int err;
short porttype;
@@ -1738,9 +1737,12 @@ static int zd1201_probe(struct usb_interface *interface,
usb = interface_to_usbdev(interface);
- zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL);
- if (!zd)
+ dev = alloc_etherdev(sizeof(*zd));
+ if (!dev)
return -ENOMEM;
+ zd = netdev_priv(dev);
+ zd->dev = dev;
+
zd->ap = ap;
zd->usb = usb;
zd->removed = 0;
@@ -1775,34 +1777,29 @@ static int zd1201_probe(struct usb_interface *interface,
if (err)
goto err_start;
- zd->dev = alloc_etherdev(0);
- if (!zd->dev)
- goto err_start;
-
- zd->dev->priv = zd;
- zd->dev->open = zd1201_net_open;
- zd->dev->stop = zd1201_net_stop;
- zd->dev->get_stats = zd1201_get_stats;
- zd->dev->wireless_handlers =
+ dev->open = zd1201_net_open;
+ dev->stop = zd1201_net_stop;
+ dev->get_stats = zd1201_get_stats;
+ dev->wireless_handlers =
(struct iw_handler_def *)&zd1201_iw_handlers;
- zd->dev->hard_start_xmit = zd1201_hard_start_xmit;
- zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
- zd->dev->tx_timeout = zd1201_tx_timeout;
- zd->dev->set_multicast_list = zd1201_set_multicast;
- zd->dev->set_mac_address = zd1201_set_mac_address;
- strcpy(zd->dev->name, "wlan%d");
+ dev->hard_start_xmit = zd1201_hard_start_xmit;
+ dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
+ dev->tx_timeout = zd1201_tx_timeout;
+ dev->set_multicast_list = zd1201_set_multicast;
+ dev->set_mac_address = zd1201_set_mac_address;
+ strcpy(dev->name, "wlan%d");
err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR,
- zd->dev->dev_addr, zd->dev->addr_len);
+ dev->dev_addr, dev->addr_len);
if (err)
- goto err_net;
+ goto err_start;
/* Set wildcard essid to match zd->essid */
*(__le16 *)buf = cpu_to_le16(0);
err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
IW_ESSID_MAX_SIZE+2, 1);
if (err)
- goto err_net;
+ goto err_start;
if (zd->ap)
porttype = ZD1201_PORTTYPE_AP;
@@ -1810,30 +1807,28 @@ static int zd1201_probe(struct usb_interface *interface,
porttype = ZD1201_PORTTYPE_BSS;
err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
if (err)
- goto err_net;
+ goto err_start;
- SET_NETDEV_DEV(zd->dev, &usb->dev);
+ SET_NETDEV_DEV(dev, &usb->dev);
- err = register_netdev(zd->dev);
+ err = register_netdev(dev);
if (err)
- goto err_net;
+ goto err_start;
dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
- zd->dev->name);
+ dev->name);
usb_set_intfdata(interface, zd);
zd1201_enable(zd); /* zd1201 likes to startup enabled, */
zd1201_disable(zd); /* interfering with all the wifis in range */
return 0;
-err_net:
- free_netdev(zd->dev);
err_start:
/* Leave the device in reset state */
zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
err_zd:
usb_free_urb(zd->tx_urb);
usb_free_urb(zd->rx_urb);
- kfree(zd);
+ free_netdev(dev);
return err;
}
@@ -1846,10 +1841,6 @@ static void zd1201_disconnect(struct usb_interface *interface)
if (!zd)
return;
usb_set_intfdata(interface, NULL);
- if (zd->dev) {
- unregister_netdev(zd->dev);
- free_netdev(zd->dev);
- }
hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) {
hlist_del_init(&frag->fnode);
@@ -1865,7 +1856,11 @@ static void zd1201_disconnect(struct usb_interface *interface)
usb_kill_urb(zd->rx_urb);
usb_free_urb(zd->rx_urb);
}
- kfree(zd);
+
+ if (zd->dev) {
+ unregister_netdev(zd->dev);
+ free_netdev(zd->dev);
+ }
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index e0ac58b8ff1..f1519143f8a 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -378,7 +378,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
[0] = { .addr = CR_MAC_ADDR_P1 },
[1] = { .addr = CR_MAC_ADDR_P2 },
};
- DECLARE_MAC_BUF(mac);
if (mac_addr) {
reqs[0].value = (mac_addr[3] << 24)
@@ -387,8 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
| mac_addr[0];
reqs[1].value = (mac_addr[5] << 8)
| mac_addr[4];
- dev_dbg_f(zd_chip_dev(chip),
- "mac addr %s\n", print_mac(mac, mac_addr));
+ dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr);
} else {
dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n");
}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index fe1867b25ff..9caa96a1358 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -171,7 +171,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
r = zd_reg2alpha2(mac->regdomain, alpha2);
if (!r)
- regulatory_hint(hw->wiphy, alpha2, NULL);
+ regulatory_hint(hw->wiphy, alpha2);
r = 0;
disable_int:
@@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_hw *hw)
* If no status information has been requested, the skb is freed.
*/
static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- u32 flags, int ackssi, bool success)
+ int ackssi, bool success)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- memset(&info->status, 0, sizeof(info->status));
+ ieee80211_tx_info_clear_status(info);
- if (!success)
- info->status.excessive_retries = 1;
- info->flags |= flags;
+ if (success)
+ info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ackssi;
ieee80211_tx_status_irqsafe(hw, skb);
}
@@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
if (skb == NULL)
return;
- tx_status(hw, skb, 0, 0, 0);
+ tx_status(hw, skb, 0, 0);
}
/**
@@ -342,12 +341,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hw *hw = info->driver_data[0];
+ struct ieee80211_hw *hw = info->rate_driver_data[0];
skb_pull(skb, sizeof(struct zd_ctrlset));
if (unlikely(error ||
(info->flags & IEEE80211_TX_CTL_NO_ACK))) {
- tx_status(hw, skb, 0, 0, !error);
+ tx_status(hw, skb, 0, !error);
} else {
struct sk_buff_head *q =
&zd_hw_mac(hw)->ack_wait_queue;
@@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
}
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
- struct ieee80211_hdr *header, u32 flags)
+ struct ieee80211_hdr *header,
+ struct ieee80211_tx_info *info)
{
/*
* CONTROL TODO:
@@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control = 0;
/* First fragment */
- if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
/* Multicast */
@@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
if (ieee80211_is_pspoll(header->frame_control))
cs->control |= ZD_CS_PS_POLL_FRAME;
- if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
cs->control |= ZD_CS_RTS;
- if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
cs->control |= ZD_CS_SELF_CTS;
/* FIXME: Management frame? */
@@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *mac,
txrate = ieee80211_get_tx_rate(mac->hw, info);
cs->modulation = txrate->hw_value;
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
cs->modulation = txrate->hw_value_short;
cs->tx_length = cpu_to_le16(frag_len);
- cs_set_control(mac, cs, hdr, info->flags);
+ cs_set_control(mac, cs, hdr, info);
packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
ZD_ASSERT(packet_length <= 0xffff);
@@ -577,7 +577,7 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (r)
return r;
- info->driver_data[0] = hw;
+ info->rate_driver_data[0] = hw;
r = zd_usb_tx(&mac->chip.usb, skb);
if (r)
@@ -615,10 +615,10 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
struct ieee80211_hdr *tx_hdr;
tx_hdr = (struct ieee80211_hdr *)skb->data;
- if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
+ if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN)))
{
__skb_unlink(skb, q);
- tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
+ tx_status(hw, skb, stats->signal, 1);
goto out;
}
}
@@ -743,9 +743,11 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
zd_write_mac_addr(&mac->chip, NULL);
}
-static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct zd_mac *mac = zd_hw_mac(hw);
+ struct ieee80211_conf *conf = &hw->conf;
+
return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
}
@@ -852,14 +854,12 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
zd_mc_add_all(&hash);
} else {
- DECLARE_MAC_BUF(macbuf);
-
zd_mc_clear(&hash);
for (i = 0; i < mc_count; i++) {
if (!mclist)
break;
- dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
- print_mac(macbuf, mclist->dmi_addr));
+ dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
+ mclist->dmi_addr);
zd_mc_add_addr(&hash, mclist->dmi_addr);
mclist = mclist->next;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index a3ccd8c1c71..b5db57d2fcf 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -909,7 +909,7 @@ free_urb:
* it might be freed by zd_mac_tx_to_dev or mac80211)
*/
info = IEEE80211_SKB_CB(skb);
- usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
+ usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
zd_mac_tx_to_dev(skb, urb->status);
free_tx_urb(usb, urb);
tx_dec_submitted_urbs(usb);
@@ -1065,8 +1065,7 @@ static int eject_installer(struct usb_interface *intf)
/* Find bulk out endpoint */
endpoint = &iface_desc->endpoint[1].desc;
if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
- (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_BULK) {
+ usb_endpoint_xfer_bulk(endpoint)) {
bulk_out_ep = endpoint->bEndpointAddress;
} else {
dev_err(&udev->dev,