Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
John W. Linville [Thu, 15 Apr 2010 20:21:34 +0000 (16:21 -0400)]
Conflicts:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/wl12xx/wl1271_main.c

174 files changed:
Documentation/feature-removal-schedule.txt
drivers/net/wireless/ath/ar9170/cmd.h
drivers/net/wireless/ath/ar9170/eeprom.h
drivers/net/wireless/ath/ar9170/hw.h
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/Makefile
drivers/net/wireless/ath/ath5k/ani.c [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/ani.h [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/caps.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/debug.h
drivers/net/wireless/ath/ath5k/desc.c
drivers/net/wireless/ath/ath5k/desc.h
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/initvals.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/virtual.c
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/hw.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965-hw.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-hw.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-ict.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/prism54/islpci_mgt.c
drivers/net/wireless/prism54/oid_mgt.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_spi.c
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_acx.c
drivers/net/wireless/wl12xx/wl1271_acx.h
drivers/net/wireless/wl12xx/wl1271_boot.c
drivers/net/wireless/wl12xx/wl1271_boot.h
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_cmd.h
drivers/net/wireless/wl12xx/wl1271_conf.h
drivers/net/wireless/wl12xx/wl1271_event.c
drivers/net/wireless/wl12xx/wl1271_event.h
drivers/net/wireless/wl12xx/wl1271_init.c
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_ps.c
drivers/net/wireless/wl12xx/wl1271_rx.c
drivers/net/wireless/wl12xx/wl1271_rx.h
drivers/net/wireless/wl12xx/wl1271_sdio.c
drivers/net/wireless/wl12xx/wl1271_spi.c
drivers/net/wireless/wl12xx/wl1271_tx.c
drivers/net/wireless/wl12xx/wl1271_tx.h
include/linux/ieee80211.h
include/linux/mmc/sdio.h
include/linux/nl80211.h
include/net/cfg80211.h
include/net/iw_handler.h
include/net/mac80211.h
net/mac80211/Kconfig
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/work.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
net/wireless/util.c

index 267e905..116a13c 100644 (file)
@@ -520,7 +520,6 @@ Who:        Hans de Goede <hdegoede@redhat.com>
 
 ----------------------------
 
-
 What:  corgikbd, spitzkbd, tosakbd driver
 When:  2.6.35
 Files: drivers/input/keyboard/{corgi,spitz,tosa}kbd.c
@@ -608,3 +607,24 @@ Why:       Useful in 2003, implementation is a hack.
        Generally invoked by accident today.
        Seen as doing more harm than good.
 Who:   Len Brown <len.brown@intel.com>
+
+----------------------------
+
+What:  iwlwifi 50XX module parameters
+When:  2.6.40
+Why:   The "..50" modules parameters were used to configure 5000 series and
+       up devices; different set of module parameters also available for 4965
+       with same functionalities. Consolidate both set into single place
+       in drivers/net/wireless/iwlwifi/iwl-agn.c
+
+Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+----------------------------
+
+What:  iwl4965 alias support
+When:  2.6.40
+Why:   Internal alias support has been present in module-init-tools for some
+       time, the MODULE_ALIAS("iwl4965") boilerplate aliases can be removed
+       with no impact.
+
+Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
index 826c45e..ec8134b 100644 (file)
@@ -79,7 +79,7 @@ __regwrite_out :                                                      \
        if (__nreg) {                                                   \
                if (IS_ACCEPTING_CMD(__ar))                             \
                        __err = ar->exec_cmd(__ar, AR9170_CMD_WREG,     \
-                                            8 * __nreg,                \
+                                            8 * __nreg,                \
                                             (u8 *) &__ar->cmdbuf[1],   \
                                             0, NULL);                  \
                __nreg = 0;                                             \
index d2c8cc8..6c46638 100644 (file)
@@ -127,8 +127,8 @@ struct ar9170_eeprom {
        __le16  checksum;
        __le16  version;
        u8      operating_flags;
-#define AR9170_OPFLAG_5GHZ             1
-#define AR9170_OPFLAG_2GHZ             2
+#define AR9170_OPFLAG_5GHZ             1
+#define AR9170_OPFLAG_2GHZ             2
        u8      misc;
        __le16  reg_domain[2];
        u8      mac_address[6];
index 0a1d4c2..06f1f3c 100644 (file)
@@ -425,5 +425,6 @@ enum ar9170_txq {
 
 #define AR9170_TXQ_DEPTH       32
 #define AR9170_TX_MAX_PENDING  128
+#define AR9170_RX_STREAM_MAX_SIZE 65535
 
 #endif /* __AR9170_HW_H */
index 7c4a7d8..0312cee 100644 (file)
@@ -236,7 +236,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
               wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
 
        skb_queue_walk(queue, skb) {
-               printk(KERN_DEBUG "index:%d => \n", i++);
+               printk(KERN_DEBUG "index:%d =>\n", i++);
                ar9170_print_txheader(ar, skb);
        }
        if (i != skb_queue_len(queue))
@@ -281,7 +281,7 @@ static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
        unsigned long flags;
 
        spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
-       printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+       printk(KERN_DEBUG "%s: A-MPDU tx_status queue =>\n",
               wiphy_name(ar->hw->wiphy));
        __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
        spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
@@ -308,7 +308,7 @@ static void ar9170_recycle_expired(struct ar9170 *ar,
                if (time_is_before_jiffies(arinfo->timeout)) {
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
-                              "recycle \n", wiphy_name(ar->hw->wiphy),
+                              "recycle\n", wiphy_name(ar->hw->wiphy),
                               jiffies, arinfo->timeout);
                        ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
@@ -689,7 +689,8 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 
        /* firmware debug */
        case 0xca:
-               printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4);
+               printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4,
+                               (char *)buf + 4);
                break;
        case 0xcb:
                len -= 4;
@@ -1728,7 +1729,7 @@ static void ar9170_tx(struct ar9170 *ar)
                        printk(KERN_DEBUG "%s: queue %d full\n",
                               wiphy_name(ar->hw->wiphy), i);
 
-                       printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+                       printk(KERN_DEBUG "%s: stuck frames: ===>\n",
                               wiphy_name(ar->hw->wiphy));
                        ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
                        ar9170_dump_txqueue(ar, &ar->tx_status[i]);
@@ -2512,7 +2513,7 @@ void *ar9170_alloc(size_t priv_size)
         * tends to split the streams into separate rx descriptors.
         */
 
-       skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
+       skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
        if (!skb)
                goto err_nomem;
 
index 99a6da4..c1c7c42 100644 (file)
@@ -67,18 +67,28 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x1001) },
        /* TP-Link TL-WN821N v2 */
        { USB_DEVICE(0x0cf3, 0x1002) },
+       /* 3Com Dual Band 802.11n USB Adapter */
+       { USB_DEVICE(0x0cf3, 0x1010) },
+       /* H3C Dual Band 802.11n USB Adapter */
+       { USB_DEVICE(0x0cf3, 0x1011) },
        /* Cace Airpcap NX */
        { USB_DEVICE(0xcace, 0x0300) },
        /* D-Link DWA 160 A1 */
        { USB_DEVICE(0x07d1, 0x3c10) },
        /* D-Link DWA 160 A2 */
        { USB_DEVICE(0x07d1, 0x3a09) },
+       /* Netgear WNA1000 */
+       { USB_DEVICE(0x0846, 0x9040) },
        /* Netgear WNDA3100 */
        { USB_DEVICE(0x0846, 0x9010) },
        /* Netgear WN111 v2 */
        { USB_DEVICE(0x0846, 0x9001) },
        /* Zydas ZD1221 */
        { USB_DEVICE(0x0ace, 0x1221) },
+       /* Proxim ORiNOCO 802.11n USB */
+       { USB_DEVICE(0x1435, 0x0804) },
+       /* WNC Generic 11n USB Dongle */
+       { USB_DEVICE(0x1435, 0x0326) },
        /* ZyXEL NWD271N */
        { USB_DEVICE(0x0586, 0x3417) },
        /* Z-Com UB81 BG */
index 71fc960..1fbf6b1 100644 (file)
@@ -48,6 +48,12 @@ enum ath_device_state {
        ATH_HW_INITIALIZED,
 };
 
+enum ath_bus_type {
+       ATH_PCI,
+       ATH_AHB,
+       ATH_USB,
+};
+
 struct reg_dmn_pair_mapping {
        u16 regDmnEnum;
        u16 reg_5ghz_ctl;
@@ -73,9 +79,10 @@ struct ath_ops {
 struct ath_common;
 
 struct ath_bus_ops {
-       void            (*read_cachesize)(struct ath_common *common, int *csz);
-       bool            (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
-       void            (*bt_coex_prep)(struct ath_common *common);
+       enum ath_bus_type ath_bus_type;
+       void (*read_cachesize)(struct ath_common *common, int *csz);
+       bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+       void (*bt_coex_prep)(struct ath_common *common);
 };
 
 struct ath_common {
index 090dc6d..cc09595 100644 (file)
@@ -12,5 +12,6 @@ ath5k-y                               += attach.o
 ath5k-y                                += base.o
 ath5k-y                                += led.o
 ath5k-y                                += rfkill.o
+ath5k-y                                += ani.o
 ath5k-$(CONFIG_ATH5K_DEBUG)    += debug.o
 obj-$(CONFIG_ATH5K)            += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
new file mode 100644 (file)
index 0000000..584a328
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * 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 "ath5k.h"
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+#include "ani.h"
+
+/**
+ * DOC: Basic ANI Operation
+ *
+ * Adaptive Noise Immunity (ANI) controls five noise immunity parameters
+ * depending on the amount of interference in the environment, increasing
+ * or reducing sensitivity as necessary.
+ *
+ * The parameters are:
+ *   - "noise immunity"
+ *   - "spur immunity"
+ *   - "firstep level"
+ *   - "OFDM weak signal detection"
+ *   - "CCK weak signal detection"
+ *
+ * Basically we look at the amount of ODFM and CCK timing errors we get and then
+ * raise or lower immunity accordingly by setting one or more of these
+ * parameters.
+ * Newer chipsets have PHY error counters in hardware which will generate a MIB
+ * interrupt when they overflow. Older hardware has too enable PHY error frames
+ * by setting a RX flag and then count every single PHY error. When a specified
+ * threshold of errors has been reached we will raise immunity.
+ * Also we regularly check the amount of errors and lower or raise immunity as
+ * necessary.
+ */
+
+
+/*** ANI parameter control ***/
+
+/**
+ * ath5k_ani_set_noise_immunity_level() - Set noise immunity level
+ *
+ * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL
+ */
+void
+ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
+{
+       /* TODO:
+        * ANI documents suggest the following five levels to use, but the HAL
+        * and ath9k use only use the last two levels, making this
+        * essentially an on/off option. There *may* be a reason for this (???),
+        * so i stick with the HAL version for now...
+        */
+#if 0
+       const s8 hi[] = { -18, -18, -16, -14, -12 };
+       const s8 lo[] = { -52, -56, -60, -64, -70 };
+       const s8 sz[] = { -34, -41, -48, -55, -62 };
+       const s8 fr[] = { -70, -72, -75, -78, -80 };
+#else
+       const s8 sz[] = { -55, -62 };
+       const s8 lo[] = { -64, -70 };
+       const s8 hi[] = { -14, -12 };
+       const s8 fr[] = { -78, -80 };
+#endif
+       if (level < 0 || level > ARRAY_SIZE(sz)) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_TOT, sz[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE,
+                               AR5K_PHY_AGCCOARSE_LO, lo[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE,
+                               AR5K_PHY_AGCCOARSE_HI, hi[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG,
+                               AR5K_PHY_SIG_FIRPWR, fr[level]);
+
+       ah->ah_sc->ani_state.noise_imm_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_spur_immunity_level() - Set spur immunity level
+ *
+ * @level: level between 0 and @max_spur_level (the maximum level is dependent
+ *     on the chip revision).
+ */
+void
+ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
+{
+       const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+
+       if (level < 0 || level > ARRAY_SIZE(val) ||
+           level > ah->ah_sc->ani_state.max_spur_level) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+               AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]);
+
+       ah->ah_sc->ani_state.spur_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_firstep_level() - Set "firstep" level
+ *
+ * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL
+ */
+void
+ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
+{
+       const int val[] = { 0, 4, 8 };
+
+       if (level < 0 || level > ARRAY_SIZE(val)) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG,
+                               AR5K_PHY_SIG_FIRSTEP, val[level]);
+
+       ah->ah_sc->ani_state.firstep_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal
+ *                                             detection
+ *
+ * @on: turn on or off
+ */
+void
+ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
+{
+       const int m1l[] = { 127, 50 };
+       const int m2l[] = { 127, 40 };
+       const int m1[] = { 127, 0x4d };
+       const int m2[] = { 127, 0x40 };
+       const int m2cnt[] = { 31, 16 };
+       const int m2lcnt[] = { 63, 48 };
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_M2, m2l[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                               AR5K_PHY_WEAK_OFDM_HIGH_THR_M1, m1[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                               AR5K_PHY_WEAK_OFDM_HIGH_THR_M2, m2[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                       AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT, m2cnt[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                       AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT, m2lcnt[on]);
+
+       if (on)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN);
+       else
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN);
+
+       ah->ah_sc->ani_state.ofdm_weak_sig = on;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s",
+                         on ? "on" : "off");
+}
+
+
+/**
+ * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection
+ *
+ * @on: turn on or off
+ */
+void
+ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
+{
+       const int val[] = { 8, 6 };
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR,
+                               AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]);
+       ah->ah_sc->ani_state.cck_weak_sig = on;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s",
+                         on ? "on" : "off");
+}
+
+
+/*** ANI algorithm ***/
+
+/**
+ * ath5k_ani_raise_immunity() - Increase noise immunity
+ *
+ * @ofdm_trigger: If this is true we are called because of too many OFDM errors,
+ *     the algorithm will tune more parameters then.
+ *
+ * Try to raise noise immunity (=decrease sensitivity) in several steps
+ * depending on the average RSSI of the beacons we received.
+ */
+static void
+ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
+                        bool ofdm_trigger)
+{
+       int rssi = ah->ah_beacon_rssi_avg.avg;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)",
+               ofdm_trigger ? "ODFM" : "CCK");
+
+       /* first: raise noise immunity */
+       if (as->noise_imm_level < ATH5K_ANI_MAX_NOISE_IMM_LVL) {
+               ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level + 1);
+               return;
+       }
+
+       /* only OFDM: raise spur immunity level */
+       if (ofdm_trigger &&
+           as->spur_level < ah->ah_sc->ani_state.max_spur_level) {
+               ath5k_ani_set_spur_immunity_level(ah, as->spur_level + 1);
+               return;
+       }
+
+       /* AP mode */
+       if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) {
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL)
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+               return;
+       }
+
+       /* STA and IBSS mode */
+
+       /* TODO: for IBSS mode it would be better to keep a beacon RSSI average
+        * per each neighbour node and use the minimum of these, to make sure we
+        * don't shut out a remote node by raising immunity too high. */
+
+       if (rssi > ATH5K_ANI_RSSI_THR_HIGH) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI high");
+               /* only OFDM: beacon RSSI is high, we can disable ODFM weak
+                * signal detection */
+               if (ofdm_trigger && as->ofdm_weak_sig == true) {
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+                       ath5k_ani_set_spur_immunity_level(ah, 0);
+                       return;
+               }
+               /* as a last resort or CCK: raise firstep level */
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) {
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+                       return;
+               }
+       } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) {
+               /* beacon RSSI in mid range, we need OFDM weak signal detect,
+                * but can raise firstep level */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI mid");
+               if (ofdm_trigger && as->ofdm_weak_sig == false)
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL)
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+               return;
+       } else if (ah->ah_current_channel->band == IEEE80211_BAND_2GHZ) {
+               /* beacon RSSI is low. in B/G mode turn of OFDM weak signal
+                * detect and zero firstep level to maximize CCK sensitivity */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI low, 2GHz");
+               if (ofdm_trigger && as->ofdm_weak_sig == true)
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+               if (as->firstep_level > 0)
+                       ath5k_ani_set_firstep_level(ah, 0);
+               return;
+       }
+
+       /* TODO: why not?:
+       if (as->cck_weak_sig == true) {
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       }
+       */
+}
+
+
+/**
+ * ath5k_ani_lower_immunity() - Decrease noise immunity
+ *
+ * Try to lower noise immunity (=increase sensitivity) in several steps
+ * depending on the average RSSI of the beacons we received.
+ */
+static void
+ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       int rssi = ah->ah_beacon_rssi_avg.avg;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity");
+
+       if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) {
+               /* AP mode */
+               if (as->firstep_level > 0) {
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level - 1);
+                       return;
+               }
+       } else {
+               /* STA and IBSS mode (see TODO above) */
+               if (rssi > ATH5K_ANI_RSSI_THR_HIGH) {
+                       /* beacon signal is high, leave OFDM weak signal
+                        * detection off or it may oscillate
+                        * TODO: who said it's off??? */
+               } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) {
+                       /* beacon RSSI is mid-range: turn on ODFM weak signal
+                        * detection and next, lower firstep level */
+                       if (as->ofdm_weak_sig == false) {
+                               ath5k_ani_set_ofdm_weak_signal_detection(ah,
+                                                                        true);
+                               return;
+                       }
+                       if (as->firstep_level > 0) {
+                               ath5k_ani_set_firstep_level(ah,
+                                                       as->firstep_level - 1);
+                               return;
+                       }
+               } else {
+                       /* beacon signal is low: only reduce firstep level */
+                       if (as->firstep_level > 0) {
+                               ath5k_ani_set_firstep_level(ah,
+                                                       as->firstep_level - 1);
+                               return;
+                       }
+               }
+       }
+
+       /* all modes */
+       if (as->spur_level > 0) {
+               ath5k_ani_set_spur_immunity_level(ah, as->spur_level - 1);
+               return;
+       }
+
+       /* finally, reduce noise immunity */
+       if (as->noise_imm_level > 0) {
+               ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level - 1);
+               return;
+       }
+}
+
+
+/**
+ * ath5k_hw_ani_get_listen_time() - Calculate time spent listening
+ *
+ * Return an approximation of the time spent "listening" in milliseconds (ms)
+ * since the last call of this function by deducting the cycles spent
+ * transmitting and receiving from the total cycle count.
+ * Save profile count values for debugging/statistics and because we might want
+ * to use them later.
+ *
+ * We assume no one else clears these registers!
+ */
+static int
+ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       int listen;
+
+       /* freeze */
+       ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC);
+       /* read */
+       as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE);
+       as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR);
+       as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX);
+       as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX);
+       /* clear */
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
+       /* un-freeze */
+       ath5k_hw_reg_write(ah, 0, AR5K_MIBC);
+
+       /* TODO: where does 44000 come from? (11g clock rate?) */
+       listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000;
+
+       if (as->pfc_cycles == 0 || listen < 0)
+               return 0;
+       return listen;
+}
+
+
+/**
+ * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters
+ *
+ * Clear the PHY error counters as soon as possible, since this might be called
+ * from a MIB interrupt and we want to make sure we don't get interrupted again.
+ * Add the count of CCK and OFDM errors to our internal state, so it can be used
+ * by the algorithm later.
+ *
+ * Will be called from interrupt and tasklet context.
+ * Returns 0 if both counters are zero.
+ */
+static int
+ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah,
+                                   struct ath5k_ani_state *as)
+{
+       unsigned int ofdm_err, cck_err;
+
+       if (!ah->ah_capabilities.cap_has_phyerr_counters)
+               return 0;
+
+       ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1);
+       cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2);
+
+       /* reset counters first, we might be in a hurry (interrupt) */
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH,
+                          AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH,
+                          AR5K_PHYERR_CNT2);
+
+       ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err);
+       cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err);
+
+       /* sometimes both can be zero, especially when there is a superfluous
+        * second interrupt. detect that here and return an error. */
+       if (ofdm_err <= 0 && cck_err <= 0)
+               return 0;
+
+       /* avoid negative values should one of the registers overflow */
+       if (ofdm_err > 0) {
+               as->ofdm_errors += ofdm_err;
+               as->sum_ofdm_errors += ofdm_err;
+       }
+       if (cck_err > 0) {
+               as->cck_errors += cck_err;
+               as->sum_cck_errors += cck_err;
+       }
+       return 1;
+}
+
+
+/**
+ * ath5k_ani_period_restart() - Restart ANI period
+ *
+ * Just reset counters, so they are clear for the next "ani period".
+ */
+static void
+ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       /* keep last values for debugging */
+       as->last_ofdm_errors = as->ofdm_errors;
+       as->last_cck_errors = as->cck_errors;
+       as->last_listen = as->listen_time;
+
+       as->ofdm_errors = 0;
+       as->cck_errors = 0;
+       as->listen_time = 0;
+}
+
+
+/**
+ * ath5k_ani_calibration() - The main ANI calibration function
+ *
+ * We count OFDM and CCK errors relative to the time where we did not send or
+ * receive ("listen" time) and raise or lower immunity accordingly.
+ * This is called regularly (every second) from the calibration timer, but also
+ * when an error threshold has been reached.
+ *
+ * In order to synchronize access from different contexts, this should be
+ * called only indirectly by scheduling the ANI tasklet!
+ */
+void
+ath5k_ani_calibration(struct ath5k_hw *ah)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+       int listen, ofdm_high, ofdm_low, cck_high, cck_low;
+
+       if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
+               return;
+
+       /* get listen time since last call and add it to the counter because we
+        * might not have restarted the "ani period" last time */
+       listen = ath5k_hw_ani_get_listen_time(ah, as);
+       as->listen_time += listen;
+
+       ath5k_ani_save_and_clear_phy_errors(ah, as);
+
+       ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000;
+       cck_high = as->listen_time * ATH5K_ANI_CCK_TRIG_HIGH / 1000;
+       ofdm_low = as->listen_time * ATH5K_ANI_OFDM_TRIG_LOW / 1000;
+       cck_low = as->listen_time * ATH5K_ANI_CCK_TRIG_LOW / 1000;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+               "listen %d (now %d)", as->listen_time, listen);
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+               "check high ofdm %d/%d cck %d/%d",
+               as->ofdm_errors, ofdm_high, as->cck_errors, cck_high);
+
+       if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) {
+               /* too many PHY errors - we have to raise immunity */
+               bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false;
+               ath5k_ani_raise_immunity(ah, as, ofdm_flag);
+               ath5k_ani_period_restart(ah, as);
+
+       } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) {
+               /* If more than 5 (TODO: why 5?) periods have passed and we got
+                * relatively little errors we can try to lower immunity */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "check low ofdm %d/%d cck %d/%d",
+                       as->ofdm_errors, ofdm_low, as->cck_errors, cck_low);
+
+               if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low)
+                       ath5k_ani_lower_immunity(ah, as);
+
+               ath5k_ani_period_restart(ah, as);
+       }
+}
+
+
+/*** INTERRUPT HANDLER ***/
+
+/**
+ * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters
+ *
+ * Just read & reset the registers quickly, so they don't generate more
+ * interrupts, save the counters and schedule the tasklet to decide whether
+ * to raise immunity or not.
+ *
+ * We just need to handle PHY error counters, ath5k_hw_update_mib_counters()
+ * should take care of all "normal" MIB interrupts.
+ */
+void
+ath5k_ani_mib_intr(struct ath5k_hw *ah)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+
+       /* nothing to do here if HW does not have PHY error counters - they
+        * can't be the reason for the MIB interrupt then */
+       if (!ah->ah_capabilities.cap_has_phyerr_counters)
+               return;
+
+       /* not in use but clear anyways */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+
+       if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
+               return;
+
+       /* if one of the errors triggered, we can get a superfluous second
+        * interrupt, even though we have already reset the register. the
+        * function detects that so we can return early */
+       if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
+               return;
+
+       if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH ||
+           as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH)
+               tasklet_schedule(&ah->ah_sc->ani_tasklet);
+}
+
+
+/**
+ * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors
+ *
+ * This is used by hardware without PHY error counters to report PHY errors
+ * on a frame-by-frame basis, instead of the interrupt.
+ */
+void
+ath5k_ani_phy_error_report(struct ath5k_hw *ah,
+                          enum ath5k_phy_error_code phyerr)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+
+       if (phyerr == AR5K_RX_PHY_ERROR_OFDM_TIMING) {
+               as->ofdm_errors++;
+               if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH)
+                       tasklet_schedule(&ah->ah_sc->ani_tasklet);
+       } else if (phyerr == AR5K_RX_PHY_ERROR_CCK_TIMING) {
+               as->cck_errors++;
+               if (as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH)
+                       tasklet_schedule(&ah->ah_sc->ani_tasklet);
+       }
+}
+
+
+/*** INIT ***/
+
+/**
+ * ath5k_enable_phy_err_counters() - Enable PHY error counters
+ *
+ * Enable PHY error counters for OFDM and CCK timing errors.
+ */
+static void
+ath5k_enable_phy_err_counters(struct ath5k_hw *ah)
+{
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH,
+                          AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH,
+                          AR5K_PHYERR_CNT2);
+       ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_OFDM, AR5K_PHYERR_CNT1_MASK);
+       ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_CCK, AR5K_PHYERR_CNT2_MASK);
+
+       /* not in use */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+}
+
+
+/**
+ * ath5k_disable_phy_err_counters() - Disable PHY error counters
+ *
+ * Disable PHY error counters for OFDM and CCK timing errors.
+ */
+static void
+ath5k_disable_phy_err_counters(struct ath5k_hw *ah)
+{
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1_MASK);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2_MASK);
+
+       /* not in use */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+}
+
+
+/**
+ * ath5k_ani_init() - Initialize ANI
+ * @mode: Which mode to use (auto, manual high, manual low, off)
+ *
+ * Initialize ANI according to mode.
+ */
+void
+ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
+{
+       /* ANI is only possible on 5212 and newer */
+       if (ah->ah_version < AR5K_AR5212)
+               return;
+
+       /* clear old state information */
+       memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state));
+
+       /* older hardware has more spur levels than newer */
+       if (ah->ah_mac_srev < AR5K_SREV_AR2414)
+               ah->ah_sc->ani_state.max_spur_level = 7;
+       else
+               ah->ah_sc->ani_state.max_spur_level = 2;
+
+       /* initial values for our ani parameters */
+       if (mode == ATH5K_ANI_MODE_OFF) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n");
+       } else if  (mode == ATH5K_ANI_MODE_MANUAL_LOW) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "ANI manual low -> high sensitivity\n");
+               ath5k_ani_set_noise_immunity_level(ah, 0);
+               ath5k_ani_set_spur_immunity_level(ah, 0);
+               ath5k_ani_set_firstep_level(ah, 0);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               ath5k_ani_set_cck_weak_signal_detection(ah, true);
+       } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "ANI manual high -> low sensitivity\n");
+               ath5k_ani_set_noise_immunity_level(ah,
+                                       ATH5K_ANI_MAX_NOISE_IMM_LVL);
+               ath5k_ani_set_spur_immunity_level(ah,
+                                       ah->ah_sc->ani_state.max_spur_level);
+               ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       } else if (mode == ATH5K_ANI_MODE_AUTO) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI auto\n");
+               ath5k_ani_set_noise_immunity_level(ah, 0);
+               ath5k_ani_set_spur_immunity_level(ah, 0);
+               ath5k_ani_set_firstep_level(ah, 0);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       }
+
+       /* newer hardware has PHY error counter registers which we can use to
+        * get OFDM and CCK error counts. older hardware has to set rxfilter and
+        * report every single PHY error by calling ath5k_ani_phy_error_report()
+        */
+       if (mode == ATH5K_ANI_MODE_AUTO) {
+               if (ah->ah_capabilities.cap_has_phyerr_counters)
+                       ath5k_enable_phy_err_counters(ah);
+               else
+                       ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) |
+                                                  AR5K_RX_FILTER_PHYERR);
+       } else {
+               if (ah->ah_capabilities.cap_has_phyerr_counters)
+                       ath5k_disable_phy_err_counters(ah);
+               else
+                       ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) &
+                                                  ~AR5K_RX_FILTER_PHYERR);
+       }
+
+       ah->ah_sc->ani_state.ani_mode = mode;
+}
+
+
+/*** DEBUG ***/
+
+#ifdef CONFIG_ATH5K_DEBUG
+
+void
+ath5k_ani_print_counters(struct ath5k_hw *ah)
+{
+       /* clears too */
+       printk(KERN_NOTICE "ACK fail\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_ACK_FAIL));
+       printk(KERN_NOTICE "RTS fail\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_RTS_FAIL));
+       printk(KERN_NOTICE "RTS success\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_RTS_OK));
+       printk(KERN_NOTICE "FCS error\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_FCS_FAIL));
+
+       /* no clear */
+       printk(KERN_NOTICE "tx\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX));
+       printk(KERN_NOTICE "rx\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX));
+       printk(KERN_NOTICE "busy\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR));
+       printk(KERN_NOTICE "cycles\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE));
+
+       printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1));
+       printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2));
+       printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT));
+       printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT));
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h
new file mode 100644 (file)
index 0000000..55cf26d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef ANI_H
+#define ANI_H
+
+/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */
+#define ATH5K_ANI_LISTEN_PERIOD                100
+#define ATH5K_ANI_OFDM_TRIG_HIGH       500
+#define ATH5K_ANI_OFDM_TRIG_LOW                200
+#define ATH5K_ANI_CCK_TRIG_HIGH                200
+#define ATH5K_ANI_CCK_TRIG_LOW         100
+
+/* average beacon RSSI thresholds */
+#define ATH5K_ANI_RSSI_THR_HIGH                40
+#define ATH5K_ANI_RSSI_THR_LOW         7
+
+/* maximum availabe levels */
+#define ATH5K_ANI_MAX_FIRSTEP_LVL      2
+#define ATH5K_ANI_MAX_NOISE_IMM_LVL    1
+
+
+/**
+ * enum ath5k_ani_mode - mode for ANI / noise sensitivity
+ *
+ * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI
+ *     algorithm after it has been on auto mode.
+ * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
+ *     maximizing sensitivity. ANI will not run.
+ * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
+ *     minimizing sensitivity. ANI will not run.
+ * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
+ *     amount of OFDM and CCK frame errors (default).
+ */
+enum ath5k_ani_mode {
+       ATH5K_ANI_MODE_OFF              = 0,
+       ATH5K_ANI_MODE_MANUAL_LOW       = 1,
+       ATH5K_ANI_MODE_MANUAL_HIGH      = 2,
+       ATH5K_ANI_MODE_AUTO             = 3
+};
+
+
+/**
+ * struct ath5k_ani_state - ANI state and associated counters
+ *
+ * @max_spur_level: the maximum spur level is chip dependent
+ */
+struct ath5k_ani_state {
+       enum ath5k_ani_mode     ani_mode;
+
+       /* state */
+       int                     noise_imm_level;
+       int                     spur_level;
+       int                     firstep_level;
+       bool                    ofdm_weak_sig;
+       bool                    cck_weak_sig;
+
+       int                     max_spur_level;
+
+       /* used by the algorithm */
+       unsigned int            listen_time;
+       unsigned int            ofdm_errors;
+       unsigned int            cck_errors;
+
+       /* debug/statistics only: numbers from last ANI calibration */
+       unsigned int            pfc_tx;
+       unsigned int            pfc_rx;
+       unsigned int            pfc_busy;
+       unsigned int            pfc_cycles;
+       unsigned int            last_listen;
+       unsigned int            last_ofdm_errors;
+       unsigned int            last_cck_errors;
+       unsigned int            sum_ofdm_errors;
+       unsigned int            sum_cck_errors;
+};
+
+void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode);
+void ath5k_ani_mib_intr(struct ath5k_hw *ah);
+void ath5k_ani_calibration(struct ath5k_hw *ah);
+void ath5k_ani_phy_error_report(struct ath5k_hw *ah,
+                               enum ath5k_phy_error_code phyerr);
+
+/* for manual control */
+void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on);
+void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on);
+
+void ath5k_ani_print_counters(struct ath5k_hw *ah);
+
+#endif /* ANI_H */
index 1d7491c..2785946 100644 (file)
 #define AR5K_TUNE_MAX_TXPOWER                  63
 #define AR5K_TUNE_DEFAULT_TXPOWER              25
 #define AR5K_TUNE_TPC_TXPOWER                  false
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL    10000   /* 10 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI    1000    /* 1 sec */
 
 #define AR5K_INIT_CARR_SENSE_EN                        1
 
@@ -799,9 +801,9 @@ struct ath5k_athchan_2ghz {
  * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
  *     We currently do increments on interrupt by
  *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
- * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
- *     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_MIB: Indicates the either Management Information Base counters or
+ *     one of the PHY error counters reached the maximum value and should be
+ *     read and cleared.
  * @AR5K_INT_RXPHY: RX PHY Error
  * @AR5K_INT_RXKCM: RX Key cache miss
  * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
@@ -889,10 +891,11 @@ enum ath5k_int {
        AR5K_INT_NOCARD = 0xffffffff
 };
 
-/* Software interrupts used for calibration */
-enum ath5k_software_interrupt {
-       AR5K_SWI_FULL_CALIBRATION = 0x01,
-       AR5K_SWI_SHORT_CALIBRATION = 0x02,
+/* mask which calibration is active at the moment */
+enum ath5k_calibration_mask {
+       AR5K_CALIBRATION_FULL = 0x01,
+       AR5K_CALIBRATION_SHORT = 0x02,
+       AR5K_CALIBRATION_ANI = 0x04,
 };
 
 /*
@@ -981,6 +984,8 @@ struct ath5k_capabilities {
        struct {
                u8      q_tx_num;
        } cap_queues;
+
+       bool cap_has_phyerr_counters;
 };
 
 /* size of noise floor history (keep it a power of two) */
@@ -991,6 +996,15 @@ struct ath5k_nfcal_hist
        s16 nfval[ATH5K_NF_CAL_HIST_MAX];       /* last few noise floors */
 };
 
+/**
+ * struct avg_val - Helper structure for average calculation
+ * @avg: contains the actual average value
+ * @avg_weight: is used internally during calculation to prevent rounding errors
+ */
+struct ath5k_avg_val {
+       int avg;
+       int avg_weight;
+};
 
 /***************************************\
   HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1095,17 +1109,18 @@ struct ath5k_hw {
 
        struct ath5k_nfcal_hist ah_nfcal_hist;
 
+       /* average beacon RSSI in our BSS (used by ANI) */
+       struct ath5k_avg_val    ah_beacon_rssi_avg;
+
        /* noise floor from last periodic calibration */
        s32                     ah_noise_floor;
 
        /* Calibration timestamp */
-       unsigned long           ah_cal_tstamp;
-
-       /* Calibration interval (secs) */
-       u8                      ah_cal_intval;
+       unsigned long           ah_cal_next_full;
+       unsigned long           ah_cal_next_ani;
 
-       /* Software interrupt mask */
-       u8                      ah_swi_mask;
+       /* Calibration mask */
+       u8                      ah_cal_mask;
 
        /*
         * Function pointers
@@ -1163,8 +1178,7 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
 bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
 int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
 enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
-void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
-                                 struct ieee80211_low_level_stats *stats);
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah);
 
 /* EEPROM access functions */
 int ath5k_eeprom_init(struct ath5k_hw *ah);
@@ -1256,7 +1270,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
 int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
                           struct ieee80211_channel *channel);
-void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
 /* Spur mitigation */
 bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
                                  struct ieee80211_channel *channel);
@@ -1308,4 +1321,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
        return retval;
 }
 
+#define AVG_SAMPLES    8
+#define AVG_FACTOR     1000
+
+/**
+ * ath5k_moving_average -  Exponentially weighted moving average
+ * @avg: average structure
+ * @val: current value
+ *
+ * This implementation make use of a struct ath5k_avg_val to prevent rounding
+ * errors.
+ */
+static inline struct ath5k_avg_val
+ath5k_moving_average(const struct ath5k_avg_val avg, const int val)
+{
+       struct ath5k_avg_val new;
+       new.avg_weight = avg.avg_weight  ?
+               (((avg.avg_weight * ((AVG_SAMPLES) - 1)) +
+                       (val * (AVG_FACTOR))) / (AVG_SAMPLES)) :
+               (val * (AVG_FACTOR));
+       new.avg = new.avg_weight / (AVG_FACTOR);
+       return new;
+}
+
 #endif
index f571ad1..e0c244b 100644 (file)
@@ -124,6 +124,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
        ah->ah_software_retry = false;
        ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
+       ah->ah_noise_floor = -95;       /* until first NF calibration is run */
+       sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
 
        /*
         * Find the mac version
index 7ac3a72..93005f1 100644 (file)
@@ -59,8 +59,8 @@
 #include "base.h"
 #include "reg.h"
 #include "debug.h"
+#include "ani.h"
 
-static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
 static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -365,6 +365,7 @@ static void         ath5k_beacon_send(struct ath5k_softc *sc);
 static void    ath5k_beacon_config(struct ath5k_softc *sc);
 static void    ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
 static void    ath5k_tasklet_beacon(unsigned long data);
+static void    ath5k_tasklet_ani(unsigned long data);
 
 static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
 {
@@ -830,6 +831,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
        tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
        tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
+       tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
 
        ret = ath5k_eeprom_read_mac(ah, mac);
        if (ret) {
@@ -1635,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
                                        sc->txqs[i].link);
                        }
        }
-       ieee80211_wake_queues(sc->hw); /* XXX move to callers */
 
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
                if (sc->txqs[i].setup)
@@ -1805,6 +1806,25 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
        }
 }
 
+static void
+ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath_common *common = ath5k_hw_common(ah);
+
+       /* only beacons from our BSSID */
+       if (!ieee80211_is_beacon(mgmt->frame_control) ||
+           memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
+               return;
+
+       ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg,
+                                                     rssi);
+
+       /* in IBSS mode we should keep RSSI statistics per neighbour */
+       /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
+}
+
 /*
  * Compute padding position. skb must contains an IEEE 802.11 frame
  */
@@ -1923,6 +1943,8 @@ ath5k_tasklet_rx(unsigned long data)
                                sc->stats.rxerr_fifo++;
                        if (rs.rs_status & AR5K_RXERR_PHY) {
                                sc->stats.rxerr_phy++;
+                               if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32)
+                                       sc->stats.rxerr_phy_code[rs.rs_phyerr]++;
                                goto next;
                        }
                        if (rs.rs_status & AR5K_RXERR_DECRYPT) {
@@ -2024,6 +2046,8 @@ accept:
 
                ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
 
+               ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi);
+
                /* check beacons in IBSS mode */
                if (sc->opmode == NL80211_IFTYPE_ADHOC)
                        ath5k_check_ibss_tsf(sc, skb, rxs);
@@ -2060,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
        list_for_each_entry_safe(bf, bf0, &txq->q, list) {
                ds = bf->desc;
 
+               /*
+                * It's possible that the hardware can say the buffer is
+                * completed when it hasn't yet loaded the ds_link from
+                * host memory and moved on.  If there are more TX
+                * descriptors in the queue, wait for TXDP to change
+                * before processing this one.
+                */
+               if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr &&
+                   !list_is_last(&bf->list, &txq->q))
+                       break;
+
                ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
                if (unlikely(ret == -EINPROGRESS))
                        break;
@@ -2095,7 +2130,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                info->status.rates[ts.ts_final_idx].count++;
 
                if (unlikely(ts.ts_status)) {
-                       sc->ll_stats.dot11ACKFailureCount++;
+                       sc->stats.ack_fail++;
                        if (ts.ts_status & AR5K_TXERR_FILT) {
                                info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                                sc->stats.txerr_filt++;
@@ -2498,9 +2533,6 @@ ath5k_init(struct ath5k_softc *sc)
         */
        ath5k_stop_locked(sc);
 
-       /* Set PHY calibration interval */
-       ah->ah_cal_intval = ath5k_calinterval;
-
        /*
         * The basic interface to setting the hardware in a good
         * state is ``reset''.  On return the hardware is known to
@@ -2512,7 +2544,8 @@ ath5k_init(struct ath5k_softc *sc)
        sc->curband = &sc->sbands[sc->curchan->band];
        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_SWI;
+               AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
+
        ret = ath5k_reset(sc, NULL);
        if (ret)
                goto done;
@@ -2526,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc)
        for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
                ath5k_hw_reset_key(ah, i);
 
-       /* Set ack to be sent at low bit-rates */
-       ath5k_hw_set_ack_bitrate_high(ah, false);
+       ath5k_hw_set_ack_bitrate_high(ah, true);
        ret = 0;
 done:
        mmiowb();
@@ -2624,12 +2656,33 @@ ath5k_stop_hw(struct ath5k_softc *sc)
        tasklet_kill(&sc->restq);
        tasklet_kill(&sc->calib);
        tasklet_kill(&sc->beacontq);
+       tasklet_kill(&sc->ani_tasklet);
 
        ath5k_rfkill_hw_stop(sc->ah);
 
        return ret;
 }
 
+static void
+ath5k_intr_calibration_poll(struct ath5k_hw *ah)
+{
+       if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) &&
+           !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) {
+               /* run ANI only when full calibration is not active */
+               ah->ah_cal_next_ani = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
+               tasklet_schedule(&ah->ah_sc->ani_tasklet);
+
+       } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
+               ah->ah_cal_next_full = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
+               tasklet_schedule(&ah->ah_sc->calib);
+       }
+       /* we could use SWI to generate enough interrupts to meet our
+        * calibration interval requirements, if necessary:
+        * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
+}
+
 static irqreturn_t
 ath5k_intr(int irq, void *dev_id)
 {
@@ -2653,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id)
                         */
                        tasklet_schedule(&sc->restq);
                } else if (unlikely(status & AR5K_INT_RXORN)) {
-                       tasklet_schedule(&sc->restq);
+                       /*
+                        * Receive buffers are full. Either the bus is busy or
+                        * the CPU is not fast enough to process all received
+                        * frames.
+                        * Older chipsets need a reset to come out of this
+                        * condition, but we treat it as RX for newer chips.
+                        * We don't know exactly which versions need a reset -
+                        * this guess is copied from the HAL.
+                        */
+                       sc->stats.rxorn_intr++;
+                       if (ah->ah_mac_srev < AR5K_SREV_AR5212)
+                               tasklet_schedule(&sc->restq);
+                       else
+                               tasklet_schedule(&sc->rxtq);
                } else {
                        if (status & AR5K_INT_SWBA) {
                                tasklet_hi_schedule(&sc->beacontq);
@@ -2678,15 +2744,10 @@ ath5k_intr(int irq, void *dev_id)
                        if (status & AR5K_INT_BMISS) {
                                /* TODO */
                        }
-                       if (status & AR5K_INT_SWI) {
-                               tasklet_schedule(&sc->calib);
-                       }
                        if (status & AR5K_INT_MIB) {
-                               /*
-                                * These stats are also used for ANI i think
-                                * so how about updating them more often ?
-                                */
-                               ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+                               sc->stats.mib_intr++;
+                               ath5k_hw_update_mib_counters(ah);
+                               ath5k_ani_mib_intr(ah);
                        }
                        if (status & AR5K_INT_GPIO)
                                tasklet_schedule(&sc->rf_kill.toggleq);
@@ -2697,7 +2758,7 @@ ath5k_intr(int irq, void *dev_id)
        if (unlikely(!counter))
                ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
 
-       ath5k_hw_calibration_poll(ah);
+       ath5k_intr_calibration_poll(ah);
 
        return IRQ_HANDLED;
 }
@@ -2721,8 +2782,7 @@ ath5k_tasklet_calibrate(unsigned long data)
        struct ath5k_hw *ah = sc->ah;
 
        /* Only full calibration for now */
-       if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
-               return;
+       ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
 
        /* Stop queues so that calibration
         * doesn't interfere with tx */
@@ -2738,18 +2798,29 @@ ath5k_tasklet_calibrate(unsigned long data)
                 * to load new gain values.
                 */
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-               ath5k_reset_wake(sc);
+               ath5k_reset(sc, sc->curchan);
        }
        if (ath5k_hw_phy_calibrate(ah, sc->curchan))
                ATH5K_ERR(sc, "calibration of channel %u failed\n",
                        ieee80211_frequency_to_channel(
                                sc->curchan->center_freq));
 
-       ah->ah_swi_mask = 0;
-
        /* Wake queues */
        ieee80211_wake_queues(sc->hw);
 
+       ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
+}
+
+
+static void
+ath5k_tasklet_ani(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+       struct ath5k_hw *ah = sc->ah;
+
+       ah->ah_cal_mask |= AR5K_CALIBRATION_ANI;
+       ath5k_ani_calibration(ah);
+       ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI;
 }
 
 
@@ -2852,6 +2923,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
                goto err;
        }
 
+       ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
+
        /*
         * Change channels and update the h/w rate map if we're switching;
         * e.g. 11a to 11b/g.
@@ -3207,12 +3280,14 @@ ath5k_get_stats(struct ieee80211_hw *hw,
                struct ieee80211_low_level_stats *stats)
 {
        struct ath5k_softc *sc = hw->priv;
-       struct ath5k_hw *ah = sc->ah;
 
        /* Force update */
-       ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+       ath5k_hw_update_mib_counters(sc->ah);
 
-       memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
+       stats->dot11ACKFailureCount = sc->stats.ack_fail;
+       stats->dot11RTSFailureCount = sc->stats.rts_fail;
+       stats->dot11RTSSuccessCount = sc->stats.rts_ok;
+       stats->dot11FCSErrorCount = sc->stats.fcs_error;
 
        return 0;
 }
index 33f1d8b..56221bc 100644 (file)
@@ -50,6 +50,7 @@
 
 #include "ath5k.h"
 #include "debug.h"
+#include "ani.h"
 
 #include "../regd.h"
 #include "../ath.h"
@@ -105,14 +106,18 @@ struct ath5k_rfkill {
        struct tasklet_struct toggleq;
 };
 
-/* statistics (only used for debugging now) */
+/* statistics */
 struct ath5k_statistics {
+       /* antenna use */
        unsigned int antenna_rx[5];     /* frames count per antenna RX */
        unsigned int antenna_tx[5];     /* frames count per antenna TX */
+
+       /* frame errors */
        unsigned int rx_all_count;      /* all RX frames, including errors */
        unsigned int tx_all_count;      /* all TX frames, including errors */
        unsigned int rxerr_crc;
        unsigned int rxerr_phy;
+       unsigned int rxerr_phy_code[32];
        unsigned int rxerr_fifo;
        unsigned int rxerr_decrypt;
        unsigned int rxerr_mic;
@@ -121,6 +126,16 @@ struct ath5k_statistics {
        unsigned int txerr_retry;
        unsigned int txerr_fifo;
        unsigned int txerr_filt;
+
+       /* MIB counters */
+       unsigned int ack_fail;
+       unsigned int rts_fail;
+       unsigned int rts_ok;
+       unsigned int fcs_error;
+       unsigned int beacons;
+
+       unsigned int mib_intr;
+       unsigned int rxorn_intr;
 };
 
 #if CHAN_DEBUG
@@ -135,7 +150,6 @@ struct ath5k_softc {
        struct pci_dev          *pdev;          /* for dma mapping */
        void __iomem            *iobase;        /* address of the device */
        struct mutex            lock;           /* dev-level lock */
-       struct ieee80211_low_level_stats ll_stats;
        struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
        struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
        struct ieee80211_channel channels[ATH_CHAN_MAX];
@@ -211,6 +225,9 @@ struct ath5k_softc {
        bool                    enable_beacon;  /* true if beacons are on */
 
        struct ath5k_statistics stats;
+
+       struct ath5k_ani_state  ani_state;
+       struct tasklet_struct   ani_tasklet;    /* ANI calibration */
 };
 
 #define ath5k_hw_hasbssidmask(_ah) \
index e618e71..74f0071 100644 (file)
@@ -109,6 +109,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
        else
                ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
 
+       /* newer hardware has PHY error counters */
+       if (ah->ah_mac_srev >= AR5K_SREV_AR5213A)
+               ah->ah_capabilities.cap_has_phyerr_counters = true;
+       else
+               ah->ah_capabilities.cap_has_phyerr_counters = false;
+
        return 0;
 }
 
index bccd4a7..6fb5c5f 100644 (file)
@@ -69,6 +69,7 @@ module_param_named(debug, ath5k_debug, uint, 0);
 
 #include <linux/seq_file.h>
 #include "reg.h"
+#include "ani.h"
 
 static struct dentry *ath5k_global_debugfs;
 
@@ -307,6 +308,7 @@ static const struct {
        { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
        { ATH5K_DEBUG_DUMPBANDS, "dumpbands",   "dump bands" },
        { ATH5K_DEBUG_TRACE,    "trace",        "trace function calls" },
+       { ATH5K_DEBUG_ANI,      "ani",          "adaptive noise immunity" },
        { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
 };
 
@@ -474,6 +476,7 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
        struct ath5k_statistics *st = &sc->stats;
        char buf[700];
        unsigned int len = 0;
+       int i;
 
        len += snprintf(buf+len, sizeof(buf)-len,
                        "RX\n---------------------\n");
@@ -485,6 +488,13 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
                        st->rxerr_phy,
                        st->rx_all_count > 0 ?
                                st->rxerr_phy*100/st->rx_all_count : 0);
+       for (i = 0; i < 32; i++) {
+               if (st->rxerr_phy_code[i])
+                       len += snprintf(buf+len, sizeof(buf)-len,
+                               " phy_err[%d]\t%d\n",
+                               i, st->rxerr_phy_code[i]);
+       }
+
        len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
                        st->rxerr_fifo,
                        st->rx_all_count > 0 ?
@@ -565,6 +575,160 @@ static const struct file_operations fops_frameerrors = {
 };
 
 
+/* debugfs: ani */
+
+static ssize_t read_file_ani(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_statistics *st = &sc->stats;
+       struct ath5k_ani_state *as = &sc->ani_state;
+
+       char buf[700];
+       unsigned int len = 0;
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "HW has PHY error counters:\t%s\n",
+                       sc->ah->ah_capabilities.cap_has_phyerr_counters ?
+                       "yes" : "no");
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "HW max spur immunity level:\t%d\n",
+                       as->max_spur_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "\nANI state\n--------------------------------------------\n");
+       len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t");
+       switch (as->ani_mode) {
+       case ATH5K_ANI_MODE_OFF:
+               len += snprintf(buf+len, sizeof(buf)-len, "OFF\n");
+               break;
+       case ATH5K_ANI_MODE_MANUAL_LOW:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "MANUAL LOW\n");
+               break;
+       case ATH5K_ANI_MODE_MANUAL_HIGH:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "MANUAL HIGH\n");
+               break;
+       case ATH5K_ANI_MODE_AUTO:
+               len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n");
+               break;
+       default:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "??? (not good)\n");
+               break;
+       }
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "noise immunity level:\t\t%d\n",
+                       as->noise_imm_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "spur immunity level:\t\t%d\n",
+                       as->spur_level);
+       len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n",
+                       as->firstep_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "OFDM weak signal detection:\t%s\n",
+                       as->ofdm_weak_sig ? "on" : "off");
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "CCK weak signal detection:\t%s\n",
+                       as->cck_weak_sig ? "on" : "off");
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "\nMIB INTERRUPTS:\t\t%u\n",
+                       st->mib_intr);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "beacon RSSI average:\t%d\n",
+                       sc->ah->ah_beacon_rssi_avg.avg);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n",
+                       as->pfc_tx,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_tx*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n",
+                       as->pfc_rx,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_rx*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n",
+                       as->pfc_busy,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_busy*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n",
+                       as->pfc_cycles);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "listen time\t\t%d\tlast: %d\n",
+                       as->listen_time, as->last_listen);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
+                       as->ofdm_errors, as->last_ofdm_errors,
+                       as->sum_ofdm_errors);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "CCK errors\t\t%u\tlast: %u\tsum: %u\n",
+                       as->cck_errors, as->last_cck_errors,
+                       as->sum_cck_errors);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1),
+                       ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1)));
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2),
+                       ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2)));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_ani(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       if (strncmp(buf, "sens-low", 8) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_HIGH);
+       } else if (strncmp(buf, "sens-high", 9) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_LOW);
+       } else if (strncmp(buf, "ani-off", 7) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_OFF);
+       } else if (strncmp(buf, "ani-on", 6) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_AUTO);
+       } else if (strncmp(buf, "noise-low", 9) == 0) {
+               ath5k_ani_set_noise_immunity_level(sc->ah, 0);
+       } else if (strncmp(buf, "noise-high", 10) == 0) {
+               ath5k_ani_set_noise_immunity_level(sc->ah,
+                                                  ATH5K_ANI_MAX_NOISE_IMM_LVL);
+       } else if (strncmp(buf, "spur-low", 8) == 0) {
+               ath5k_ani_set_spur_immunity_level(sc->ah, 0);
+       } else if (strncmp(buf, "spur-high", 9) == 0) {
+               ath5k_ani_set_spur_immunity_level(sc->ah,
+                                                 sc->ani_state.max_spur_level);
+       } else if (strncmp(buf, "fir-low", 7) == 0) {
+               ath5k_ani_set_firstep_level(sc->ah, 0);
+       } else if (strncmp(buf, "fir-high", 8) == 0) {
+               ath5k_ani_set_firstep_level(sc->ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
+       } else if (strncmp(buf, "ofdm-off", 8) == 0) {
+               ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, false);
+       } else if (strncmp(buf, "ofdm-on", 7) == 0) {
+               ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, true);
+       } else if (strncmp(buf, "cck-off", 7) == 0) {
+               ath5k_ani_set_cck_weak_signal_detection(sc->ah, false);
+       } else if (strncmp(buf, "cck-on", 6) == 0) {
+               ath5k_ani_set_cck_weak_signal_detection(sc->ah, true);
+       }
+       return count;
+}
+
+static const struct file_operations fops_ani = {
+       .read = read_file_ani,
+       .write = write_file_ani,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
 /* init */
 
 void
@@ -603,6 +767,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
                                S_IWUSR | S_IRUSR,
                                sc->debug.debugfs_phydir, sc,
                                &fops_frameerrors);
+
+       sc->debug.debugfs_ani = debugfs_create_file("ani",
+                               S_IWUSR | S_IRUSR,
+                               sc->debug.debugfs_phydir, sc,
+                               &fops_ani);
 }
 
 void
@@ -620,6 +789,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
        debugfs_remove(sc->debug.debugfs_reset);
        debugfs_remove(sc->debug.debugfs_antenna);
        debugfs_remove(sc->debug.debugfs_frameerrors);
+       debugfs_remove(sc->debug.debugfs_ani);
        debugfs_remove(sc->debug.debugfs_phydir);
 }
 
index da24ff5..ddd5b3a 100644 (file)
@@ -76,6 +76,7 @@ struct ath5k_dbg_info {
        struct dentry           *debugfs_reset;
        struct dentry           *debugfs_antenna;
        struct dentry           *debugfs_frameerrors;
+       struct dentry           *debugfs_ani;
 };
 
 /**
@@ -115,6 +116,7 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_DUMP_TX     = 0x00000200,
        ATH5K_DEBUG_DUMPBANDS   = 0x00000400,
        ATH5K_DEBUG_TRACE       = 0x00001000,
+       ATH5K_DEBUG_ANI         = 0x00002000,
        ATH5K_DEBUG_ANY         = 0xffffffff
 };
 
index 9d920fb..7d7b646 100644 (file)
@@ -645,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
                        rs->rs_status |= AR5K_RXERR_PHY;
                        rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
                                           AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+                       ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
                }
 
                if (rx_status->rx_status_1 &
index 56158c8..64538fb 100644 (file)
@@ -112,15 +112,32 @@ struct ath5k_hw_rx_error {
 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE     0x0000ff00
 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S   8
 
-/* PHY Error codes */
-#define AR5K_DESC_RX_PHY_ERROR_NONE            0x00
-#define AR5K_DESC_RX_PHY_ERROR_TIMING          0x20
-#define AR5K_DESC_RX_PHY_ERROR_PARITY          0x40
-#define AR5K_DESC_RX_PHY_ERROR_RATE            0x60
-#define AR5K_DESC_RX_PHY_ERROR_LENGTH          0x80
-#define AR5K_DESC_RX_PHY_ERROR_64QAM           0xa0
-#define AR5K_DESC_RX_PHY_ERROR_SERVICE         0xc0
-#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR     0xe0
+/**
+ * enum ath5k_phy_error_code - PHY Error codes
+ */
+enum ath5k_phy_error_code {
+       AR5K_RX_PHY_ERROR_UNDERRUN              = 0,    /* Transmit underrun */
+       AR5K_RX_PHY_ERROR_TIMING                = 1,    /* Timing error */
+       AR5K_RX_PHY_ERROR_PARITY                = 2,    /* Illegal parity */
+       AR5K_RX_PHY_ERROR_RATE                  = 3,    /* Illegal rate */
+       AR5K_RX_PHY_ERROR_LENGTH                = 4,    /* Illegal length */
+       AR5K_RX_PHY_ERROR_RADAR                 = 5,    /* Radar detect */
+       AR5K_RX_PHY_ERROR_SERVICE               = 6,    /* Illegal service */
+       AR5K_RX_PHY_ERROR_TOR                   = 7,    /* Transmit override receive */
+       /* these are specific to the 5212 */
+       AR5K_RX_PHY_ERROR_OFDM_TIMING           = 17,
+       AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY    = 18,
+       AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL     = 19,
+       AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL   = 20,
+       AR5K_RX_PHY_ERROR_OFDM_POWER_DROP       = 21,
+       AR5K_RX_PHY_ERROR_OFDM_SERVICE          = 22,
+       AR5K_RX_PHY_ERROR_OFDM_RESTART          = 23,
+       AR5K_RX_PHY_ERROR_CCK_TIMING            = 25,
+       AR5K_RX_PHY_ERROR_CCK_HEADER_CRC        = 26,
+       AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL      = 27,
+       AR5K_RX_PHY_ERROR_CCK_SERVICE           = 30,
+       AR5K_RX_PHY_ERROR_CCK_RESTART           = 31,
+};
 
 /*
  * 5210/5211 hardware 2-word TX control descriptor
index 1b9fcb8..174412f 100644 (file)
@@ -113,39 +113,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
 }
 
 /**
- * ath5k_hw_update - Update mib counters (mac layer statistics)
+ * ath5k_hw_update - Update MIB counters (mac layer statistics)
  *
  * @ah: The &struct ath5k_hw
- * @stats: The &struct ieee80211_low_level_stats we use to track
- * statistics on the driver
  *
- * Reads MIB counters from PCU and updates sw statistics. Must be
- * called after a MIB interrupt.
+ * Reads MIB counters from PCU and updates sw statistics. Is called after a
+ * MIB interrupt, because one of these counters might have reached their maximum
+ * and triggered the MIB interrupt, to let us read and clear the counter.
+ *
+ * Is called in interrupt context!
  */
-void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
-               struct ieee80211_low_level_stats  *stats)
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
 {
-       ATH5K_TRACE(ah->ah_sc);
+       struct ath5k_statistics *stats = &ah->ah_sc->stats;
 
        /* Read-And-Clear */
-       stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
-       stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
-       stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
-       stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
-
-       /* XXX: Should we use this to track beacon count ?
-        * -we read it anyway to clear the register */
-       ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
-
-       /* Reset profile count registers on 5212*/
-       if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
-       }
-
-       /* TODO: Handle ANI stats */
+       stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
+       stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
+       stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
+       stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
+       stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
 }
 
 /**
@@ -167,9 +154,9 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
        else {
                u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
                if (high)
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
-               else
                        AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+               else
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
        }
 }
 
@@ -392,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
  * (ACK etc).
  *
  * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
- * TODO: Init ANI here
  */
 void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
 {
index 3ee74c8..3ce9afb 100644 (file)
@@ -980,7 +980,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
                        return -EINVAL;
 
                data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
-       } else if ((c - (c % 5)) != 2 || c > 5435) {
+       } else if ((c % 5) != 2 || c > 5435) {
                if (!(c % 20) && c >= 5120) {
                        data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
                        data2 = ath5k_hw_bitswap(3, 2);
@@ -993,7 +993,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
                } else
                        return -EINVAL;
        } else {
-               data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+               data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8);
                data2 = ath5k_hw_bitswap(0, 2);
        }
 
@@ -1021,7 +1021,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
                data0 = ath5k_hw_bitswap((c - 2272), 8);
                data2 = 0;
        /* ? 5GHz ? */
-       } else if ((c - (c % 5)) != 2 || c > 5435) {
+       } else if ((c % 5) != 2 || c > 5435) {
                if (!(c % 20) && c < 5120)
                        data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
                else if (!(c % 10))
@@ -1032,7 +1032,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
                        return -EINVAL;
                data2 = ath5k_hw_bitswap(1, 2);
        } else {
-               data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+               data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8);
                data2 = ath5k_hw_bitswap(0, 2);
        }
 
@@ -1103,28 +1103,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
   PHY calibration
 \*****************/
 
-void
-ath5k_hw_calibration_poll(struct ath5k_hw *ah)
-{
-       /* Calibration interval in jiffies */
-       unsigned long cal_intval;
-
-       cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000);
-
-       /* Initialize timestamp if needed */
-       if (!ah->ah_cal_tstamp)
-               ah->ah_cal_tstamp = jiffies;
-
-       /* For now we always do full calibration
-        * Mark software interrupt mask and fire software
-        * interrupt (bit gets auto-cleared) */
-       if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) {
-               ah->ah_cal_tstamp = jiffies;
-               ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
-               AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
-       }
-}
-
 static int sign_extend(int val, const int nbits)
 {
        int order = BIT(nbits-1);
@@ -1411,7 +1389,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
        i_coff = (-iq_corr) / i_coffd;
        i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
 
-       q_coff = (i_pwr / q_coffd) - 128;
+       if (ah->ah_version == AR5K_AR5211)
+               q_coff = (i_pwr / q_coffd) - 64;
+       else
+               q_coff = (i_pwr / q_coffd) - 128;
        q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */
 
        ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
@@ -2580,7 +2561,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
                max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
 
                /* Fill pdadc_out table */
-               while (pdadc_0 < max_idx)
+               while (pdadc_0 < max_idx && pdadc_i < 128)
                        pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
 
                /* Need to extrapolate above this pdgain? */
index 47f0493..55b4ac6 100644 (file)
  * MIB control register
  */
 #define AR5K_MIBC              0x0040                  /* Register Address */
-#define AR5K_MIBC_COW          0x00000001      /* Warn test indicator */
+#define AR5K_MIBC_COW          0x00000001      /* Counter Overflow Warning */
 #define AR5K_MIBC_FMC          0x00000002      /* Freeze MIB Counters  */
-#define AR5K_MIBC_CMC          0x00000004      /* Clean MIB Counters  */
-#define AR5K_MIBC_MCS          0x00000008      /* MIB counter strobe */
+#define AR5K_MIBC_CMC          0x00000004      /* Clear MIB Counters  */
+#define AR5K_MIBC_MCS          0x00000008      /* MIB counter strobe, increment all */
 
 /*
  * Timeout prescale register
 #define AR5K_STA_ID1_DEFAULT_ANTENNA   0x00200000      /* Use default antenna */
 #define AR5K_STA_ID1_DESC_ANTENNA      0x00400000      /* Update antenna from descriptor */
 #define AR5K_STA_ID1_RTS_DEF_ANTENNA   0x00800000      /* Use default antenna for RTS */
-#define AR5K_STA_ID1_ACKCTS_6MB                0x01000000      /* Use 6Mbit/s for ACK/CTS */
-#define AR5K_STA_ID1_BASE_RATE_11B     0x02000000      /* Use 11b base rate for ACK/CTS [5211+] */
+#define AR5K_STA_ID1_ACKCTS_6MB                0x01000000      /* Rate to use for ACK/CTS. 0: highest mandatory rate <= RX rate; 1: 1Mbps in B mode */
+#define AR5K_STA_ID1_BASE_RATE_11B     0x02000000      /* 802.11b base rate. 0: 1, 2, 5.5 and 11Mbps; 1: 1 and 2Mbps. [5211+] */
 #define AR5K_STA_ID1_SELFGEN_DEF_ANT   0x04000000      /* Use def. antenna for self generated frames */
 #define AR5K_STA_ID1_CRYPT_MIC_EN      0x08000000      /* Enable MIC */
 #define AR5K_STA_ID1_KEYSRCH_MODE      0x10000000      /* Look up key when key id != 0 */
                                AR5K_NAV_5210 : AR5K_NAV_5211)
 
 /*
- * RTS success register
+ * MIB counters:
+ *
+ * max value is 0xc000, if this is reached we get a MIB interrupt.
+ * they can be controlled via AR5K_MIBC and are cleared on read.
+ */
+
+/*
+ * RTS success (MIB counter)
  */
 #define AR5K_RTS_OK_5210       0x8090
 #define AR5K_RTS_OK_5211       0x8088
                                AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
 
 /*
- * RTS failure register
+ * RTS failure (MIB counter)
  */
 #define AR5K_RTS_FAIL_5210     0x8094
 #define AR5K_RTS_FAIL_5211     0x808c
                                AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
 
 /*
- * ACK failure register
+ * ACK failure (MIB counter)
  */
 #define AR5K_ACK_FAIL_5210     0x8098
 #define AR5K_ACK_FAIL_5211     0x8090
                                AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
 
 /*
- * FCS failure register
+ * FCS failure (MIB counter)
  */
 #define AR5K_FCS_FAIL_5210     0x809c
 #define AR5K_FCS_FAIL_5211     0x8094
 
 /*
  * Profile count registers
+ *
+ * These registers can be cleared and freezed with ATH5K_MIBC, but they do not
+ * generate a MIB interrupt.
+ * Instead of overflowing, they shift by one bit to the right. All registers
+ * shift together, i.e. when one reaches the max, all shift at the same time by
+ * one bit to the right. This way we should always get consistent values.
  */
 #define AR5K_PROFCNT_TX                        0x80ec  /* Tx count */
 #define AR5K_PROFCNT_RX                        0x80f0  /* Rx count */
-#define AR5K_PROFCNT_RXCLR             0x80f4  /* Clear Rx count */
-#define AR5K_PROFCNT_CYCLE             0x80f8  /* Cycle count (?) */
+#define AR5K_PROFCNT_RXCLR             0x80f4  /* Busy count */
+#define AR5K_PROFCNT_CYCLE             0x80f8  /* Cycle counter */
 
 /*
  * Quiet period control registers
 #define        AR5K_CCK_FIL_CNT                0x8128
 
 /*
- * PHY Error Counters (?)
+ * PHY Error Counters (same masks as AR5K_PHY_ERR_FIL)
  */
 #define        AR5K_PHYERR_CNT1                0x812c
 #define        AR5K_PHYERR_CNT1_MASK           0x8130
 #define        AR5K_PHYERR_CNT2                0x8134
 #define        AR5K_PHYERR_CNT2_MASK           0x8138
 
+/* if the PHY Error Counters reach this maximum, we get MIB interrupts */
+#define ATH5K_PHYERR_CNT_MAX           0x00c00000
+
 /*
  * TSF Threshold register (?)
  */
index ca4994f..85fdd26 100644 (file)
@@ -47,6 +47,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 }
 
 static struct ath_bus_ops ath_ahb_bus_ops  = {
+       .ath_bus_type = ATH_AHB,
        .read_cachesize = ath_ahb_read_cachesize,
        .eeprom_read = ath_ahb_eeprom_read,
 };
index 83c7ea4..bdcd257 100644 (file)
@@ -178,9 +178,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 #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)->tid[(_tidno)])
 
 #define ATH_TX_COMPLETE_POLL_INT       1000
@@ -483,7 +480,6 @@ struct ath_softc {
        bool ps_enabled;
        bool ps_idle;
        unsigned long ps_usecount;
-       enum ath9k_int imask;
 
        struct ath_config config;
        struct ath_rx rx;
index b4a31a4..22375a7 100644 (file)
@@ -524,6 +524,7 @@ static void ath9k_beacon_init(struct ath_softc *sc,
 static void ath_beacon_config_ap(struct ath_softc *sc,
                                 struct ath_beacon_config *conf)
 {
+       struct ath_hw *ah = sc->sc_ah;
        u32 nexttbtt, intval;
 
        /* NB: the beacon interval is kept internally in TU's */
@@ -539,15 +540,15 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
         * prepare beacon frames.
         */
        intval |= ATH9K_BEACON_ENA;
-       sc->imask |= ATH9K_INT_SWBA;
+       ah->imask |= ATH9K_INT_SWBA;
        ath_beaconq_config(sc);
 
        /* Set the computed AP beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Clear the reset TSF flag, so that subsequent beacon updation
           will not reset the HW TSF. */
@@ -566,7 +567,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
 static void ath_beacon_config_sta(struct ath_softc *sc,
                                  struct ath_beacon_config *conf)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_beacon_state bs;
        int dtimperiod, dtimcount, sleepduration;
        int cfpperiod, cfpcount;
@@ -605,7 +607,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
         * Pull nexttbtt forward to reflect the current
         * TSF and calculate dtim+cfp state for the result.
         */
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
 
        num_beacons = tsftu / intval + 1;
@@ -678,17 +680,18 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
 
        /* Set the computed STA beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
-       ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
-       sc->imask |= ATH9K_INT_BMISS;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, 0);
+       ath9k_hw_set_sta_beacon_timers(ah, &bs);
+       ah->imask |= ATH9K_INT_BMISS;
+       ath9k_hw_set_interrupts(ah, ah->imask);
 }
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
                                    struct ath_beacon_config *conf,
                                    struct ieee80211_vif *vif)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        u64 tsf;
        u32 tsftu, intval, nexttbtt;
 
@@ -703,7 +706,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         else if (intval)
                 nexttbtt = roundup(nexttbtt, intval);
 
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
        do {
                nexttbtt += intval;
@@ -719,20 +722,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         * self-linked tx descriptor and let the hardware deal with things.
         */
        intval |= ATH9K_BEACON_ENA;
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-               sc->imask |= ATH9K_INT_SWBA;
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
+               ah->imask |= ATH9K_INT_SWBA;
 
        ath_beaconq_config(sc);
 
        /* Set the computed ADHOC beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* FIXME: Handle properly when vif is NULL */
-       if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+       if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
                ath_beacon_start_adhoc(sc, vif);
 }
 
index d5026e4..064f5b5 100644 (file)
@@ -18,6 +18,7 @@
 
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW       -60
+#define AR9285_CLCAL_REDO_THRESH    1
 
 /* 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
@@ -1091,7 +1092,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
 EXPORT_SYMBOL(ath9k_hw_calibrate);
 
 /* Carrier leakage Calibration fix */
-static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
+static bool ar9285_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
@@ -1132,6 +1133,62 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
        return true;
 }
 
+static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       int i;
+       u_int32_t txgain_max;
+       u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
+       u_int32_t reg_clc_I0, reg_clc_Q0;
+       u_int32_t i0_num = 0;
+       u_int32_t q0_num = 0;
+       u_int32_t total_num = 0;
+       u_int32_t reg_rf2g5_org;
+       bool retv = true;
+
+       if (!(ar9285_cl_cal(ah, chan)))
+               return false;
+
+       txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
+                       AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
+
+       for (i = 0; i < (txgain_max+1); i++) {
+               clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
+                          AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
+               if (!(gain_mask & (1 << clc_gain))) {
+                       gain_mask |= (1 << clc_gain);
+                       clc_num++;
+               }
+       }
+
+       for (i = 0; i < clc_num; i++) {
+               reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+                             & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
+               reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+                             & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
+               if (reg_clc_I0 == 0)
+                       i0_num++;
+
+               if (reg_clc_Q0 == 0)
+                       q0_num++;
+       }
+       total_num = i0_num + q0_num;
+       if (total_num > AR9285_CLCAL_REDO_THRESH) {
+               reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
+               if (AR_SREV_9285E_20(ah)) {
+                       REG_WRITE(ah, AR9285_RF2G5,
+                                 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+                                 AR9285_RF2G5_IC50TX_XE_SET);
+               } else {
+                       REG_WRITE(ah, AR9285_RF2G5,
+                                 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+                                 AR9285_RF2G5_IC50TX_SET);
+               }
+               retv = ar9285_cl_cal(ah, chan);
+               REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
+       }
+       return retv;
+}
+
 bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
index 7902d28..09effde 100644 (file)
@@ -255,7 +255,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
 
        keyix = rx_stats->rs_keyix;
 
-       if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+       if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+           ieee80211_has_protected(fc)) {
                rxs->flag |= RX_FLAG_DECRYPTED;
        } else if (ieee80211_has_protected(fc)
                   && !decrypt_error && skb->len >= hdrlen + 4) {
@@ -303,88 +304,6 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
 
-/*
- * Calculate the RX filter to be set in the HW.
- */
-u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah,
-                          unsigned int rxfilter)
-{
-#define        RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
-
-       u32 rfilt;
-
-       rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
-               | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
-               | ATH9K_RX_FILTER_MCAST;
-
-       /* If not a STA, enable processing of Probe Requests */
-       if (ah->opmode != NL80211_IFTYPE_STATION)
-               rfilt |= ATH9K_RX_FILTER_PROBEREQ;
-
-       /*
-        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
-        * mode interface or when in monitor mode. AP mode does not need this
-        * since it receives all in-BSS frames anyway.
-        */
-       if (((ah->opmode != NL80211_IFTYPE_AP) &&
-            (rxfilter & FIF_PROMISC_IN_BSS)) ||
-           (ah->opmode == NL80211_IFTYPE_MONITOR))
-               rfilt |= ATH9K_RX_FILTER_PROM;
-
-       if (rxfilter & FIF_CONTROL)
-               rfilt |= ATH9K_RX_FILTER_CONTROL;
-
-       if ((ah->opmode == NL80211_IFTYPE_STATION) &&
-           !(rxfilter & FIF_BCN_PRBRESP_PROMISC))
-               rfilt |= ATH9K_RX_FILTER_MYBEACON;
-       else
-               rfilt |= ATH9K_RX_FILTER_BEACON;
-
-       if ((AR_SREV_9280_10_OR_LATER(ah) ||
-           AR_SREV_9285_10_OR_LATER(ah)) &&
-           (ah->opmode == NL80211_IFTYPE_AP) &&
-           (rxfilter & FIF_PSPOLL))
-               rfilt |= ATH9K_RX_FILTER_PSPOLL;
-
-       if (conf_is_ht(&hw->conf))
-               rfilt |= ATH9K_RX_FILTER_COMP_BAR;
-
-       return rfilt;
-
-#undef RX_FILTER_PRESERVE
-}
-EXPORT_SYMBOL(ath9k_cmn_calcrxfilter);
-
-/*
- * Recv initialization for opmode change.
- */
-void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah,
-                          unsigned int rxfilter)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       u32 rfilt, mfilt[2];
-
-       /* configure rx filter */
-       rfilt = ath9k_cmn_calcrxfilter(hw, ah, rxfilter);
-       ath9k_hw_setrxfilter(ah, rfilt);
-
-       /* configure bssid mask */
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
-               ath_hw_setbssidmask(common);
-
-       /* configure operational mode */
-       ath9k_hw_setopmode(ah);
-
-       /* Handle any link-level address change. */
-       ath9k_hw_setmac(ah, common->macaddr);
-
-       /* calculate and install multicast filter */
-       mfilt[0] = mfilt[1] = ~0;
-       ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
-}
-EXPORT_SYMBOL(ath9k_cmn_opmode_init);
-
 static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan,
                                 enum nl80211_channel_type channel_type)
 {
index bbcc57f..72a835d 100644 (file)
@@ -128,10 +128,6 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
 
 int ath9k_cmn_padpos(__le16 frame_control);
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
-u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah,
-                          unsigned int rxfilter);
-void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah,
-                          unsigned int rxfilter);
 void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
                               struct ath9k_channel *ichan);
 struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
index 081e008..9a8e419 100644 (file)
@@ -157,10 +157,10 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n",
+       len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
                        REG_READ_D(ah, AR_OBS_BUS_1));
        len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
+                       "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
 
        ath9k_ps_restore(sc);
 
@@ -557,10 +557,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 }
 
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
-                      struct ath_buf *bf)
+                      struct ath_buf *bf, struct ath_tx_status *ts)
 {
-       struct ath_desc *ds = bf->bf_desc;
-
        if (bf_isampdu(bf)) {
                if (bf_isxretried(bf))
                        TX_STAT_INC(txq->axq_qnum, a_xretries);
@@ -570,17 +568,17 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
                TX_STAT_INC(txq->axq_qnum, completed);
        }
 
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
+       if (ts->ts_status & ATH9K_TXERR_FIFO)
                TX_STAT_INC(txq->axq_qnum, fifo_underrun);
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
+       if (ts->ts_status & ATH9K_TXERR_XTXOP)
                TX_STAT_INC(txq->axq_qnum, xtxop);
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
+       if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
                TX_STAT_INC(txq->axq_qnum, timer_exp);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
+       if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
                TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
+       if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
                TX_STAT_INC(txq->axq_qnum, data_underrun);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
+       if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
                TX_STAT_INC(txq->axq_qnum, delim_underrun);
 }
 
@@ -663,30 +661,29 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
 #undef PHY_ERR
 }
 
-void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf)
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 {
 #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
 #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
 
-       struct ath_desc *ds = bf->bf_desc;
        u32 phyerr;
 
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+       if (rs->rs_status & ATH9K_RXERR_CRC)
                RX_STAT_INC(crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT)
+       if (rs->rs_status & ATH9K_RXERR_DECRYPT)
                RX_STAT_INC(decrypt_crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC)
+       if (rs->rs_status & ATH9K_RXERR_MIC)
                RX_STAT_INC(mic_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE)
+       if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
                RX_STAT_INC(pre_delim_crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST)
+       if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST)
                RX_STAT_INC(post_delim_crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY)
+       if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY)
                RX_STAT_INC(decrypt_busy_err);
 
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
+       if (rs->rs_status & ATH9K_RXERR_PHY) {
                RX_STAT_INC(phy_err);
-               phyerr = ds->ds_rxstat.rs_phyerr & 0x24;
+               phyerr = rs->rs_phyerr & 0x24;
                RX_PHY_ERR_INC(phyerr);
        }
 
index 86780e6..b2af9de 100644 (file)
@@ -167,8 +167,8 @@ void ath9k_debug_remove_root(void);
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_rc(struct ath_softc *sc, int final_rate);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
-                      struct ath_buf *bf);
-void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf);
+                      struct ath_buf *bf, struct ath_tx_status *ts);
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
                            int xretries, int retries, u8 per);
 
@@ -204,12 +204,13 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
 
 static inline void ath_debug_stat_tx(struct ath_softc *sc,
                                     struct ath_txq *txq,
-                                    struct ath_buf *bf)
+                                    struct ath_buf *bf,
+                                    struct ath_tx_status *ts)
 {
 }
 
 static inline void ath_debug_stat_rx(struct ath_softc *sc,
-                                    struct ath_buf *bf)
+                                    struct ath_rx_status *rs)
 {
 }
 
index 68db166..0354fe5 100644 (file)
@@ -43,7 +43,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
        for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
                if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
                        ath_print(common, ATH_DBG_EEPROM,
-                                 "Unable to read eeprom region \n");
+                                 "Unable to read eeprom region\n");
                        return false;
                }
                eep_data++;
index 839d05a..d8ca94c 100644 (file)
@@ -44,7 +44,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
                if (!ath9k_hw_nvram_read(common,
                                         addr + eep_start_loc, eep_data)) {
                        ath_print(common, ATH_DBG_EEPROM,
-                                 "Unable to read eeprom region \n");
+                                 "Unable to read eeprom region\n");
                        return false;
                }
                eep_data++;
index deab8be..0ee75e7 100644 (file)
@@ -283,22 +283,17 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
                                  u32 timer_next,
                                  u32 timer_period)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
        ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
 
-       if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
+       if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
                ath9k_hw_set_interrupts(ah, 0);
-               sc->imask |= ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah, sc->imask);
+               ah->imask |= ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, ah->imask);
        }
 }
 
 static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
 {
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
        struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
 
        ath9k_hw_gen_timer_stop(ah, timer);
@@ -306,8 +301,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
        /* if no timer is enabled, turn off interrupt mask */
        if (timer_table->timer_mask.val == 0) {
                ath9k_hw_set_interrupts(ah, 0);
-               sc->imask &= ~ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah, sc->imask);
+               ah->imask &= ~ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, ah->imask);
        }
 }
 
@@ -364,7 +359,7 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
-                 "no stomp timer running \n");
+                 "no stomp timer running\n");
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
index fc4f6e8..fe994e2 100644 (file)
@@ -21,6 +21,7 @@
 
 static struct usb_device_id ath9k_hif_usb_ids[] = {
        ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"),
+       ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"),
        { },
 };
 
@@ -31,27 +32,15 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev);
 static void hif_usb_regout_cb(struct urb *urb)
 {
        struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
-       struct hif_device_usb *hif_dev = cmd->hif_dev;
-
-       if (!hif_dev) {
-               usb_free_urb(urb);
-               if (cmd) {
-                       if (cmd->skb)
-                               dev_kfree_skb_any(cmd->skb);
-                       kfree(cmd);
-               }
-               return;
-       }
 
        switch (urb->status) {
        case 0:
                break;
        case -ENOENT:
        case -ECONNRESET:
-               break;
        case -ENODEV:
        case -ESHUTDOWN:
-               return;
+               goto free;
        default:
                break;
        }
@@ -60,8 +49,12 @@ static void hif_usb_regout_cb(struct urb *urb)
                ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
                                          cmd->skb, 1);
                kfree(cmd);
-               usb_free_urb(urb);
        }
+
+       return;
+free:
+       kfree_skb(cmd->skb);
+       kfree(cmd);
 }
 
 static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
@@ -89,11 +82,13 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
                         skb->data, skb->len,
                         hif_usb_regout_cb, cmd, 1);
 
+       usb_anchor_urb(urb, &hif_dev->regout_submitted);
        ret = usb_submit_urb(urb, GFP_KERNEL);
        if (ret) {
-               usb_free_urb(urb);
+               usb_unanchor_urb(urb);
                kfree(cmd);
        }
+       usb_free_urb(urb);
 
        return ret;
 }
@@ -154,6 +149,13 @@ static void hif_usb_tx_cb(struct urb *urb)
        }
 }
 
+static inline void ath9k_skb_queue_purge(struct sk_buff_head *list)
+{
+       struct sk_buff *skb;
+       while ((skb = __skb_dequeue(list)) != NULL)
+               dev_kfree_skb_any(skb);
+}
+
 /* TX lock has to be taken */
 static int __hif_usb_tx(struct hif_device_usb *hif_dev)
 {
@@ -212,7 +214,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
        ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
        if (ret) {
                tx_buf->len = tx_buf->offset = 0;
-               __skb_queue_purge(&tx_buf->skb_queue);
+               ath9k_skb_queue_purge(&tx_buf->skb_queue);
                __skb_queue_head_init(&tx_buf->skb_queue);
                list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
                hif_dev->tx.tx_buf_cnt++;
@@ -279,7 +281,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
        unsigned long flags;
 
        spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
-       __skb_queue_purge(&hif_dev->tx.tx_skb_queue);
+       ath9k_skb_queue_purge(&hif_dev->tx.tx_skb_queue);
        hif_dev->tx.tx_skb_cnt = 0;
        hif_dev->tx.flags |= HIF_USB_TX_STOP;
        spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@@ -299,6 +301,8 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
                ret = hif_usb_send_regout(hif_dev, skb);
                break;
        default:
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Invalid TX pipe: %d\n", pipe_id);
                ret = -EINVAL;
                break;
        }
@@ -321,12 +325,14 @@ static struct ath9k_htc_hif hif_usb = {
 static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                                    struct sk_buff *skb)
 {
-       struct sk_buff *nskb, *skb_pool[8];
+       struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
        int index = 0, i = 0, chk_idx, len = skb->len;
        int rx_remain_len = 0, rx_pkt_len = 0;
        u16 pkt_len, pkt_tag, pool_index = 0;
        u8 *ptr;
 
+       spin_lock(&hif_dev->rx_lock);
+
        rx_remain_len = hif_dev->rx_remain_len;
        rx_pkt_len = hif_dev->rx_transfer_len;
 
@@ -353,6 +359,8 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                }
        }
 
+       spin_unlock(&hif_dev->rx_lock);
+
        while (index < len) {
                ptr = (u8 *) skb->data;
 
@@ -370,6 +378,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                        index = index + 4 + pkt_len + pad_len;
 
                        if (index > MAX_RX_BUF_SIZE) {
+                               spin_lock(&hif_dev->rx_lock);
                                hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
                                hif_dev->rx_transfer_len =
                                        MAX_RX_BUF_SIZE - chk_idx - 4;
@@ -381,6 +390,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                                        dev_err(&hif_dev->udev->dev,
                                        "ath9k_htc: RX memory allocation"
                                        " error\n");
+                                       spin_unlock(&hif_dev->rx_lock);
                                        goto err;
                                }
                                skb_reserve(nskb, 32);
@@ -391,6 +401,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
 
                                /* Record the buffer pointer */
                                hif_dev->remain_skb = nskb;
+                               spin_unlock(&hif_dev->rx_lock);
                        } else {
                                nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
                                if (!nskb) {
@@ -408,14 +419,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                        }
                } else {
                        RX_STAT_INC(skb_dropped);
-                       dev_kfree_skb_any(skb);
                        return;
                }
        }
 
 err:
-       dev_kfree_skb_any(skb);
-
        for (i = 0; i < pool_index; i++) {
                ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
                                 skb_pool[i]->len, USB_WLAN_RX_PIPE);
@@ -426,11 +434,13 @@ err:
 static void ath9k_hif_usb_rx_cb(struct urb *urb)
 {
        struct sk_buff *skb = (struct sk_buff *) urb->context;
-       struct sk_buff *nskb;
        struct hif_device_usb *hif_dev = (struct hif_device_usb *)
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
 
+       if (!skb)
+               return;
+
        if (!hif_dev)
                goto free;
 
@@ -448,38 +458,23 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 
        if (likely(urb->actual_length != 0)) {
                skb_put(skb, urb->actual_length);
-
-               nskb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_ATOMIC);
-               if (!nskb)
-                       goto resubmit;
-
-               usb_fill_bulk_urb(urb, hif_dev->udev,
-                                 usb_rcvbulkpipe(hif_dev->udev,
-                                                 USB_WLAN_RX_PIPE),
-                                 nskb->data, MAX_RX_BUF_SIZE,
-                                 ath9k_hif_usb_rx_cb, nskb);
-
-               ret = usb_submit_urb(urb, GFP_ATOMIC);
-               if (ret) {
-                       dev_kfree_skb_any(nskb);
-                       goto free;
-               }
-
                ath9k_hif_usb_rx_stream(hif_dev, skb);
-               return;
        }
 
 resubmit:
        skb_reset_tail_pointer(skb);
        skb_trim(skb, 0);
 
+       usb_anchor_urb(urb, &hif_dev->rx_submitted);
        ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret)
+       if (ret) {
+               usb_unanchor_urb(urb);
                goto free;
+       }
 
        return;
 free:
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
 }
 
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
@@ -490,6 +485,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
 
+       if (!skb)
+               return;
+
        if (!hif_dev)
                goto free;
 
@@ -508,7 +506,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
        if (likely(urb->actual_length != 0)) {
                skb_put(skb, urb->actual_length);
 
-               nskb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
+               nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
                if (!nskb)
                        goto resubmit;
 
@@ -519,7 +517,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 
                ret = usb_submit_urb(urb, GFP_ATOMIC);
                if (ret) {
-                       dev_kfree_skb_any(nskb);
+                       kfree_skb(nskb);
                        goto free;
                }
 
@@ -539,7 +537,8 @@ resubmit:
 
        return;
 free:
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
+       urb->context = NULL;
 }
 
 static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -609,78 +608,66 @@ err:
        return -ENOMEM;
 }
 
-static void ath9k_hif_usb_dealloc_rx_skbs(struct hif_device_usb *hif_dev)
-{
-       int i;
-
-       for (i = 0; i < MAX_RX_URB_NUM; i++) {
-               if (hif_dev->wlan_rx_data_urb[i]) {
-                       if (hif_dev->wlan_rx_data_urb[i]->transfer_buffer)
-                               dev_kfree_skb_any((void *)
-                                         hif_dev->wlan_rx_data_urb[i]->context);
-               }
-       }
-}
-
 static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
-       int i;
-
-       for (i = 0; i < MAX_RX_URB_NUM; i++) {
-               if (hif_dev->wlan_rx_data_urb[i]) {
-                       usb_kill_urb(hif_dev->wlan_rx_data_urb[i]);
-                       usb_free_urb(hif_dev->wlan_rx_data_urb[i]);
-                       hif_dev->wlan_rx_data_urb[i] = NULL;
-               }
-       }
-}
-
-static int ath9k_hif_usb_prep_rx_urb(struct hif_device_usb *hif_dev,
-                                    struct urb *urb)
-{
-       struct sk_buff *skb;
-
-       skb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
-
-       usb_fill_bulk_urb(urb, hif_dev->udev,
-                         usb_rcvbulkpipe(hif_dev->udev, USB_WLAN_RX_PIPE),
-                         skb->data, MAX_RX_BUF_SIZE,
-                         ath9k_hif_usb_rx_cb, skb);
-       return 0;
+       usb_kill_anchored_urbs(&hif_dev->rx_submitted);
 }
 
 static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
+       struct urb *urb = NULL;
+       struct sk_buff *skb = NULL;
        int i, ret;
 
+       init_usb_anchor(&hif_dev->rx_submitted);
+       spin_lock_init(&hif_dev->rx_lock);
+
        for (i = 0; i < MAX_RX_URB_NUM; i++) {
 
                /* Allocate URB */
-               hif_dev->wlan_rx_data_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-               if (hif_dev->wlan_rx_data_urb[i] == NULL) {
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (urb == NULL) {
                        ret = -ENOMEM;
-                       goto err_rx_urb;
+                       goto err_urb;
                }
 
                /* Allocate buffer */
-               ret = ath9k_hif_usb_prep_rx_urb(hif_dev,
-                                               hif_dev->wlan_rx_data_urb[i]);
-               if (ret)
-                       goto err_rx_urb;
+               skb = alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
+               if (!skb) {
+                       ret = -ENOMEM;
+                       goto err_skb;
+               }
+
+               usb_fill_bulk_urb(urb, hif_dev->udev,
+                                 usb_rcvbulkpipe(hif_dev->udev,
+                                                 USB_WLAN_RX_PIPE),
+                                 skb->data, MAX_RX_BUF_SIZE,
+                                 ath9k_hif_usb_rx_cb, skb);
+
+               /* Anchor URB */
+               usb_anchor_urb(urb, &hif_dev->rx_submitted);
 
                /* Submit URB */
-               ret = usb_submit_urb(hif_dev->wlan_rx_data_urb[i], GFP_KERNEL);
-               if (ret)
-                       goto err_rx_urb;
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       usb_unanchor_urb(urb);
+                       goto err_submit;
+               }
 
+               /*
+                * Drop reference count.
+                * This ensures that the URB is freed when killing them.
+                */
+               usb_free_urb(urb);
        }
 
        return 0;
 
-err_rx_urb:
-       ath9k_hif_usb_dealloc_rx_skbs(hif_dev);
+err_submit:
+       kfree_skb(skb);
+err_skb:
+       usb_free_urb(urb);
+err_urb:
        ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
        return ret;
 }
@@ -689,6 +676,8 @@ static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
 {
        if (hif_dev->reg_in_urb) {
                usb_kill_urb(hif_dev->reg_in_urb);
+               if (hif_dev->reg_in_urb->context)
+                       kfree_skb((void *)hif_dev->reg_in_urb->context);
                usb_free_urb(hif_dev->reg_in_urb);
                hif_dev->reg_in_urb = NULL;
        }
@@ -702,7 +691,7 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
        if (hif_dev->reg_in_urb == NULL)
                return -ENOMEM;
 
-       skb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
+       skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
        if (!skb)
                goto err;
 
@@ -712,12 +701,10 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
                         ath9k_hif_usb_reg_in_cb, skb, 1);
 
        if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
-               goto err_skb;
+               goto err;
 
        return 0;
 
-err_skb:
-       dev_kfree_skb_any(skb);
 err:
        ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
        return -ENOMEM;
@@ -725,6 +712,9 @@ err:
 
 static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
 {
+       /* Register Write */
+       init_usb_anchor(&hif_dev->regout_submitted);
+
        /* TX */
        if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0)
                goto err;
@@ -733,7 +723,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
        if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0)
                goto err;
 
-       /* Register Read/Write */
+       /* Register Read */
        if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
                goto err;
 
@@ -830,6 +820,7 @@ err_fw_req:
 
 static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
 {
+       usb_kill_anchored_urbs(&hif_dev->regout_submitted);
        ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
        ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
        ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
index 7cc3762..7d49a8a 100644 (file)
@@ -34,6 +34,7 @@
 
 #define MAX_RX_URB_NUM  8
 #define MAX_RX_BUF_SIZE 16384
+#define MAX_PKT_NUM_IN_TRANSFER 10
 
 #define MAX_REG_OUT_URB_NUM  1
 #define MAX_REG_OUT_BUF_NUM  8
@@ -85,18 +86,17 @@ struct hif_device_usb {
        struct usb_interface *interface;
        const struct firmware *firmware;
        struct htc_target *htc_handle;
-       u8 flags;
-
        struct hif_usb_tx tx;
-
-       struct urb *wlan_rx_data_urb[MAX_RX_URB_NUM];
        struct urb *reg_in_urb;
-
+       struct usb_anchor regout_submitted;
+       struct usb_anchor rx_submitted;
        struct sk_buff *remain_skb;
        int rx_remain_len;
        int rx_pkt_len;
        int rx_transfer_len;
        int rx_pad_len;
+       spinlock_t rx_lock;
+       u8 flags; /* HIF_USB_* */
 };
 
 int ath9k_hif_usb_init(void);
index 7770649..78213fc 100644 (file)
@@ -309,6 +309,14 @@ struct ath_led {
        int brightness;
 };
 
+struct htc_beacon_config {
+       u16 beacon_interval;
+       u16 listen_interval;
+       u16 dtim_period;
+       u16 bmiss_timeout;
+       u8 dtim_count;
+};
+
 #define OP_INVALID        BIT(0)
 #define OP_SCANNING       BIT(1)
 #define OP_FULL_RESET     BIT(2)
@@ -349,7 +357,11 @@ struct ath9k_htc_priv {
        struct sk_buff *beacon;
        spinlock_t beacon_lock;
 
+       bool tx_queues_stop;
+       spinlock_t tx_lock;
+
        struct ieee80211_vif *vif;
+       struct htc_beacon_config cur_beacon_conf;
        unsigned int rxfilter;
        struct tasklet_struct wmi_tasklet;
        struct tasklet_struct rx_tasklet;
@@ -360,6 +372,11 @@ struct ath9k_htc_priv {
        struct ath9k_htc_aggr_work aggr_work;
        struct delayed_work ath9k_aggr_work;
        struct delayed_work ath9k_ani_work;
+       struct work_struct ps_work;
+
+       struct mutex htc_pm_lock;
+       unsigned long ps_usecount;
+       bool ps_enabled;
 
        struct ath_led radio_led;
        struct ath_led assoc_led;
@@ -386,8 +403,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 }
 
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_bss_conf *bss_conf);
+                            struct ieee80211_vif *vif);
 void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
 void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv,
                             struct ieee80211_vif *vif);
@@ -415,6 +431,11 @@ int ath9k_rx_init(struct ath9k_htc_priv *priv);
 void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
 void ath9k_host_rx_init(struct ath9k_htc_priv *priv);
 void ath9k_rx_tasklet(unsigned long data);
+u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv);
+
+void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv);
+void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
+void ath9k_ps_work(struct work_struct *work);
 
 void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
 void ath9k_init_leds(struct ath9k_htc_priv *priv);
index 25f5b53..5e21f4d 100644 (file)
@@ -19,7 +19,7 @@
 #define FUDGE 2
 
 static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
-                                       struct ieee80211_bss_conf *bss_conf)
+                                       struct htc_beacon_config *bss_conf)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ath9k_beacon_state bs;
@@ -34,8 +34,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 
        memset(&bs, 0, sizeof(bs));
 
-       intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD;
-       bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_int);
+       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
 
        /*
         * Setup dtim and cfp parameters according to
@@ -138,7 +138,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 }
 
 static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
-                                         struct ieee80211_bss_conf *bss_conf)
+                                         struct htc_beacon_config *bss_conf)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
        enum ath9k_int imask = 0;
@@ -146,7 +146,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
        int ret;
        u8 cmd_rsp;
 
-       intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD;
+       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
        nexttbtt = intval;
        intval |= ATH9K_BEACON_ENA;
        if (priv->op_flags & OP_ENABLE_BEACON)
@@ -154,7 +154,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 
        ath_print(common, ATH_DBG_BEACON,
                  "IBSS Beacon config, intval: %d, imask: 0x%x\n",
-                 bss_conf->beacon_int, imask);
+                 bss_conf->beacon_interval, imask);
 
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
@@ -239,18 +239,35 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
        spin_unlock_bh(&priv->beacon_lock);
 }
 
+
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_bss_conf *bss_conf)
+                            struct ieee80211_vif *vif)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
-
-       switch (vif->type) {
+       enum nl80211_iftype iftype;
+       struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+
+       if (vif) {
+               struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+               iftype = vif->type;
+               cur_conf->beacon_interval = bss_conf->beacon_int;
+               cur_conf->dtim_period = bss_conf->dtim_period;
+               cur_conf->listen_interval = 1;
+               cur_conf->dtim_count = 1;
+               cur_conf->bmiss_timeout =
+                       ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+       } else
+               iftype = priv->ah->opmode;
+
+       if (cur_conf->beacon_interval == 0)
+               cur_conf->beacon_interval = 100;
+
+       switch (iftype) {
        case NL80211_IFTYPE_STATION:
-               ath9k_htc_beacon_config_sta(priv, bss_conf);
+               ath9k_htc_beacon_config_sta(priv, cur_conf);
                break;
        case NL80211_IFTYPE_ADHOC:
-               ath9k_htc_beacon_config_adhoc(priv, bss_conf);
+               ath9k_htc_beacon_config_adhoc(priv, cur_conf);
                break;
        default:
                ath_print(common, ATH_DBG_CONFIG,
index 10c8760..aed5357 100644 (file)
@@ -287,6 +287,7 @@ static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 }
 
 static const struct ath_bus_ops ath9k_usb_bus_ops = {
+       .ath_bus_type = ATH_USB,
        .read_cachesize = ath_usb_read_cachesize,
        .eeprom_read = ath_usb_eeprom_read,
 };
@@ -421,6 +422,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
                memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
 
        priv->op_flags |= OP_TXAGGR;
+       priv->ah->opmode = NL80211_IFTYPE_STATION;
 }
 
 static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
@@ -449,8 +451,10 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
 
        spin_lock_init(&priv->wmi->wmi_lock);
        spin_lock_init(&priv->beacon_lock);
+       spin_lock_init(&priv->tx_lock);
        mutex_init(&priv->mutex);
        mutex_init(&priv->aggr_work.mutex);
+       mutex_init(&priv->htc_pm_lock);
        tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
                     (unsigned long)priv);
        tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
@@ -458,6 +462,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
        tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
        INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work);
        INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
+       INIT_WORK(&priv->ps_work, ath9k_ps_work);
 
        /*
         * Cache line size is used to size and align various
@@ -511,12 +516,17 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_AMPDU_AGGREGATION |
                IEEE80211_HW_SPECTRUM_MGMT |
-               IEEE80211_HW_HAS_RATE_CONTROL;
+               IEEE80211_HW_HAS_RATE_CONTROL |
+               IEEE80211_HW_RX_INCLUDES_FCS |
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_PS_NULLFUNC_STACK;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
 
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
        hw->queues = 4;
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
index 20a2c13..eb7722b 100644 (file)
@@ -65,6 +65,56 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
        return mode;
 }
 
+static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+                              enum ath9k_power_mode mode)
+{
+       bool ret;
+
+       mutex_lock(&priv->htc_pm_lock);
+       ret = ath9k_hw_setpower(priv->ah, mode);
+       mutex_unlock(&priv->htc_pm_lock);
+
+       return ret;
+}
+
+void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
+{
+       mutex_lock(&priv->htc_pm_lock);
+       if (++priv->ps_usecount != 1)
+               goto unlock;
+       ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
+
+unlock:
+       mutex_unlock(&priv->htc_pm_lock);
+}
+
+void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
+{
+       mutex_lock(&priv->htc_pm_lock);
+       if (--priv->ps_usecount != 0)
+               goto unlock;
+
+       if (priv->ps_enabled)
+               ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+unlock:
+       mutex_unlock(&priv->htc_pm_lock);
+}
+
+void ath9k_ps_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv =
+               container_of(work, struct ath9k_htc_priv,
+                            ps_work);
+       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+
+       /* The chip wakes up after receiving the first beacon
+          while network sleep is enabled. For the driver to
+          be in sync with the hw, set the chip to awake and
+          only then set it to sleep.
+        */
+       ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
+}
+
 static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
                                 struct ieee80211_hw *hw,
                                 struct ath9k_channel *hchan)
@@ -87,7 +137,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 
        /* Fiddle around with fastcc later on, for now just use full reset */
        fastcc = false;
-
+       ath9k_htc_ps_wakeup(priv);
        htc_stop(priv->htc);
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
@@ -103,6 +153,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
                ath_print(common, ATH_DBG_FATAL,
                          "Unable to reset channel (%u Mhz) "
                          "reset status %d\n", channel->center_freq, ret);
+               ath9k_htc_ps_restore(priv);
                goto err;
        }
 
@@ -128,6 +179,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 
        priv->op_flags &= ~OP_FULL_RESET;
 err:
+       ath9k_htc_ps_restore(priv);
        return ret;
 }
 
@@ -412,32 +464,31 @@ static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
        if (tid > ATH9K_HTC_MAX_TID)
                return -EINVAL;
 
+       memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
+
        rcu_read_lock();
+
+       /* Check if we are able to retrieve the station */
        sta = ieee80211_find_sta(vif, sta_addr);
-       if (sta) {
-               ista = (struct ath9k_htc_sta *) sta->drv_priv;
-       } else {
+       if (!sta) {
                rcu_read_unlock();
                return -EINVAL;
        }
 
-       if (!ista) {
-               rcu_read_unlock();
-               return -EINVAL;
-       }
+       ista = (struct ath9k_htc_sta *) sta->drv_priv;
 
-       memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
+       if (oper)
+               ista->tid_state[tid] = AGGR_START;
+       else
+               ista->tid_state[tid] = AGGR_STOP;
 
        aggr.sta_index = ista->index;
+
        rcu_read_unlock();
+
        aggr.tidno = tid;
        aggr.aggr_enable = oper;
 
-       if (oper)
-               ista->tid_state[tid] = AGGR_START;
-       else
-               ista->tid_state[tid] = AGGR_STOP;
-
        WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
        if (ret)
                ath_print(common, ATH_DBG_CONFIG,
@@ -694,6 +745,10 @@ void ath9k_ani_work(struct work_struct *work)
 
        short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
 
+       /* Only calibrate if awake */
+       if (ah->power_mode != ATH9K_PM_AWAKE)
+               goto set_timer;
+
        /* Long calibration runs independently of short calibration. */
        if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
                longcal = true;
@@ -728,6 +783,9 @@ void ath9k_ani_work(struct work_struct *work)
 
        /* Skip all processing if there's nothing to do. */
        if (longcal || shortcal || aniflag) {
+
+               ath9k_htc_ps_wakeup(priv);
+
                /* Call ANI routine if necessary */
                if (aniflag)
                        ath9k_hw_ani_monitor(ah, ah->curchan);
@@ -749,8 +807,11 @@ void ath9k_ani_work(struct work_struct *work)
                                  ah->curchan->channelFlags,
                                  common->ani.noise_floor);
                }
+
+               ath9k_htc_ps_restore(priv);
        }
 
+set_timer:
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -995,7 +1056,7 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
        struct ath9k_htc_priv *priv = hw->priv;
-       int padpos, padsize;
+       int padpos, padsize, ret;
 
        hdr = (struct ieee80211_hdr *) skb->data;
 
@@ -1009,8 +1070,19 @@ static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                memmove(skb->data, skb->data + padsize, padpos);
        }
 
-       if (ath9k_htc_tx_start(priv, skb) != 0) {
-               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed");
+       ret = ath9k_htc_tx_start(priv, skb);
+       if (ret != 0) {
+               if (ret == -ENOMEM) {
+                       ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                                 "Stopping TX queues\n");
+                       ieee80211_stop_queues(hw);
+                       spin_lock_bh(&priv->tx_lock);
+                       priv->tx_queues_stop = true;
+                       spin_unlock_bh(&priv->tx_lock);
+               } else {
+                       ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                                 "Tx failed");
+               }
                goto fail_tx;
        }
 
@@ -1075,6 +1147,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
        priv->op_flags &= ~OP_INVALID;
        htc_start(priv->htc);
 
+       spin_lock_bh(&priv->tx_lock);
+       priv->tx_queues_stop = false;
+       spin_unlock_bh(&priv->tx_lock);
+
+       ieee80211_wake_queues(hw);
+
 mutex_unlock:
        mutex_unlock(&priv->mutex);
        return ret;
@@ -1096,6 +1174,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
                return;
        }
 
+       ath9k_htc_ps_wakeup(priv);
        htc_stop(priv->htc);
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
@@ -1103,8 +1182,10 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        ath9k_hw_phy_disable(ah);
        ath9k_hw_disable(ah);
        ath9k_hw_configpcipowersave(ah, 1, 1);
-       ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+       ath9k_htc_ps_restore(priv);
+       ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
 
+       cancel_work_sync(&priv->ps_work);
        cancel_delayed_work_sync(&priv->ath9k_ani_work);
        cancel_delayed_work_sync(&priv->ath9k_aggr_work);
        cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
@@ -1145,6 +1226,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
+       ath9k_htc_ps_wakeup(priv);
        memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
        memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
 
@@ -1191,6 +1273,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
 
        priv->vif = vif;
 out:
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
        return ret;
 }
@@ -1259,6 +1342,16 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                }
 
        }
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               if (conf->flags & IEEE80211_CONF_PS) {
+                       ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
+                       priv->ps_enabled = true;
+               } else {
+                       priv->ps_enabled = false;
+                       cancel_work_sync(&priv->ps_work);
+                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+               }
+       }
 
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
@@ -1295,16 +1388,18 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
+       ath9k_htc_ps_wakeup(priv);
        changed_flags &= SUPPORTED_FILTERS;
        *total_flags &= SUPPORTED_FILTERS;
 
        priv->rxfilter = *total_flags;
-       rfilt = ath9k_cmn_calcrxfilter(hw, priv->ah, priv->rxfilter);
+       rfilt = ath9k_htc_calcrxfilter(priv);
        ath9k_hw_setrxfilter(priv->ah, rfilt);
 
        ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
                  "Set HW RX filter: 0x%x\n", rfilt);
 
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
 }
 
@@ -1382,6 +1477,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
        ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
+       ath9k_htc_ps_wakeup(priv);
 
        switch (cmd) {
        case SET_KEY:
@@ -1404,6 +1500,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
                ret = -EINVAL;
        }
 
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
 
        return ret;
@@ -1419,6 +1516,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        struct ath_common *common = ath9k_hw_common(ah);
 
        mutex_lock(&priv->mutex);
+       ath9k_htc_ps_wakeup(priv);
 
        if (changed & BSS_CHANGED_ASSOC) {
                common->curaid = bss_conf->assoc ?
@@ -1431,6 +1529,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                        ath_start_ani(priv);
                } else {
                        priv->op_flags &= ~OP_ASSOCIATED;
+                       cancel_work_sync(&priv->ps_work);
                        cancel_delayed_work_sync(&priv->ath9k_ani_work);
                }
        }
@@ -1450,7 +1549,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
            ((changed & BSS_CHANGED_BEACON_ENABLED) &&
            bss_conf->enable_beacon)) {
                priv->op_flags |= OP_ENABLE_BEACON;
-               ath9k_htc_beacon_config(priv, vif, bss_conf);
+               ath9k_htc_beacon_config(priv, vif);
        }
 
        if (changed & BSS_CHANGED_BEACON)
@@ -1459,7 +1558,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
            !bss_conf->enable_beacon) {
                priv->op_flags &= ~OP_ENABLE_BEACON;
-               ath9k_htc_beacon_config(priv, vif, bss_conf);
+               ath9k_htc_beacon_config(priv, vif);
        }
 
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -1490,6 +1589,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                ath9k_hw_init_global_settings(ah);
        }
 
+       ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
 }
 
@@ -1518,9 +1618,11 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
+       ath9k_htc_ps_wakeup(priv);
        mutex_lock(&priv->mutex);
        ath9k_hw_reset_tsf(priv->ah);
        mutex_unlock(&priv->mutex);
+       ath9k_htc_ps_restore(priv);
 }
 
 static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
@@ -1569,6 +1671,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
        spin_lock_bh(&priv->beacon_lock);
        priv->op_flags |= OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
+       cancel_work_sync(&priv->ps_work);
        cancel_delayed_work_sync(&priv->ath9k_ani_work);
        mutex_unlock(&priv->mutex);
 }
@@ -1577,13 +1680,17 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
+       ath9k_htc_ps_wakeup(priv);
        mutex_lock(&priv->mutex);
        spin_lock_bh(&priv->beacon_lock);
        priv->op_flags &= ~OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
        priv->op_flags |= OP_FULL_RESET;
+       if (priv->op_flags & OP_ASSOCIATED)
+               ath9k_htc_beacon_config(priv, NULL);
        ath_start_ani(priv);
        mutex_unlock(&priv->mutex);
+       ath9k_htc_ps_restore(priv);
 }
 
 static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
index ac66cf0..0a7cb30 100644 (file)
@@ -188,10 +188,20 @@ void ath9k_tx_tasklet(unsigned long data)
                hdr = (struct ieee80211_hdr *) skb->data;
                fc = hdr->frame_control;
                tx_info = IEEE80211_SKB_CB(skb);
-               sta = tx_info->control.sta;
+
+               memset(&tx_info->status, 0, sizeof(tx_info->status));
 
                rcu_read_lock();
 
+               sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+               if (!sta) {
+                       rcu_read_unlock();
+                       ieee80211_tx_status(priv->hw, skb);
+                       continue;
+               }
+
+               /* Check if we need to start aggregation */
+
                if (sta && conf_is_ht(&priv->hw->conf) &&
                    (priv->op_flags & OP_TXAGGR)
                    && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
@@ -213,9 +223,21 @@ void ath9k_tx_tasklet(unsigned long data)
 
                rcu_read_unlock();
 
-               memset(&tx_info->status, 0, sizeof(tx_info->status));
+               /* Send status to mac80211 */
                ieee80211_tx_status(priv->hw, skb);
        }
+
+       /* Wake TX queues if needed */
+       spin_lock_bh(&priv->tx_lock);
+       if (priv->tx_queues_stop) {
+               priv->tx_queues_stop = false;
+               spin_unlock_bh(&priv->tx_lock);
+               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                         "Waking up TX queues\n");
+               ieee80211_wake_queues(priv->hw);
+               return;
+       }
+       spin_unlock_bh(&priv->tx_lock);
 }
 
 void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
@@ -290,10 +312,84 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
 /* RX */
 /******/
 
+/*
+ * Calculate the RX filter to be set in the HW.
+ */
+u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
+{
+#define        RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
+
+       struct ath_hw *ah = priv->ah;
+       u32 rfilt;
+
+       rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
+               | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+               | ATH9K_RX_FILTER_MCAST;
+
+       /* If not a STA, enable processing of Probe Requests */
+       if (ah->opmode != NL80211_IFTYPE_STATION)
+               rfilt |= ATH9K_RX_FILTER_PROBEREQ;
+
+       /*
+        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
+        * mode interface or when in monitor mode. AP mode does not need this
+        * since it receives all in-BSS frames anyway.
+        */
+       if (((ah->opmode != NL80211_IFTYPE_AP) &&
+            (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
+           (ah->opmode == NL80211_IFTYPE_MONITOR))
+               rfilt |= ATH9K_RX_FILTER_PROM;
+
+       if (priv->rxfilter & FIF_CONTROL)
+               rfilt |= ATH9K_RX_FILTER_CONTROL;
+
+       if ((ah->opmode == NL80211_IFTYPE_STATION) &&
+           !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
+               rfilt |= ATH9K_RX_FILTER_MYBEACON;
+       else
+               rfilt |= ATH9K_RX_FILTER_BEACON;
+
+       if (conf_is_ht(&priv->hw->conf))
+               rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+
+       return rfilt;
+
+#undef RX_FILTER_PRESERVE
+}
+
+/*
+ * Recv initialization for opmode change.
+ */
+static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       u32 rfilt, mfilt[2];
+
+       /* configure rx filter */
+       rfilt = ath9k_htc_calcrxfilter(priv);
+       ath9k_hw_setrxfilter(ah, rfilt);
+
+       /* configure bssid mask */
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+               ath_hw_setbssidmask(common);
+
+       /* configure operational mode */
+       ath9k_hw_setopmode(ah);
+
+       /* Handle any link-level address change. */
+       ath9k_hw_setmac(ah, common->macaddr);
+
+       /* calculate and install multicast filter */
+       mfilt[0] = mfilt[1] = ~0;
+       ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
+}
+
 void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
 {
        ath9k_hw_rxena(priv->ah);
-       ath9k_cmn_opmode_init(priv->hw, priv->ah, priv->rxfilter);
+       ath9k_htc_opmode_init(priv);
        ath9k_hw_startpcureceive(priv->ah);
        priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
 }
@@ -354,7 +450,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
        padpos = ath9k_cmn_padpos(fc);
 
        padsize = padpos & 3;
-       if (padsize && skb->len >= padpos+padsize) {
+       if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
                memmove(skb->data + padsize, skb->data, padpos);
                skb_pull(skb, padsize);
        }
@@ -457,7 +553,7 @@ void ath9k_rx_tasklet(unsigned long data)
        struct ieee80211_rx_status rx_status;
        struct sk_buff *skb;
        unsigned long flags;
-
+       struct ieee80211_hdr *hdr;
 
        do {
                spin_lock_irqsave(&priv->rx.rxbuflock, flags);
@@ -484,6 +580,11 @@ void ath9k_rx_tasklet(unsigned long data)
                memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
                       sizeof(struct ieee80211_rx_status));
                skb = rxbuf->skb;
+               hdr = (struct ieee80211_hdr *) skb->data;
+
+               if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled)
+                               ieee80211_queue_work(priv->hw, &priv->ps_work);
+
                spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
 
                ieee80211_rx(priv->hw, skb);
@@ -550,7 +651,6 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
        spin_lock(&priv->rx.rxbuflock);
        memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
        skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
-       skb->len = rxstatus->rs_datalen;
        rxbuf->skb = skb;
        rxbuf->in_process = true;
        spin_unlock(&priv->rx.rxbuflock);
index 9a48999..587d98e 100644 (file)
@@ -146,7 +146,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
        struct htc_config_pipe_msg *cp_msg;
        int ret, time_left;
 
-       skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr));
+       skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
        if (!skb) {
                dev_err(target->dev, "failed to allocate send buffer\n");
                return -ENOMEM;
@@ -174,7 +174,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
 
        return 0;
 err:
-       dev_kfree_skb(skb);
+       kfree_skb(skb);
        return -EINVAL;
 }
 
@@ -184,7 +184,7 @@ static int htc_setup_complete(struct htc_target *target)
        struct htc_comp_msg *comp_msg;
        int ret = 0, time_left;
 
-       skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr));
+       skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
        if (!skb) {
                dev_err(target->dev, "failed to allocate send buffer\n");
                return -ENOMEM;
@@ -210,7 +210,7 @@ static int htc_setup_complete(struct htc_target *target)
        return 0;
 
 err:
-       dev_kfree_skb(skb);
+       kfree_skb(skb);
        return -EINVAL;
 }
 
@@ -250,8 +250,8 @@ int htc_connect_service(struct htc_target *target,
        endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
        endpoint->ep_callbacks = service_connreq->ep_callbacks;
 
-       skb = dev_alloc_skb(sizeof(struct htc_conn_svc_msg) +
-                           sizeof(struct htc_frame_hdr));
+       skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
+                           sizeof(struct htc_frame_hdr), GFP_ATOMIC);
        if (!skb) {
                dev_err(target->dev, "Failed to allocate buf to send"
                        "service connect req\n");
@@ -282,7 +282,7 @@ int htc_connect_service(struct htc_target *target,
        *conn_rsp_epid = target->conn_rsp_epid;
        return 0;
 err:
-       dev_kfree_skb(skb);
+       kfree_skb(skb);
        return ret;
 }
 
@@ -321,16 +321,18 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
                               struct sk_buff *skb, bool txok)
 {
        struct htc_endpoint *endpoint;
-       struct htc_frame_hdr *htc_hdr;
+       struct htc_frame_hdr *htc_hdr = NULL;
 
        if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
                complete(&htc_handle->cmd_wait);
                htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
+               goto ret;
        }
 
        if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
                complete(&htc_handle->cmd_wait);
                htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
+               goto ret;
        }
 
        if (skb) {
@@ -343,6 +345,14 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
                                                  htc_hdr->endpoint_id, txok);
                }
        }
+
+       return;
+ret:
+       /* HTC-generated packets are freed here. */
+       if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
+               dev_kfree_skb_any(skb);
+       else
+               kfree_skb(skb);
 }
 
 /*
@@ -367,7 +377,10 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
        epid = htc_hdr->endpoint_id;
 
        if (epid >= ENDPOINT_MAX) {
-               dev_kfree_skb_any(skb);
+               if (pipe_id != USB_REG_IN_PIPE)
+                       dev_kfree_skb_any(skb);
+               else
+                       kfree_skb(skb);
                return;
        }
 
@@ -377,7 +390,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
                        if (be32_to_cpu(*(u32 *) skb->data) == 0x00C60000)
                                /* Move past the Watchdog pattern */
-                               htc_hdr = (struct htc_frame_hdr *) skb->data + 4;
+                               htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
                }
 
                /* Get the message ID */
@@ -396,7 +409,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
                        break;
                }
 
-               dev_kfree_skb_any(skb);
+               kfree_skb(skb);
 
        } else {
                if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
index 7fdaea3..af730c7 100644 (file)
@@ -28,9 +28,6 @@
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan);
-static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value);
 
 MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
@@ -548,7 +545,6 @@ static bool ath9k_hw_devid_supported(u16 devid)
        case AR9285_DEVID_PCIE:
        case AR5416_DEVID_AR9287_PCI:
        case AR5416_DEVID_AR9287_PCIE:
-       case AR9271_USB:
        case AR2427_DEVID_PCIE:
                return true;
        default:
@@ -817,38 +813,46 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
 
                /* txgain table */
                if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9285Modes_high_power_tx_gain_9285_1_2,
-                       ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+                       if (AR_SREV_9285E_20(ah)) {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_XE2_0_high_power,
+                               ARRAY_SIZE(
+                                 ar9285Modes_XE2_0_high_power), 6);
+                       } else {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_high_power_tx_gain_9285_1_2,
+                               ARRAY_SIZE(
+                                 ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+                       }
                } else {
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9285Modes_original_tx_gain_9285_1_2,
-                       ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6);
+                       if (AR_SREV_9285E_20(ah)) {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_XE2_0_normal_power,
+                               ARRAY_SIZE(
+                                 ar9285Modes_XE2_0_normal_power), 6);
+                       } else {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_original_tx_gain_9285_1_2,
+                               ARRAY_SIZE(
+                                 ar9285Modes_original_tx_gain_9285_1_2), 6);
+                       }
                }
-
        }
 }
 
 static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah)
 {
-       u32 i, j;
-
-       if (ah->hw_version.devid == AR9280_DEVID_PCI) {
-
-               /* EEPROM Fixup */
-               for (i = 0; i < ah->iniModes.ia_rows; i++) {
-                       u32 reg = INI_RA(&ah->iniModes, i, 0);
+       struct base_eep_header *pBase = &(ah->eeprom.def.baseEepHeader);
+       struct ath_common *common = ath9k_hw_common(ah);
 
-                       for (j = 1; j < ah->iniModes.ia_columns; j++) {
-                               u32 val = INI_RA(&ah->iniModes, i, j);
+       ah->need_an_top2_fixup = (ah->hw_version.devid == AR9280_DEVID_PCI) &&
+                                (ah->eep_map != EEP_MAP_4KBITS) &&
+                                ((pBase->version & 0xff) > 0x0a) &&
+                                (pBase->pwdclkind == 0);
 
-                               INI_RA(&ah->iniModes, i, j) =
-                                       ath9k_hw_ini_fixup(ah,
-                                                          &ah->eeprom.def,
-                                                          reg, val);
-                       }
-               }
-       }
+       if (ah->need_an_top2_fixup)
+               ath_print(common, ATH_DBG_EEPROM,
+                         "needs fixup for AR_AN_TOP2 register\n");
 }
 
 int ath9k_hw_init(struct ath_hw *ah)
@@ -856,11 +860,13 @@ int ath9k_hw_init(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        int r = 0;
 
-       if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unsupported device ID: 0x%0x\n",
-                         ah->hw_version.devid);
-               return -EOPNOTSUPP;
+       if (common->bus_ops->ath_bus_type != ATH_USB) {
+               if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Unsupported device ID: 0x%0x\n",
+                                 ah->hw_version.devid);
+                       return -EOPNOTSUPP;
+               }
        }
 
        ath9k_hw_init_defaults(ah);
@@ -1121,23 +1127,23 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
 static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                                          enum nl80211_iftype opmode)
 {
-       ah->mask_reg = AR_IMR_TXERR |
+       u32 imr_reg = AR_IMR_TXERR |
                AR_IMR_TXURN |
                AR_IMR_RXERR |
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
 
        if (ah->config.rx_intr_mitigation)
-               ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+               imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
        else
-               ah->mask_reg |= AR_IMR_RXOK;
+               imr_reg |= AR_IMR_RXOK;
 
-       ah->mask_reg |= AR_IMR_TXOK;
+       imr_reg |= AR_IMR_TXOK;
 
        if (opmode == NL80211_IFTYPE_AP)
-               ah->mask_reg |= AR_IMR_MIB;
+               imr_reg |= AR_IMR_MIB;
 
-       REG_WRITE(ah, AR_IMR, ah->mask_reg);
+       REG_WRITE(ah, AR_IMR, imr_reg);
        ah->imrs2_reg |= AR_IMR_S2_GTT;
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
 
@@ -1290,51 +1296,6 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
        }
 }
 
-static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value)
-{
-       struct base_eep_header *pBase = &(pEepData->baseEepHeader);
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       switch (ah->hw_version.devid) {
-       case AR9280_DEVID_PCI:
-               if (reg == 0x7894) {
-                       ath_print(common, ATH_DBG_EEPROM,
-                               "ini VAL: %x  EEPROM: %x\n", value,
-                               (pBase->version & 0xff));
-
-                       if ((pBase->version & 0xff) > 0x0a) {
-                               ath_print(common, ATH_DBG_EEPROM,
-                                         "PWDCLKIND: %d\n",
-                                         pBase->pwdclkind);
-                               value &= ~AR_AN_TOP2_PWDCLKIND;
-                               value |= AR_AN_TOP2_PWDCLKIND &
-                                       (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
-                       } else {
-                               ath_print(common, ATH_DBG_EEPROM,
-                                         "PWDCLKIND Earlier Rev\n");
-                       }
-
-                       ath_print(common, ATH_DBG_EEPROM,
-                                 "final ini VAL: %x\n", value);
-               }
-               break;
-       }
-
-       return value;
-}
-
-static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value)
-{
-       if (ah->eep_map == EEP_MAP_4KBITS)
-               return value;
-       else
-               return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
-}
-
 static void ath9k_olc_init(struct ath_hw *ah)
 {
        u32 i;
@@ -1440,6 +1401,9 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
                u32 reg = INI_RA(&ah->iniModes, i, 0);
                u32 val = INI_RA(&ah->iniModes, i, modesIndex);
 
+               if (reg == AR_AN_TOP2 && ah->need_an_top2_fixup)
+                       val &= ~AR_AN_TOP2_PWDCLKIND;
+
                REG_WRITE(ah, reg, val);
 
                if (reg >= 0x7800 && reg < 0x78a0
@@ -2840,7 +2804,7 @@ EXPORT_SYMBOL(ath9k_hw_getisr);
 
 enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 {
-       u32 omask = ah->mask_reg;
+       enum ath9k_int omask = ah->imask;
        u32 mask, mask2;
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -2912,7 +2876,6 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
                           AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
        ah->imrs2_reg |= mask2;
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
-       ah->mask_reg = ints;
 
        if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
                if (ints & ATH9K_INT_TIM_TIMER)
@@ -3231,8 +3194,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
        }
 #endif
-
-       pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+       if (AR_SREV_9271(ah))
+               pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
+       else
+               pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
 
        if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
                pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
index 6b03e16..f4821cf 100644 (file)
@@ -44,8 +44,6 @@
 
 #define AR5416_AR9100_DEVID    0x000b
 
-#define AR9271_USB             0x9271
-
 #define        AR_SUBVENDOR_ID_NOG     0x0e11
 #define AR_SUBVENDOR_ID_NEW_A  0x7065
 #define AR5416_MAGIC           0x19641014
@@ -461,6 +459,7 @@ struct ath_hw {
 
        bool sw_mgmt_crypto;
        bool is_pciexpress;
+       bool need_an_top2_fixup;
        u16 tx_trig_level;
        u16 rfsilent;
        u32 rfkill_gpio;
@@ -478,7 +477,7 @@ struct ath_hw {
        struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
 
        int16_t curchan_rad_index;
-       u32 mask_reg;
+       enum ath9k_int imask;
        u32 imrs2_reg;
        u32 txok_interrupt_mask;
        u32 txerr_interrupt_mask;
index 177bdeb..455e9d3 100644 (file)
@@ -4184,7 +4184,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -4198,8 +4198,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -4312,7 +4312,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -4326,8 +4326,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -4731,17 +4731,12 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00007808, 0x54214514 },
     { 0x0000780c, 0x02025830 },
     { 0x00007810, 0x71c0d388 },
-    { 0x00007814, 0x924934a8 },
     { 0x0000781c, 0x00000000 },
     { 0x00007824, 0x00d86fff },
-    { 0x00007828, 0x26d2491b },
     { 0x0000782c, 0x6e36d97b },
-    { 0x00007830, 0xedb6d96e },
     { 0x00007834, 0x71400087 },
-    { 0x0000783c, 0x0001fffe },
-    { 0x00007840, 0xffeb1a20 },
     { 0x00007844, 0x000c0db6 },
-    { 0x00007848, 0x6db61b6f },
+    { 0x00007848, 0x6db6246f },
     { 0x0000784c, 0x6d9b66db },
     { 0x00007850, 0x6d8c6dba },
     { 0x00007854, 0x00040000 },
@@ -4777,7 +4772,12 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
+    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
+    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
     { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
+    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
     { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
     { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
     { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
@@ -4813,7 +4813,12 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
     { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
+    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
+    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
     { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 },
+    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
     { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
     { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
     { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
@@ -4825,6 +4830,86 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
     { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
 };
 
+static const u_int32_t ar9285Modes_XE2_0_normal_power[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
+    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
+    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae },
+    { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 },
+    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
+    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
+    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
+    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
+    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
+    { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
+    { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+    { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+};
+
+static const u_int32_t ar9285Modes_XE2_0_high_power[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
+    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
+    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e },
+    { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 },
+    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
+    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
+    { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
+    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+    { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+    { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+};
+
 static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
index 7af823a..4a2060e 100644 (file)
@@ -105,7 +105,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
        if (ah->tx_trig_level >= ah->config.max_txtrig_level)
                return false;
 
-       omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
+       omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
 
        txcfg = REG_READ(ah, AR_TXCFG);
        curLevel = MS(txcfg, AR_FTRIG);
@@ -246,79 +246,80 @@ void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
 }
 EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
 
-int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
+int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds,
+                       struct ath_tx_status *ts)
 {
        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;
+       ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+       ts->ts_tstamp = ads->AR_SendTimestamp;
+       ts->ts_status = 0;
+       ts->ts_flags = 0;
 
        if (ads->ds_txstatus1 & AR_FrmXmitOK)
-               ds->ds_txstat.ts_status |= ATH9K_TX_ACKED;
+               ts->ts_status |= ATH9K_TX_ACKED;
        if (ads->ds_txstatus1 & AR_ExcessiveRetries)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+               ts->ts_status |= ATH9K_TXERR_XRETRY;
        if (ads->ds_txstatus1 & AR_Filtered)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+               ts->ts_status |= ATH9K_TXERR_FILT;
        if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+               ts->ts_status |= ATH9K_TXERR_FIFO;
                ath9k_hw_updatetxtriglevel(ah, true);
        }
        if (ads->ds_txstatus9 & AR_TxOpExceeded)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+               ts->ts_status |= ATH9K_TXERR_XTXOP;
        if (ads->ds_txstatus1 & AR_TxTimerExpired)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+               ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
 
        if (ads->ds_txstatus1 & AR_DescCfgErr)
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+               ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
        if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+               ts->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;
+               ts->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;
+               ts->ts_flags |= ATH9K_TX_BA;
+               ts->ba_low = ads->AR_BaBitmapLow;
+               ts->ba_high = ads->AR_BaBitmapHigh;
        }
 
-       ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
-       switch (ds->ds_txstat.ts_rateindex) {
+       ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+       switch (ts->ts_rateindex) {
        case 0:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
                break;
        case 1:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
                break;
        case 2:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
                break;
        case 3:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+               ts->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 = 0;
+       ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+       ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+       ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+       ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+       ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+       ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+       ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+       ts->evm0 = ads->AR_TxEVM0;
+       ts->evm1 = ads->AR_TxEVM1;
+       ts->evm2 = ads->AR_TxEVM2;
+       ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+       ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+       ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+       ts->ts_antenna = 0;
 
        return 0;
 }
@@ -858,7 +859,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 EXPORT_SYMBOL(ath9k_hw_resettxqueue);
 
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-                       u32 pa, struct ath_desc *nds, u64 tsf)
+                       struct ath_rx_status *rs, u64 tsf)
 {
        struct ar5416_desc ads;
        struct ar5416_desc *adsp = AR5416DESC(ds);
@@ -869,70 +870,70 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
 
        ads.u.rx = adsp->u.rx;
 
-       ds->ds_rxstat.rs_status = 0;
-       ds->ds_rxstat.rs_flags = 0;
+       rs->rs_status = 0;
+       rs->rs_flags = 0;
 
-       ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
-       ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+       rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+       rs->rs_tstamp = ads.AR_RcvTimestamp;
 
        if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
-               ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+               rs->rs_rssi = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
        } else {
-               ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-               ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+               rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt00);
-               ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt01);
-               ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt02);
-               ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt10);
-               ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt11);
-               ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+               rs->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);
+               rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
        else
-               ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+               rs->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;
+       rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
+       rs->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 =
+       rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+       rs->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 =
+       rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+       rs->rs_flags =
                (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
-       ds->ds_rxstat.rs_flags |=
+       rs->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;
+               rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
        if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+               rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
        if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+               rs->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;
+                       rs->rs_status |= ATH9K_RXERR_CRC;
                else if (ads.ds_rxstatus8 & AR_PHYErr) {
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+                       rs->rs_status |= ATH9K_RXERR_PHY;
                        phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
-                       ds->ds_rxstat.rs_phyerr = phyerr;
+                       rs->rs_phyerr = phyerr;
                } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+                       rs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (ads.ds_rxstatus8 & AR_MichaelErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+                       rs->rs_status |= ATH9K_RXERR_MIC;
        }
 
        return 0;
index a5e543b..68dbd7a 100644 (file)
@@ -233,18 +233,9 @@ struct ath_desc {
        u32 ds_ctl0;
        u32 ds_ctl1;
        u32 ds_hw[20];
-       union {
-               struct ath_tx_status tx;
-               struct ath_rx_status rx;
-               void *stats;
-       } ds_us;
        void *ds_vdata;
 } __packed;
 
-#define        ds_txstat       ds_us.tx
-#define        ds_rxstat       ds_us.rx
-#define ds_stat                ds_us.stats
-
 #define ATH9K_TXDESC_CLRDMASK          0x0001
 #define ATH9K_TXDESC_NOACK             0x0002
 #define ATH9K_TXDESC_RTSENA            0x0004
@@ -702,7 +693,8 @@ void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
                         u32 segLen, bool firstSeg,
                         bool lastSeg, const struct ath_desc *ds0);
 void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
-int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds,
+                       struct ath_tx_status *ts);
 void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
                            u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
                            u32 keyIx, enum ath9k_key_type keyType, u32 flags);
@@ -732,7 +724,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
 bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
 bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-                       u32 pa, struct ath_desc *nds, u64 tsf);
+                       struct ath_rx_status *rs, u64 tsf);
 void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
                          u32 size, u32 flags);
 bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
index 115e1ae..f7ef114 100644 (file)
@@ -225,7 +225,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
        ath_cache_conf_rate(sc, &hw->conf);
        ath_update_txpow(sc);
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
  ps_restore:
        ath9k_ps_restore(sc);
@@ -434,7 +434,7 @@ void ath9k_tasklet(unsigned long data)
                        ath_gen_timer_isr(sc->sc_ah);
 
        /* re-enable hardware interrupt */
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
        ath9k_ps_restore(sc);
 }
 
@@ -477,7 +477,7 @@ irqreturn_t ath_isr(int irq, void *dev)
         * value to insure we only process bits we requested.
         */
        ath9k_hw_getisr(ah, &status);   /* NB: clears ISR too */
-       status &= sc->imask;    /* discard unasked-for bits */
+       status &= ah->imask;    /* discard unasked-for bits */
 
        /*
         * If there are no status bits set, then this interrupt was not
@@ -518,7 +518,7 @@ irqreturn_t ath_isr(int irq, void *dev)
                 * the interrupt.
                 */
                ath9k_hw_procmibevent(ah);
-               ath9k_hw_set_interrupts(ah, sc->imask);
+               ath9k_hw_set_interrupts(ah, ah->imask);
        }
 
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
@@ -536,7 +536,7 @@ chip_reset:
 
        if (sched) {
                /* turn off every interrupt except SWBA */
-               ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA));
+               ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA));
                tasklet_schedule(&sc->intr_tq);
        }
 
@@ -887,7 +887,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
                ath_beacon_config(sc, NULL);    /* restart beacons */
 
        /* Re-Enable  interrupts */
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Enable LED */
        ath9k_hw_cfg_output(ah, ah->led_pin,
@@ -977,7 +977,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        if (sc->sc_flags & SC_OP_BEACONS)
                ath_beacon_config(sc, NULL);    /* restart beacons */
 
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        if (retry_tx) {
                int i;
@@ -1162,23 +1162,23 @@ static int ath9k_start(struct ieee80211_hw *hw)
        }
 
        /* Setup our intr mask. */
-       sc->imask = ATH9K_INT_RX | ATH9K_INT_TX
+       ah->imask = ATH9K_INT_RX | ATH9K_INT_TX
                | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
                | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
-               sc->imask |= ATH9K_INT_GTT;
+               ah->imask |= ATH9K_INT_GTT;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-               sc->imask |= ATH9K_INT_CST;
+               ah->imask |= ATH9K_INT_CST;
 
        ath_cache_conf_rate(sc, &hw->conf);
 
        sc->sc_flags &= ~SC_OP_INVALID;
 
        /* Disable BMISS interrupt when we're not associated */
-       sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        ieee80211_wake_queues(hw);
 
@@ -1372,14 +1372,15 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
        int ret = 0;
 
        mutex_lock(&sc->mutex);
 
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
            sc->nvifs > 0) {
                ret = -ENOBUFS;
                goto out;
@@ -1414,19 +1415,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
        sc->nvifs++;
 
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
                ath9k_set_bssid_mask(hw);
 
        if (sc->nvifs > 1)
                goto out; /* skip global settings for secondary vif */
 
        if (ic_opmode == NL80211_IFTYPE_AP) {
-               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+               ath9k_hw_set_tsfadjust(ah, 1);
                sc->sc_flags |= SC_OP_TSF_RESET;
        }
 
        /* Set the device opmode */
-       sc->sc_ah->opmode = ic_opmode;
+       ah->opmode = ic_opmode;
 
        /*
         * Enable MIB interrupts when there are hardware phy counters.
@@ -1435,11 +1436,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        if ((vif->type == NL80211_IFTYPE_STATION) ||
            (vif->type == NL80211_IFTYPE_ADHOC) ||
            (vif->type == NL80211_IFTYPE_MESH_POINT)) {
-               sc->imask |= ATH9K_INT_MIB;
-               sc->imask |= ATH9K_INT_TSFOOR;
+               ah->imask |= ATH9K_INT_MIB;
+               ah->imask |= ATH9K_INT_TSFOOR;
        }
 
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        if (vif->type == NL80211_IFTYPE_AP    ||
            vif->type == NL80211_IFTYPE_ADHOC ||
@@ -1495,15 +1496,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
 void ath9k_enable_ps(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
+
        sc->ps_enabled = true;
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-               if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
-                       sc->imask |= ATH9K_INT_TIM_TIMER;
-                       ath9k_hw_set_interrupts(sc->sc_ah,
-                                       sc->imask);
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+               if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
+                       ah->imask |= ATH9K_INT_TIM_TIMER;
+                       ath9k_hw_set_interrupts(ah, ah->imask);
                }
        }
-       ath9k_hw_setrxabort(sc->sc_ah, 1);
+       ath9k_hw_setrxabort(ah, 1);
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1579,10 +1581,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                                                  PS_WAIT_FOR_CAB |
                                                  PS_WAIT_FOR_PSPOLL_DATA |
                                                  PS_WAIT_FOR_TX_ACK);
-                               if (sc->imask & ATH9K_INT_TIM_TIMER) {
-                                       sc->imask &= ~ATH9K_INT_TIM_TIMER;
+                               if (ah->imask & ATH9K_INT_TIM_TIMER) {
+                                       ah->imask &= ~ATH9K_INT_TIM_TIMER;
                                        ath9k_hw_set_interrupts(sc->sc_ah,
-                                                       sc->imask);
+                                                       ah->imask);
                                }
                        }
                }
index 9441c67..1ec836c 100644 (file)
@@ -88,6 +88,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
 }
 
 static const struct ath_bus_ops ath_pci_bus_ops = {
+       .ath_bus_type = ATH_PCI,
        .read_cachesize = ath_pci_read_cachesize,
        .eeprom_read = ath_pci_eeprom_read,
        .bt_coex_prep = ath_pci_bt_coex_prep,
index 0999a49..0132e4c 100644 (file)
@@ -503,6 +503,8 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
 #define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S   24
 
 #define AR_PHY_TX_PWRCTRL7       0xa274
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX   0x0007E000
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX_S 13
 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
 
@@ -513,8 +515,16 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
 #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
 
 #define AR_PHY_TX_GAIN_TBL1      0xa300
-#define AR_PHY_TX_GAIN                     0x0007F000
-#define AR_PHY_TX_GAIN_S                   12
+#define AR_PHY_TX_GAIN_CLC       0x0000001E
+#define AR_PHY_TX_GAIN_CLC_S     1
+#define AR_PHY_TX_GAIN           0x0007F000
+#define AR_PHY_TX_GAIN_S         12
+
+#define AR_PHY_CLC_TBL1      0xa35c
+#define AR_PHY_CLC_I0        0x07ff0000
+#define AR_PHY_CLC_I0_S      16
+#define AR_PHY_CLC_Q0        0x0000ffd0
+#define AR_PHY_CLC_Q0_S      5
 
 #define AR_PHY_CH0_TX_PWRCTRL11  0xa398
 #define AR_PHY_CH1_TX_PWRCTRL11  0xb398
index 36083dd..3d8d40c 100644 (file)
@@ -176,9 +176,9 @@ struct ath_rate_priv {
 #define ATH_TX_INFO_UNDERRUN           (1 << 4)
 
 enum ath9k_internal_frame_type {
-       ATH9K_NOT_INTERNAL,
-       ATH9K_INT_PAUSE,
-       ATH9K_INT_UNPAUSE
+       ATH9K_IFT_NOT_INTERNAL,
+       ATH9K_IFT_PAUSE,
+       ATH9K_IFT_UNPAUSE
 };
 
 int ath_rate_control_register(void);
index 1ca42e5..94560e2 100644 (file)
@@ -477,7 +477,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
        struct ath_buf *bf;
        struct ath_desc *ds;
-       struct ath_rx_status *rx_stats;
        struct sk_buff *skb = NULL, *requeue_skb;
        struct ieee80211_rx_status *rxs;
        struct ath_hw *ah = sc->sc_ah;
@@ -491,6 +490,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
        struct ieee80211_hdr *hdr;
        int retval;
        bool decrypt_error = false;
+       struct ath_rx_status rs;
 
        spin_lock_bh(&sc->rx.rxbuflock);
 
@@ -518,14 +518,14 @@ 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,
-                                            bf->bf_daddr,
-                                            PA2DESC(sc, ds->ds_link),
-                                            0);
+               memset(&rs, 0, sizeof(rs));
+               retval = ath9k_hw_rxprocdesc(ah, ds, &rs, 0);
                if (retval == -EINPROGRESS) {
+                       struct ath_rx_status trs;
                        struct ath_buf *tbf;
                        struct ath_desc *tds;
 
+                       memset(&trs, 0, sizeof(trs));
                        if (list_is_last(&bf->list, &sc->rx.rxbuf)) {
                                sc->rx.rxlink = NULL;
                                break;
@@ -545,8 +545,7 @@ 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, &trs, 0);
                        if (retval == -EINPROGRESS) {
                                break;
                        }
@@ -569,9 +568,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                rxs =  IEEE80211_SKB_RXCB(skb);
 
                hw = ath_get_virt_hw(sc, hdr);
-               rx_stats = &ds->ds_rxstat;
 
-               ath_debug_stat_rx(sc, bf);
+               ath_debug_stat_rx(sc, &rs);
 
                /*
                 * If we're asked to flush receive queue, directly
@@ -580,7 +578,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                if (flush)
                        goto requeue;
 
-               retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats,
+               retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs,
                                                     rxs, &decrypt_error);
                if (retval)
                        goto requeue;
@@ -601,9 +599,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                                 common->rx_bufsize,
                                 DMA_FROM_DEVICE);
 
-               skb_put(skb, rx_stats->rs_datalen);
+               skb_put(skb, rs.rs_datalen);
 
-               ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats,
+               ath9k_cmn_rx_skb_postprocess(common, skb, &rs,
                                             rxs, decrypt_error);
 
                /* We will now give hardware our shiny new allocated skb */
@@ -626,9 +624,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                 * change the default rx antenna if rx diversity chooses the
                 * other antenna 3 times in a row.
                 */
-               if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
+               if (sc->rx.defant != rs.rs_antenna) {
                        if (++sc->rx.rxotherant >= 3)
-                               ath_setdefantenna(sc, rx_stats->rs_antenna);
+                               ath_setdefantenna(sc, rs.rs_antenna);
                } else {
                        sc->rx.rxotherant = 0;
                }
index 198e41d..7e36ad7 100644 (file)
 
 #define AR_WA                          0x4004
 #define AR_WA_D3_L1_DISABLE            (1 << 14)
-#define AR9285_WA_DEFAULT              0x004a05cb
+#define AR9285_WA_DEFAULT              0x004a050b
 #define AR9280_WA_DEFAULT              0x0040073b
 #define AR_WA_DEFAULT                  0x0000073f
 
     (AR_SREV_9271(_ah) && \
      ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
 
+#define AR_SREV_9285E_20(_ah) \
+    (AR_SREV_9285_12_OR_LATER(_ah) && \
+     ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
+
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
 #define AR_RAD2133_SREV_MAJOR                 0xd0
@@ -1181,6 +1185,13 @@ enum {
 #define AR9285_AN_RF2G4_DB2_4    0x00003800
 #define AR9285_AN_RF2G4_DB2_4_S    11
 
+#define AR9285_RF2G5                   0x7830
+#define AR9285_RF2G5_IC50TX            0xfffff8ff
+#define AR9285_RF2G5_IC50TX_SET                0x00000400
+#define AR9285_RF2G5_IC50TX_XE_SET     0x00000500
+#define AR9285_RF2G5_IC50TX_CLEAR      0x00000700
+#define AR9285_RF2G5_IC50TX_CLEAR_S    8
+
 /* AR9271 : 0x7828, 0x782c different setting from AR9285 */
 #define AR9271_AN_RF2G3_OB_cck         0x001C0000
 #define AR9271_AN_RF2G3_OB_cck_S       18
index 00c0e21..105ad40 100644 (file)
@@ -220,7 +220,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
 
        memset(&txctl, 0, sizeof(struct ath_tx_control));
        txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
-       txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE;
+       txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
 
        if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
                goto exit;
index 818dea0..f2ff18c 100644 (file)
@@ -169,7 +169,7 @@ void ath9k_wmi_tasklet(unsigned long data)
                break;
        }
 
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
 }
 
 static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
@@ -207,13 +207,13 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
        ath9k_wmi_rsp_callback(wmi, skb);
 
 free_skb:
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
 }
 
 static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb,
                              enum htc_endpoint_id epid, bool txok)
 {
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
 }
 
 int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
@@ -269,7 +269,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
        if (!wmi)
                return -EINVAL;
 
-       skb = dev_alloc_skb(headroom + cmd_len);
+       skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
        if (!skb)
                return -ENOMEM;
 
@@ -313,7 +313,7 @@ out:
        ath_print(common, ATH_DBG_WMI,
                  "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
        mutex_unlock(&wmi->op_mutex);
-       dev_kfree_skb_any(skb);
+       kfree_skb(skb);
 
        return ret;
 }
index a3b6cf2..02df4cb 100644 (file)
@@ -59,15 +59,14 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
                                  struct ath_atx_tid *tid,
                                  struct list_head *bf_head);
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-                               struct ath_txq *txq,
-                               struct list_head *bf_q,
-                               int txok, int sendbar);
+                               struct ath_txq *txq, struct list_head *bf_q,
+                               struct ath_tx_status *ts, int txok, int sendbar);
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                             struct list_head *head);
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
 static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-                             int txok);
-static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
+                             struct ath_tx_status *ts, int txok);
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
                             int nbad, int txok, bool update_rc);
 
 enum {
@@ -223,6 +222,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 {
        struct ath_buf *bf;
        struct list_head bf_head;
+       struct ath_tx_status ts;
+
+       memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
        for (;;) {
@@ -236,7 +238,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
                        ath_tx_update_baw(sc, tid, bf->bf_seqno);
 
                spin_unlock(&txq->axq_lock);
-               ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+               ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
                spin_lock(&txq->axq_lock);
        }
 
@@ -286,7 +288,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                 struct ath_buf *bf, struct list_head *bf_q,
-                                int txok)
+                                struct ath_tx_status *ts, int txok)
 {
        struct ath_node *an = NULL;
        struct sk_buff *skb;
@@ -296,7 +298,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        struct ieee80211_tx_info *tx_info;
        struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
-       struct ath_desc *ds = bf_last->bf_desc;
        struct list_head bf_head, bf_pending;
        u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
        u32 ba[WME_BA_BMP_SIZE >> 5];
@@ -325,10 +326,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        memset(ba, 0, WME_BA_BMP_SIZE >> 3);
 
        if (isaggr && txok) {
-               if (ATH_DS_TX_BA(ds)) {
-                       seq_st = ATH_DS_BA_SEQ(ds);
-                       memcpy(ba, ATH_DS_BA_BITMAP(ds),
-                              WME_BA_BMP_SIZE >> 3);
+               if (ts->ts_flags & ATH9K_TX_BA) {
+                       seq_st = ts->ts_seqnum;
+                       memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
                } else {
                        /*
                         * AR5416 can become deaf/mute when BA
@@ -345,7 +345,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        INIT_LIST_HEAD(&bf_pending);
        INIT_LIST_HEAD(&bf_head);
 
-       nbad = ath_tx_num_badfrms(sc, bf, txok);
+       nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
        while (bf) {
                txfail = txpending = 0;
                bf_next = bf->bf_next;
@@ -359,7 +359,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        acked_cnt++;
                } else {
                        if (!(tid->state & AGGR_CLEANUP) &&
-                           ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
+                           ts->ts_flags != ATH9K_TX_SW_ABORTED) {
                                if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
                                        ath_tx_set_retry(sc, txq, bf);
                                        txpending = 1;
@@ -402,13 +402,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        spin_unlock_bh(&txq->axq_lock);
 
                        if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
-                               ath_tx_rc_status(bf, ds, nbad, txok, true);
+                               ath_tx_rc_status(bf, ts, nbad, txok, true);
                                rc_update = false;
                        } else {
-                               ath_tx_rc_status(bf, ds, nbad, txok, false);
+                               ath_tx_rc_status(bf, ts, nbad, txok, false);
                        }
 
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
+                               !txfail, sendbar);
                } else {
                        /* retry the un-acked ones */
                        if (bf->bf_next == NULL && bf_last->bf_stale) {
@@ -426,10 +427,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                        spin_unlock_bh(&txq->axq_lock);
 
                                        bf->bf_state.bf_type |= BUF_XRETRY;
-                                       ath_tx_rc_status(bf, ds, nbad,
+                                       ath_tx_rc_status(bf, ts, nbad,
                                                         0, false);
                                        ath_tx_complete_buf(sc, bf, txq,
-                                                           &bf_head, 0, 0);
+                                                           &bf_head, ts, 0, 0);
                                        break;
                                }
 
@@ -752,8 +753,11 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
        struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
+       struct ath_tx_status ts;
        struct ath_buf *bf;
        struct list_head bf_head;
+
+       memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
        if (txtid->state & AGGR_CLEANUP)
@@ -780,7 +784,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
                }
                list_move_tail(&bf->list, &bf_head);
                ath_tx_update_baw(sc, txtid, bf->bf_seqno);
-               ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+               ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }
        spin_unlock_bh(&txq->axq_lock);
 
@@ -1028,6 +1032,11 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 {
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
+       struct ath_tx_status ts;
+
+       memset(&ts, 0, sizeof(ts));
+       if (!retry_tx)
+               ts.ts_flags = ATH9K_TX_SW_ABORTED;
 
        INIT_LIST_HEAD(&bf_head);
 
@@ -1053,9 +1062,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
                }
 
                lastbf = bf->bf_lastbf;
-               if (!retry_tx)
-                       lastbf->bf_desc->ds_txstat.ts_flags =
-                               ATH9K_TX_SW_ABORTED;
 
                /* remove ath_buf's of the same mpdu from txq */
                list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
@@ -1064,9 +1070,9 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
                spin_unlock_bh(&txq->axq_lock);
 
                if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
+                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
                else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }
 
        spin_lock_bh(&txq->axq_lock);
@@ -1568,12 +1574,12 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
 
        tx_info->pad[0] = 0;
        switch (txctl->frame_type) {
-       case ATH9K_NOT_INTERNAL:
+       case ATH9K_IFT_NOT_INTERNAL:
                break;
-       case ATH9K_INT_PAUSE:
+       case ATH9K_IFT_PAUSE:
                tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
                /* fall through */
-       case ATH9K_INT_UNPAUSE:
+       case ATH9K_IFT_UNPAUSE:
                tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
                break;
        }
@@ -1852,9 +1858,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-                               struct ath_txq *txq,
-                               struct list_head *bf_q,
-                               int txok, int sendbar)
+                               struct ath_txq *txq, struct list_head *bf_q,
+                               struct ath_tx_status *ts, int txok, int sendbar)
 {
        struct sk_buff *skb = bf->bf_mpdu;
        unsigned long flags;
@@ -1872,7 +1877,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 
        dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
        ath_tx_complete(sc, skb, bf->aphy, tx_flags);
-       ath_debug_stat_tx(sc, txq, bf);
+       ath_debug_stat_tx(sc, txq, bf, ts);
 
        /*
         * Return the list of ath_buf of this mpdu to free queue
@@ -1883,23 +1888,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 }
 
 static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-                             int txok)
+                             struct ath_tx_status *ts, int txok)
 {
-       struct ath_buf *bf_last = bf->bf_lastbf;
-       struct ath_desc *ds = bf_last->bf_desc;
        u16 seq_st = 0;
        u32 ba[WME_BA_BMP_SIZE >> 5];
        int ba_index;
        int nbad = 0;
        int isaggr = 0;
 
-       if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+       if (ts->ts_flags == ATH9K_TX_SW_ABORTED)
                return 0;
 
        isaggr = bf_isaggr(bf);
        if (isaggr) {
-               seq_st = ATH_DS_BA_SEQ(ds);
-               memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3);
+               seq_st = ts->ts_seqnum;
+               memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
        }
 
        while (bf) {
@@ -1913,7 +1916,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
        return nbad;
 }
 
-static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
                             int nbad, int txok, bool update_rc)
 {
        struct sk_buff *skb = bf->bf_mpdu;
@@ -1923,24 +1926,24 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
        u8 i, tx_rateindex;
 
        if (txok)
-               tx_info->status.ack_signal = ds->ds_txstat.ts_rssi;
+               tx_info->status.ack_signal = ts->ts_rssi;
 
-       tx_rateindex = ds->ds_txstat.ts_rateindex;
+       tx_rateindex = ts->ts_rateindex;
        WARN_ON(tx_rateindex >= hw->max_rates);
 
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+       if (ts->ts_status & ATH9K_TXERR_FILT)
                tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 
-       if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+       if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
            (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
                if (ieee80211_is_data(hdr->frame_control)) {
-                       if (ds->ds_txstat.ts_flags &
+                       if (ts->ts_flags &
                            (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
                                tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
-                       if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
-                           (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
+                       if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
+                           (ts->ts_status & ATH9K_TXERR_FIFO))
                                tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
                        tx_info->status.ampdu_len = bf->bf_nframes;
                        tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
@@ -1978,6 +1981,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        struct ath_buf *bf, *lastbf, *bf_held = NULL;
        struct list_head bf_head;
        struct ath_desc *ds;
+       struct ath_tx_status ts;
        int txok;
        int status;
 
@@ -2017,7 +2021,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                lastbf = bf->bf_lastbf;
                ds = lastbf->bf_desc;
 
-               status = ath9k_hw_txprocdesc(ah, ds);
+               memset(&ts, 0, sizeof(ts));
+               status = ath9k_hw_txprocdesc(ah, ds, &ts);
                if (status == -EINPROGRESS) {
                        spin_unlock_bh(&txq->axq_lock);
                        break;
@@ -2028,7 +2033,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                 * can disable RX.
                 */
                if (bf->bf_isnullfunc &&
-                   (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
+                   (ts.ts_status & ATH9K_TX_ACKED)) {
                        if ((sc->ps_flags & PS_ENABLED))
                                ath9k_enable_ps(sc);
                        else
@@ -2047,7 +2052,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                                &txq->axq_q, lastbf->list.prev);
 
                txq->axq_depth--;
-               txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK);
+               txok = !(ts.ts_status & ATH9K_TXERR_MASK);
                txq->axq_tx_inprogress = false;
                spin_unlock_bh(&txq->axq_lock);
 
@@ -2062,16 +2067,16 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                         * This frame is sent out as a single frame.
                         * Use hardware retry status for this frame.
                         */
-                       bf->bf_retries = ds->ds_txstat.ts_longretry;
-                       if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
+                       bf->bf_retries = ts.ts_longretry;
+                       if (ts.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
-                       ath_tx_rc_status(bf, ds, 0, txok, true);
+                       ath_tx_rc_status(bf, &ts, 0, txok, true);
                }
 
                if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
+                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
                else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
 
                ath_wake_mac80211_queue(sc, txq);
 
index ecc9eb0..a8f81ea 100644 (file)
@@ -19,8 +19,8 @@
 #include "ath.h"
 #include "reg.h"
 
-#define REG_READ       common->ops->read
-#define REG_WRITE      common->ops->write
+#define REG_READ       (common->ops->read)
+#define REG_WRITE      (common->ops->write)
 
 /**
  * ath_hw_set_bssid_mask - filter out bssids we listen
index 00489c4..24d5988 100644 (file)
@@ -50,6 +50,7 @@
 
 #define ATH9K_5GHZ_ALL         ATH9K_5GHZ_5150_5350, \
                                ATH9K_5GHZ_5470_5850
+
 /* This one skips what we call "mid band" */
 #define ATH9K_5GHZ_NO_MIDBAND  ATH9K_5GHZ_5150_5350, \
                                ATH9K_5GHZ_5725_5850
@@ -360,7 +361,7 @@ EXPORT_SYMBOL(ath_reg_notifier_apply);
 
 static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
 {
-        u16 rd = ath_regd_get_eepromRD(reg);
+       u16 rd = ath_regd_get_eepromRD(reg);
        int i;
 
        if (rd & COUNTRY_ERD_FLAG) {
index c4dc369..3d6b337 100644 (file)
@@ -105,7 +105,7 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
 }
 
 static void b43_chantab_radio_upload(struct b43_wldev *dev,
-                                    const struct b43_nphy_channeltab_entry *e)
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
 {
        b43_radio_write(dev, B2055_PLL_REF, e->radio_pll_ref);
        b43_radio_write(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
@@ -142,7 +142,7 @@ static void b43_chantab_radio_upload(struct b43_wldev *dev,
 }
 
 static void b43_chantab_phy_upload(struct b43_wldev *dev,
-                                  const struct b43_nphy_channeltab_entry *e)
+                                  const struct b43_phy_n_sfo_cfg *e)
 {
        b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
        b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
@@ -160,16 +160,16 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
 static void b43_radio_2055_setup(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry *e)
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
 {
        B43_WARN_ON(dev->phy.rev >= 3);
 
        b43_chantab_radio_upload(dev, e);
        udelay(50);
-       b43_radio_write(dev, B2055_VCO_CAL10, 5);
-       b43_radio_write(dev, B2055_VCO_CAL10, 45);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x05);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x45);
        b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
-       b43_radio_write(dev, B2055_VCO_CAL10, 65);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x65);
        udelay(300);
 }
 
@@ -255,6 +255,16 @@ static void b43_radio_init2055(struct b43_wldev *dev)
 }
 
 /*
+ * Initialize a Broadcom 2056 N-radio
+ * http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init
+ */
+static void b43_radio_init2056(struct b43_wldev *dev)
+{
+       /* TODO */
+}
+
+
+/*
  * Upload the N-PHY tables.
  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
  */
@@ -2791,7 +2801,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        }
                        b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
                                                buffer);
-                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2,
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 101), 2,
                                                buffer);
                        b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
                                                buffer);
@@ -3261,7 +3271,7 @@ int b43_phy_initn(struct b43_wldev *dev)
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */
 static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry *e,
+                               const struct b43_phy_n_sfo_cfg *e,
                                struct b43_chanspec chanspec)
 {
        struct b43_phy *phy = &dev->phy;
@@ -3327,13 +3337,21 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev,
 {
        struct b43_phy_n *nphy = dev->phy.n;
 
-       const struct b43_nphy_channeltab_entry *tabent;
+       const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
+       const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
 
        u8 tmp;
        u8 channel = chanspec.channel;
 
        if (dev->phy.rev >= 3) {
                /* TODO */
+               tabent_r3 = NULL;
+               if (!tabent_r3)
+                       return -ESRCH;
+       } else {
+               tabent_r2 = b43_nphy_get_chantabent_rev2(dev, channel);
+               if (!tabent_r2)
+                       return -ESRCH;
        }
 
        nphy->radio_chanspec = chanspec;
@@ -3354,17 +3372,13 @@ static int b43_nphy_set_chanspec(struct b43_wldev *dev,
        if (dev->phy.rev >= 3) {
                tmp = (chanspec.b_freq == 1) ? 4 : 0;
                b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
-               /* TODO: PHY Radio2056 Setup (chan_info_ptr[i]) */
-               /* TODO: N PHY Chanspec Setup (chan_info_ptr[i]) */
+               /* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
+               b43_nphy_chanspec_setup(dev, &(tabent_r3->phy_regs), chanspec);
        } else {
-               tabent = b43_nphy_get_chantabent(dev, channel);
-               if (!tabent)
-                       return -ESRCH;
-
                tmp = (chanspec.b_freq == 1) ? 0x0020 : 0x0050;
                b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp);
-               b43_radio_2055_setup(dev, tabent);
-               b43_nphy_chanspec_setup(dev, tabent, chanspec);
+               b43_radio_2055_setup(dev, tabent_r2);
+               b43_nphy_chanspec_setup(dev, &(tabent_r2->phy_regs), chanspec);
        }
 
        return 0;
@@ -3474,6 +3488,8 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
                                        bool blocked)
 {
+       struct b43_phy_n *nphy = dev->phy.n;
+
        if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
                b43err(dev->wl, "MAC not suspended\n");
 
@@ -3499,8 +3515,8 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
                }
        } else {
                if (dev->phy.rev >= 3) {
-                       /* TODO: b43_radio_init2056(dev); */
-                       /* TODO: PHY Set Channel Spec (dev, radio_chanspec) */
+                       b43_radio_init2056(dev);
+                       b43_nphy_set_chanspec(dev, nphy->radio_chanspec);
                } else {
                        b43_radio_init2055(dev);
                }
index a00d509..d96e870 100644 (file)
@@ -318,14 +318,14 @@ void b2055_upload_inittab(struct b43_wldev *dev,
        .radio_c2_tx_mxbgtrim   = r21
 
 #define PHYREGS(r0, r1, r2, r3, r4, r5)        \
-       .phy_bw1a       = r0,           \
-       .phy_bw2        = r1,           \
-       .phy_bw3        = r2,           \
-       .phy_bw4        = r3,           \
-       .phy_bw5        = r4,           \
-       .phy_bw6        = r5
-
-static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
+       .phy_regs.phy_bw1a      = r0,   \
+       .phy_regs.phy_bw2       = r1,   \
+       .phy_regs.phy_bw3       = r2,   \
+       .phy_regs.phy_bw4       = r3,   \
+       .phy_regs.phy_bw5       = r4,   \
+       .phy_regs.phy_bw6       = r5
+
+static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab[] = {
   {    .channel                = 184,
        .freq                   = 4920, /* MHz */
        .unk2                   = 3280,
@@ -1320,10 +1320,10 @@ static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
   },
 };
 
-const struct b43_nphy_channeltab_entry *
-b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
+const struct b43_nphy_channeltab_entry_rev2 *
+b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel)
 {
-       const struct b43_nphy_channeltab_entry *e;
+       const struct b43_nphy_channeltab_entry_rev2 *e;
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {