Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
authorDavid S. Miller <davem@davemloft.net>
Thu, 15 Apr 2010 21:31:06 +0000 (14:31 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Apr 2010 21:31:06 +0000 (14:31 -0700)
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++) {
index b23036f..8fc1da9 100644 (file)
@@ -13,9 +13,13 @@ struct b43_phy_n_sfo_cfg {
        u16 phy_bw6;
 };
 
-struct b43_nphy_channeltab_entry {
+struct b43_nphy_channeltab_entry_rev2 {
        /* The channel number */
        u8 channel;
+       /* The channel frequency in MHz */
+       u16 freq;
+       /* An unknown value */
+       u16 unk2;
        /* Radio register values on channelswitch */
        u8 radio_pll_ref;
        u8 radio_rf_pllmod0;
@@ -40,16 +44,18 @@ struct b43_nphy_channeltab_entry {
        u8 radio_c2_tx_pgapadtn;
        u8 radio_c2_tx_mxbgtrim;
        /* PHY register values on channelswitch */
-       u16 phy_bw1a;
-       u16 phy_bw2;
-       u16 phy_bw3;
-       u16 phy_bw4;
-       u16 phy_bw5;
-       u16 phy_bw6;
+       struct b43_phy_n_sfo_cfg phy_regs;
+};
+
+struct b43_nphy_channeltab_entry_rev3 {
+       /* The channel number */
+       u8 channel;
        /* The channel frequency in MHz */
        u16 freq;
-       /* An unknown value */
-       u16 unk2;
+       /* Radio register values on channelswitch */
+       /* TODO */
+       /* PHY register values on channelswitch */
+       struct b43_phy_n_sfo_cfg phy_regs;
 };
 
 
@@ -86,8 +92,8 @@ void b2055_upload_inittab(struct b43_wldev *dev,
 
 /* Get the NPHY Channel Switch Table entry for a channel number.
  * Returns NULL on failure to find an entry. */
-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);
 
 
 /* The N-PHY tables. */
index fe63bf2..2088ac0 100644 (file)
@@ -2140,7 +2140,7 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
        DECLARE_SSID_BUF(ssid);
 
        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-                 "disassociated: '%s' %pM \n",
+                 "disassociated: '%s' %pM\n",
                  print_ssid(ssid, priv->essid, priv->essid_len),
                  priv->bssid);
 
@@ -3285,7 +3285,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
 
        if (inta & IPW2100_INTA_PARITY_ERROR) {
                printk(KERN_ERR DRV_NAME
-                      ": ***** PARITY ERROR INTERRUPT !!!! \n");
+                      ": ***** PARITY ERROR INTERRUPT !!!!\n");
                priv->inta_other++;
                write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
        }
@@ -6753,7 +6753,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
                err = -EOPNOTSUPP;
                goto done;
        } else {                /* Set the channel */
-               IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+               IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
                err = ipw2100_set_channel(priv, fwrq->m, 0);
        }
 
@@ -6782,7 +6782,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev,
        else
                wrqu->freq.m = 0;
 
-       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
        return 0;
 
 }
@@ -6794,7 +6794,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
        struct ipw2100_priv *priv = libipw_priv(dev);
        int err = 0;
 
-       IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
+       IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
 
        if (wrqu->mode == priv->ieee->iw_mode)
                return 0;
@@ -7149,7 +7149,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
        memset(priv->nick, 0, sizeof(priv->nick));
        memcpy(priv->nick, extra, wrqu->data.length);
 
-       IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
+       IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
 
        return 0;
 }
@@ -7168,7 +7168,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
        memcpy(extra, priv->nick, wrqu->data.length);
        wrqu->data.flags = 1;   /* active */
 
-       IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
+       IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
 
        return 0;
 }
@@ -7207,7 +7207,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev,
 
        err = ipw2100_set_tx_rates(priv, rate, 0);
 
-       IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
+       IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
       done:
        mutex_unlock(&priv->action_mutex);
        return err;
@@ -7258,7 +7258,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
                wrqu->bitrate.value = 0;
        }
 
-       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+       IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7294,7 +7294,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
 
        err = ipw2100_set_rts_threshold(priv, value);
 
-       IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
+       IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
       done:
        mutex_unlock(&priv->action_mutex);
        return err;
@@ -7316,7 +7316,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev,
        /* If RTS is set to the default value, then it is disabled */
        wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
 
-       IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
+       IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
 
        return 0;
 }
@@ -7355,7 +7355,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
 
        err = ipw2100_set_tx_power(priv, value);
 
-       IPW_DEBUG_WX("SET TX Power -> %d \n", value);
+       IPW_DEBUG_WX("SET TX Power -> %d\n", value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7384,7 +7384,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
 
        wrqu->txpower.flags = IW_TXPOW_DBM;
 
-       IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value);
+       IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
 
        return 0;
 }
@@ -7414,7 +7414,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev,
                priv->frag_threshold = priv->ieee->fts;
        }
 
-       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
+       IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
 
        return 0;
 }
@@ -7432,7 +7432,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev,
        wrqu->frag.fixed = 0;   /* no auto select */
        wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
 
-       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
 
        return 0;
 }
@@ -7458,14 +7458,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
 
        if (wrqu->retry.flags & IW_RETRY_SHORT) {
                err = ipw2100_set_short_retry(priv, wrqu->retry.value);
-               IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
+               IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
                             wrqu->retry.value);
                goto done;
        }
 
        if (wrqu->retry.flags & IW_RETRY_LONG) {
                err = ipw2100_set_long_retry(priv, wrqu->retry.value);
-               IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
+               IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
                             wrqu->retry.value);
                goto done;
        }
@@ -7474,7 +7474,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
        if (!err)
                err = ipw2100_set_long_retry(priv, wrqu->retry.value);
 
-       IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7508,7 +7508,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
                wrqu->retry.value = priv->short_retry_limit;
        }
 
-       IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
 
        return 0;
 }
index 7266730..82de71a 100644 (file)
@@ -459,7 +459,7 @@ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
 {
        u32 word;
        _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
-       IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
+       IPW_DEBUG_IO(" reg = 0x%8X :\n", reg);
        word = _ipw_read32(priv, IPW_INDIRECT_DATA);
        return (word >> ((reg & 0x3) * 8)) & 0xff;
 }
@@ -473,7 +473,7 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
 
        _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
        value = _ipw_read32(priv, IPW_INDIRECT_DATA);
-       IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
+       IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x\n", reg, value);
        return value;
 }
 
@@ -2349,16 +2349,25 @@ static void ipw_bg_adapter_restart(struct work_struct *work)
        mutex_unlock(&priv->mutex);
 }
 
-#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
+static void ipw_abort_scan(struct ipw_priv *priv);
+
+#define IPW_SCAN_CHECK_WATCHDOG        (5 * HZ)
 
 static void ipw_scan_check(void *data)
 {
        struct ipw_priv *priv = data;
-       if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+
+       if (priv->status & STATUS_SCAN_ABORTING) {
                IPW_DEBUG_SCAN("Scan completion watchdog resetting "
                               "adapter after (%dms).\n",
                               jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
                queue_work(priv->workqueue, &priv->adapter_restart);
+       } else if (priv->status & STATUS_SCANNING) {
+               IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
+                              "after (%dms).\n",
+                              jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
+               ipw_abort_scan(priv);
+               queue_delayed_work(priv->workqueue, &priv->scan_check, HZ);
        }
 }
 
@@ -2739,7 +2748,7 @@ static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
 static int ipw_fw_dma_enable(struct ipw_priv *priv)
 {                              /* start dma engine but no transfers yet */
 
-       IPW_DEBUG_FW(">> : \n");
+       IPW_DEBUG_FW(">> :\n");
 
        /* Start the dma */
        ipw_fw_dma_reset_command_blocks(priv);
@@ -2747,7 +2756,7 @@ static int ipw_fw_dma_enable(struct ipw_priv *priv)
        /* Write CB base address */
        ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
 
-       IPW_DEBUG_FW("<< : \n");
+       IPW_DEBUG_FW("<< :\n");
        return 0;
 }
 
@@ -2762,7 +2771,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
        ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
        priv->sram_desc.last_cb_index = 0;
 
-       IPW_DEBUG_FW("<< \n");
+       IPW_DEBUG_FW("<<\n");
 }
 
 static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
@@ -2813,29 +2822,29 @@ static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
 
        IPW_DEBUG_FW(">> :\n");
        address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
-       IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
+       IPW_DEBUG_FW_INFO("Current CB is 0x%x\n", address);
 
        /* Read the DMA Controlor register */
        register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
-       IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x\n", register_value);
 
        /* Print the CB values */
        cb_fields_address = address;
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Control Field is 0x%x\n", register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x\n", register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n",
+       IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x\n",
                          register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x\n", register_value);
 
        IPW_DEBUG_FW(">> :\n");
 }
@@ -2851,7 +2860,7 @@ static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
        current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
            sizeof(struct command_block);
 
-       IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
+       IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X\n",
                          current_cb_index, current_cb_address);
 
        IPW_DEBUG_FW(">> :\n");
@@ -2910,7 +2919,7 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
        int ret, i;
        u32 size;
 
-       IPW_DEBUG_FW(">> \n");
+       IPW_DEBUG_FW(">>\n");
        IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n",
                          nr, dest_address, len);
 
@@ -2927,7 +2936,7 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
                        IPW_DEBUG_FW_INFO(": Added new cb\n");
        }
 
-       IPW_DEBUG_FW("<< \n");
+       IPW_DEBUG_FW("<<\n");
        return 0;
 }
 
@@ -2936,7 +2945,7 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
        u32 current_index = 0, previous_index;
        u32 watchdog = 0;
 
-       IPW_DEBUG_FW(">> : \n");
+       IPW_DEBUG_FW(">> :\n");
 
        current_index = ipw_fw_dma_command_block_index(priv);
        IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
@@ -2965,7 +2974,7 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
        ipw_set_bit(priv, IPW_RESET_REG,
                    IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
 
-       IPW_DEBUG_FW("<< dmaWaitSync \n");
+       IPW_DEBUG_FW("<< dmaWaitSync\n");
        return 0;
 }
 
@@ -3026,7 +3035,7 @@ static int ipw_stop_master(struct ipw_priv *priv)
 {
        int rc;
 
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
        /* stop master. typical delay - 0 */
        ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
 
@@ -3045,7 +3054,7 @@ static int ipw_stop_master(struct ipw_priv *priv)
 
 static void ipw_arc_release(struct ipw_priv *priv)
 {
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
        mdelay(5);
 
        ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
@@ -3067,7 +3076,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 
        image = (__le16 *) data;
 
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
 
        rc = ipw_stop_master(priv);
 
@@ -3181,7 +3190,7 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
        void **virts;
        dma_addr_t *phys;
 
-       IPW_DEBUG_TRACE("<< : \n");
+       IPW_DEBUG_TRACE("<< :\n");
 
        virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL,
                        GFP_KERNEL);
@@ -4482,7 +4491,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        case CMAS_ASSOCIATED:{
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "associated: '%s' %pM \n",
+                                                 "associated: '%s' %pM\n",
                                                  print_ssid(ssid, priv->essid,
                                                             priv->essid_len),
                                                  priv->bssid);
@@ -4563,7 +4572,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                                          IPW_DL_ASSOC,
                                                          "deauthenticated: '%s' "
                                                          "%pM"
-                                                         ": (0x%04X) - %s \n",
+                                                         ": (0x%04X) - %s\n",
                                                          print_ssid(ssid,
                                                                     priv->
                                                                     essid,
@@ -4614,7 +4623,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "disassociated: '%s' %pM \n",
+                                                 "disassociated: '%s' %pM\n",
                                                  print_ssid(ssid, priv->essid,
                                                             priv->essid_len),
                                                  priv->bssid);
@@ -4652,7 +4661,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        switch (auth->state) {
                        case CMAS_AUTHENTICATED:
                                IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-                                         "authenticated: '%s' %pM \n",
+                                         "authenticated: '%s' %pM\n",
                                          print_ssid(ssid, priv->essid,
                                                     priv->essid_len),
                                          priv->bssid);
@@ -6925,7 +6934,7 @@ static u8 ipw_qos_current_mode(struct ipw_priv * priv)
        } else {
                mode = priv->ieee->mode;
        }
-       IPW_DEBUG_QOS("QoS network/card mode %d \n", mode);
+       IPW_DEBUG_QOS("QoS network/card mode %d\n", mode);
        return mode;
 }
 
@@ -6965,7 +6974,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
                               &def_parameters_OFDM, size);
 
                if ((network->qos_data.active == 1) && (active_network == 1)) {
-                       IPW_DEBUG_QOS("QoS was disabled call qos_activate \n");
+                       IPW_DEBUG_QOS("QoS was disabled call qos_activate\n");
                        schedule_work(&priv->qos_activate);
                }
 
@@ -7542,7 +7551,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
                return err;
        }
 
-       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n",
+       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM\n",
                  print_ssid(ssid, priv->essid, priv->essid_len),
                  priv->bssid);
 
@@ -8793,7 +8802,7 @@ static int ipw_wx_set_freq(struct net_device *dev,
                }
        }
 
-       IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+       IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
        mutex_lock(&priv->mutex);
        ret = ipw_set_channel(priv, channel);
        mutex_unlock(&priv->mutex);
@@ -8835,7 +8844,7 @@ static int ipw_wx_get_freq(struct net_device *dev,
                wrqu->freq.m = 0;
 
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
        return 0;
 }
 
@@ -9230,7 +9239,7 @@ static int ipw_wx_get_sens(struct net_device *dev,
        wrqu->sens.value = priv->roaming_threshold;
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET roaming threshold -> %s %d \n",
+       IPW_DEBUG_WX("GET roaming threshold -> %s %d\n",
                     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
 
        return 0;
@@ -9358,7 +9367,7 @@ static int ipw_wx_get_rate(struct net_device *dev,
        wrqu->bitrate.value = priv->last_rate;
        wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+       IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
        return 0;
 }
 
@@ -9381,7 +9390,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
 
        ipw_send_rts_threshold(priv, priv->rts_threshold);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
+       IPW_DEBUG_WX("SET RTS Threshold -> %d\n", priv->rts_threshold);
        return 0;
 }
 
@@ -9395,7 +9404,7 @@ static int ipw_wx_get_rts(struct net_device *dev,
        wrqu->rts.fixed = 0;    /* no auto select */
        wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
+       IPW_DEBUG_WX("GET RTS Threshold -> %d\n", wrqu->rts.value);
        return 0;
 }
 
@@ -9445,7 +9454,7 @@ static int ipw_wx_get_txpow(struct net_device *dev,
        wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET TX Power -> %s %d \n",
+       IPW_DEBUG_WX("GET TX Power -> %s %d\n",
                     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
 
        return 0;
@@ -9471,7 +9480,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
 
        ipw_send_frag_threshold(priv, wrqu->frag.value);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("SET Frag Threshold -> %d\n", wrqu->frag.value);
        return 0;
 }
 
@@ -9485,7 +9494,7 @@ static int ipw_wx_get_frag(struct net_device *dev,
        wrqu->frag.fixed = 0;   /* no auto select */
        wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
 
        return 0;
 }
@@ -9549,7 +9558,7 @@ static int ipw_wx_get_retry(struct net_device *dev,
        }
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("GET retry -> %d\n", wrqu->retry.value);
 
        return 0;
 }
index e31a5cc..a684a72 100644 (file)
@@ -10,6 +10,8 @@ CFLAGS_iwl-devtrace.o := -I$(src)
 # AGN
 obj-$(CONFIG_IWLAGN)   += iwlagn.o
 iwlagn-objs            := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
+iwlagn-objs            += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
+iwlagn-objs            += iwl-agn-lib.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
 iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
index 9e39289..9a0191a 100644 (file)
@@ -44,7 +44,7 @@
 #include "iwl-sta.h"
 #include "iwl-agn.h"
 #include "iwl-helpers.h"
-#include "iwl-5000-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-agn-led.h"
 
 /* Highest firmware API version supported */
@@ -118,7 +118,7 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
 static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -126,13 +126,13 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
-       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+       priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
        priv->hw_params.max_bsm_size = 0;
        priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
@@ -162,25 +162,25 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 
 static struct iwl_lib_ops iwl1000_lib = {
        .set_hw_params = iwl1000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .apm_ops = {
                .init = iwl_apm_init,
@@ -190,25 +190,25 @@ static struct iwl_lib_ops iwl1000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
        .add_bcast_station = iwl_add_bcast_station,
@@ -218,10 +218,10 @@ static struct iwl_lib_ops iwl1000_lib = {
 };
 
 static const struct iwl_ops iwl1000_ops = {
-       .ucode = &iwl5000_ucode,
+       .ucode = &iwlagn_ucode,
        .lib = &iwl1000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
@@ -234,10 +234,10 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .ops = &iwl1000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -253,6 +253,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 128,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
@@ -264,10 +265,10 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .ops = &iwl1000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -282,6 +283,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 128,
 };
 
 MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
index 074f42a..91bcb4e 100644 (file)
 
 #include "iwl-eeprom.h"
 
-/* Time constants */
-#define SHORT_SLOT_TIME 9
-#define LONG_SLOT_TIME 20
-
 /* RSSI to dBm */
 #define IWL39_RSSI_OFFSET      95
 
@@ -230,7 +226,6 @@ struct iwl3945_eeprom {
 
 /* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
 #define IWL39_NUM_QUEUES        5
-#define IWL_NUM_SCAN_RATES         (2)
 
 #define IWL_DEFAULT_TX_RETRY  15
 
index 8f85a0d..32eb470 100644 (file)
@@ -342,7 +342,7 @@ void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 s
        struct ieee80211_supported_band *sband;
        int i;
 
-       IWL_DEBUG_INFO(priv, "enter \n");
+       IWL_DEBUG_INFO(priv, "enter\n");
        if (sta_id == priv->hw_params.bcast_sta_id)
                goto out;
 
@@ -648,7 +648,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
        unsigned long flags;
        u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
        s8 max_rate_idx = -1;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        IWL_DEBUG_RATE(priv, "enter\n");
index 7ac6cec..bde3b4c 100644 (file)
@@ -192,12 +192,12 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
 
 static const char *iwl3945_get_tx_fail_reason(u32 status)
 {
        switch (status & TX_STATUS_MSK) {
-       case TX_STATUS_SUCCESS:
+       case TX_3945_STATUS_SUCCESS:
                return "SUCCESS";
                TX_STATUS_ENTRY(SHORT_LIMIT);
                TX_STATUS_ENTRY(LONG_LIMIT);
@@ -487,7 +487,7 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
                 *    but you can hack it to show more, if you'd like to. */
                if (dataframe)
                        IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
+                                    "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
                                     title, le16_to_cpu(fc), header->addr1[5],
                                     length, rssi, channel, rate);
                else {
@@ -549,7 +549,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
        u16 len = le16_to_cpu(rx_hdr->len);
        struct sk_buff *skb;
-       int ret;
        __le16 fc = hdr->frame_control;
 
        /* We received data from the HW, so stop the watchdog */
@@ -566,9 +565,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                return;
        }
 
-       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
+       skb = dev_alloc_skb(128);
        if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
+               IWL_ERR(priv, "dev_alloc_skb failed\n");
                return;
        }
 
@@ -577,37 +576,13 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                                       (struct ieee80211_hdr *)rxb_addr(rxb),
                                       le32_to_cpu(rx_end->status), stats);
 
-       skb_reserve(skb, IWL_LINK_HDR_MAX);
        skb_add_rx_frag(skb, 0, rxb->page,
                        (void *)rx_hdr->payload - (void *)pkt, len);
 
-       /* mac80211 currently doesn't support paged SKB. Convert it to
-        * linear SKB for management frame and data frame requires
-        * software decryption or software defragementation. */
-       if (ieee80211_is_mgmt(fc) ||
-           ieee80211_has_protected(fc) ||
-           ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
-               ret = skb_linearize(skb);
-       else
-               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
-                       0 : -ENOMEM;
-
-       if (ret) {
-               kfree_skb(skb);
-               goto out;
-       }
-
-       /*
-        * XXX: We cannot touch the page and its virtual memory (pkt) after
-        * here. It might have already been freed by the above skb change.
-        */
-
        iwl_update_stats(priv, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
        ieee80211_rx(priv->hw, skb);
- out:
        priv->alloc_rxb_page--;
        rxb->page = NULL;
 }
@@ -623,9 +598,8 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
-       int snr;
-       u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
-       u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+       u16 rx_stats_sig_avg __maybe_unused = le16_to_cpu(rx_stats->sig_avg);
+       u16 rx_stats_noise_diff __maybe_unused = le16_to_cpu(rx_stats->noise_diff);
        u8 network_packet;
 
        rx_status.flag = 0;
@@ -663,43 +637,19 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        /* Convert 3945's rssi indicator to dBm */
        rx_status.signal = rx_stats->rssi - IWL39_RSSI_OFFSET;
 
-       /* Set default noise value to -127 */
-       if (priv->last_rx_noise == 0)
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-       /* 3945 provides noise info for OFDM frames only.
-        * sig_avg and noise_diff are measured by the 3945's digital signal
-        *   processor (DSP), and indicate linear levels of signal level and
-        *   distortion/noise within the packet preamble after
-        *   automatic gain control (AGC).  sig_avg should stay fairly
-        *   constant if the radio's AGC is working well.
-        * Since these values are linear (not dB or dBm), linear
-        *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
-        * Convert linear SNR to dB SNR, then subtract that from rssi dBm
-        *   to obtain noise level in dBm.
-        * Calculate rx_status.signal (quality indicator in %) based on SNR. */
-       if (rx_stats_noise_diff) {
-               snr = rx_stats_sig_avg / rx_stats_noise_diff;
-               rx_status.noise = rx_status.signal -
-                                       iwl3945_calc_db_from_ratio(snr);
-       } else {
-               rx_status.noise = priv->last_rx_noise;
-       }
-
-
-       IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n",
-                       rx_status.signal, rx_status.noise,
-                       rx_stats_sig_avg, rx_stats_noise_diff);
+       IWL_DEBUG_STATS(priv, "Rssi %d sig_avg %d noise_diff %d\n",
+                       rx_status.signal, rx_stats_sig_avg,
+                       rx_stats_noise_diff);
 
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 
        network_packet = iwl3945_is_network_packet(priv, header);
 
-       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
+       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Rate:%u\n",
                              network_packet ? '*' : ' ',
                              le16_to_cpu(rx_hdr->channel),
                              rx_status.signal, rx_status.signal,
-                             rx_status.noise, rx_status.rate_idx);
+                             rx_status.rate_idx);
 
        /* Set "1" to report good data frames in groups of 100 */
        iwl3945_dbg_report_frame(priv, pkt, header, 1);
@@ -710,7 +660,6 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
                        le32_to_cpu(rx_end->beacon_timestamp);
                priv->_3945.last_tsf = le64_to_cpu(rx_end->timestamp);
                priv->_3945.last_rx_rssi = rx_status.signal;
-               priv->last_rx_noise = rx_status.noise;
        }
 
        iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
@@ -1050,7 +999,7 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
 
        if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
-               IWL_DEBUG_INFO(priv, "RTP type \n");
+               IWL_DEBUG_INFO(priv, "RTP type\n");
        else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
                IWL_DEBUG_INFO(priv, "3945 RADIO-MB type\n");
                iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
@@ -2822,6 +2771,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .broken_powersave = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2841,6 +2791,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .broken_powersave = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
index 67ef562..cd4b61a 100644 (file)
  */
 #define IWL49_FIRST_AMPDU_QUEUE        7
 
-/* Time constants */
-#define SHORT_SLOT_TIME 9
-#define LONG_SLOT_TIME 20
-
-/* RSSI to dBm */
-#define IWL49_RSSI_OFFSET      44
-
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT  0x041
-
-/* PCI register values */
-#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
-#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-#define IWL_DEFAULT_TX_RETRY  15
-
-
 /* Sizes and addresses for instruction and data memory (SRAM) in
  * 4965's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
 #define IWL49_RTC_INST_LOWER_BOUND             (0x000000)
@@ -393,10 +373,6 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
  *     location(s) in command (struct iwl4965_txpowertable_cmd).
  */
 
-/* Limit range of txpower output target to be between these values */
-#define IWL_TX_POWER_TARGET_POWER_MIN       (0)        /* 0 dBm = 1 milliwatt */
-#define IWL_TX_POWER_TARGET_POWER_MAX      (16)        /* 16 dBm */
-
 /**
  * When MIMO is used (2 transmitters operating simultaneously), driver should
  * limit each transmitter to deliver a max of 3 dB below the regulatory limit
index 89aba76..2e3cda7 100644 (file)
@@ -46,6 +46,7 @@
 #include "iwl-calib.h"
 #include "iwl-sta.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn.h"
 
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -60,14 +61,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
 #define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode"
 #define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api)
 
-
-/* module parameters */
-static struct iwl_mod_params iwl4965_mod_params = {
-       .amsdu_size_8K = 1,
-       .restart_fw = 1,
-       /* the rest are 0 by default */
-};
-
 /* check contents of special bootstrap uCode SRAM */
 static int iwl4965_verify_bsm(struct iwl_priv *priv)
 {
@@ -417,7 +410,7 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
                                      sizeof(cmd), &cmd);
                if (ret)
                        IWL_DEBUG_CALIB(priv, "fail sending cmd "
-                                    "REPLY_PHY_CALIBRATION_CMD \n");
+                                    "REPLY_PHY_CALIBRATION_CMD\n");
 
                /* TODO we might want recalculate
                 * rx_chain in rxon cmd */
@@ -1619,19 +1612,19 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
 
        /* get absolute value */
        if (temp_diff < 0) {
-               IWL_DEBUG_POWER(priv, "Getting cooler, delta %d\n", temp_diff);
+               IWL_DEBUG_POWER(priv, "Getting cooler, delta %d\n", temp_diff);
                temp_diff = -temp_diff;
        } else if (temp_diff == 0)
-               IWL_DEBUG_POWER(priv, "Same temp, \n");
+               IWL_DEBUG_POWER(priv, "Temperature unchanged\n");
        else
-               IWL_DEBUG_POWER(priv, "Getting warmer, delta %d\n", temp_diff);
+               IWL_DEBUG_POWER(priv, "Getting warmer, delta %d\n", temp_diff);
 
        if (temp_diff < IWL_TEMPERATURE_THRESHOLD) {
-               IWL_DEBUG_POWER(priv, "Thermal txpower calib not needed\n");
+               IWL_DEBUG_POWER(priv, " => thermal txpower calib not needed\n");
                return 0;
        }
 
-       IWL_DEBUG_POWER(priv, "Thermal txpower calib needed\n");
+       IWL_DEBUG_POWER(priv, " => thermal txpower calib needed\n");
 
        return 1;
 }
@@ -1880,7 +1873,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
+               iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
                /* FIXME: code repetition end */
 
                IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
@@ -2020,7 +2013,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                        index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
                        IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
                                           "%d index %d\n", scd_ssn , index);
-                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+                       freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
                        if (qc)
                                iwl_free_tfds_in_queue(priv, sta_id,
                                                       tid, freed);
@@ -2037,7 +2030,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
        } else {
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv,
+               iwlagn_hwrate_to_tx_control(priv,
                                        le32_to_cpu(tx_resp->rate_n_flags),
                                        info);
 
@@ -2048,7 +2041,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                                   le32_to_cpu(tx_resp->rate_n_flags),
                                   tx_resp->failure_frame);
 
-               freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+               freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
                if (qc && likely(sta_id != IWL_INVALID_STATION))
                        iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
                else if (sta_id == IWL_INVALID_STATION)
@@ -2059,10 +2052,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                        iwl_wake_queue(priv, txq_id);
        }
        if (qc && likely(sta_id != IWL_INVALID_STATION))
-               iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
 
-       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
-               IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
+       iwl_check_abort_status(priv, tx_resp->frame_count, status);
 }
 
 static int iwl4965_calc_rssi(struct iwl_priv *priv,
@@ -2096,7 +2088,7 @@ static int iwl4965_calc_rssi(struct iwl_priv *priv,
 
        /* dBm = max_rssi dB - agc dB - constant.
         * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWL49_RSSI_OFFSET;
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 }
 
 
@@ -2104,7 +2096,7 @@ static int iwl4965_calc_rssi(struct iwl_priv *priv,
 static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
 {
        /* Legacy Rx frames */
-       priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx;
+       priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx;
        /* Tx response */
        priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 }
@@ -2247,7 +2239,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .ops = &iwl4965_ops,
        .num_of_queues = IWL49_NUM_QUEUES,
        .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl4965_mod_params,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = 0,
@@ -2260,27 +2252,11 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .temperature_kelvin = true,
+       .off_channel_workaround = true,
+       .max_event_log_size = 512,
 };
 
 /* Module firmware */
 MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
 
-module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO);
-MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO);
-MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(
-       disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-/* 11n */
-module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-
-module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
index 714e032..146e643 100644 (file)
 #ifndef __iwl_5000_hw_h__
 #define __iwl_5000_hw_h__
 
-#define IWL50_RTC_INST_LOWER_BOUND             (0x000000)
-#define IWL50_RTC_INST_UPPER_BOUND             (0x020000)
-
-#define IWL50_RTC_DATA_LOWER_BOUND             (0x800000)
-#define IWL50_RTC_DATA_UPPER_BOUND             (0x80C000)
-
-#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - \
-                               IWL50_RTC_INST_LOWER_BOUND)
-#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - \
-                               IWL50_RTC_DATA_LOWER_BOUND)
-
-/* EEPROM */
-#define IWL_5000_EEPROM_IMG_SIZE                       2048
-
-#define IWL50_CMD_FIFO_NUM                 7
-#define IWL50_NUM_QUEUES                  20
-#define IWL50_NUM_AMPDU_QUEUES           10
-#define IWL50_FIRST_AMPDU_QUEUE                  10
-
 /* 5150 only */
 #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF  (-5)
 
@@ -103,19 +84,5 @@ static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
        return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
 }
 
-/* Fixed (non-configurable) rx data from phy */
-
-/**
- * struct iwl5000_schedq_bc_tbl scheduler byte count table
- *     base physical address of iwl5000_shared
- *     is provided to SCD_DRAM_BASE_ADDR
- * @tfd_offset  0-12 - tx command byte count
- *            12-16 - station index
- */
-struct iwl5000_scd_bc_tbl {
-       __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __attribute__ ((packed));
-
-
 #endif /* __iwl_5000_hw_h__ */
 
index 2267cad..e967cfc 100644 (file)
@@ -19,6 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -45,8 +46,8 @@
 #include "iwl-helpers.h"
 #include "iwl-agn.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn-hw.h"
 #include "iwl-5000-hw.h"
-#include "iwl-6000-hw.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 2
 #define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
 #define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
 
-static const s8 iwl5000_default_queue_to_tx_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-       IWL50_CMD_FIFO_NUM,
-       IWL_TX_FIFO_UNUSED,
-       IWL_TX_FIFO_UNUSED,
-       IWL_TX_FIFO_UNUSED,
-       IWL_TX_FIFO_UNUSED,
-       IWL_TX_FIFO_UNUSED,
-};
-
 /* NIC configuration for 5000 series */
-void iwl5000_nic_config(struct iwl_priv *priv)
+static void iwl5000_nic_config(struct iwl_priv *priv)
 {
        unsigned long flags;
        u16 radio_cfg;
@@ -111,162 +99,6 @@ void iwl5000_nic_config(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-
-/*
- * EEPROM
- */
-static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
-{
-       u16 offset = 0;
-
-       if ((address & INDIRECT_ADDRESS) == 0)
-               return address;
-
-       switch (address & INDIRECT_TYPE_MSK) {
-       case INDIRECT_HOST:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST);
-               break;
-       case INDIRECT_GENERAL:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL);
-               break;
-       case INDIRECT_REGULATORY:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY);
-               break;
-       case INDIRECT_CALIBRATION:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION);
-               break;
-       case INDIRECT_PROCESS_ADJST:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST);
-               break;
-       case INDIRECT_OTHERS:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS);
-               break;
-       default:
-               IWL_ERR(priv, "illegal indirect type: 0x%X\n",
-               address & INDIRECT_TYPE_MSK);
-               break;
-       }
-
-       /* translate the offset from words to byte */
-       return (address & ADDRESS_MSK) + (offset << 1);
-}
-
-u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
-{
-       struct iwl_eeprom_calib_hdr {
-               u8 version;
-               u8 pa_type;
-               u16 voltage;
-       } *hdr;
-
-       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-                                                       EEPROM_5000_CALIB_ALL);
-       return hdr->version;
-
-}
-
-static void iwl5000_gain_computation(struct iwl_priv *priv,
-               u32 average_noise[NUM_RX_CHAINS],
-               u16 min_average_noise_antenna_i,
-               u32 min_average_noise,
-               u8 default_chain)
-{
-       int i;
-       s32 delta_g;
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-
-       /*
-        * Find Gain Code for the chains based on "default chain"
-        */
-       for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
-               if ((data->disconn_array[i])) {
-                       data->delta_gain_code[i] = 0;
-                       continue;
-               }
-
-               delta_g = (priv->cfg->chain_noise_scale *
-                       ((s32)average_noise[default_chain] -
-                       (s32)average_noise[i])) / 1500;
-
-               /* bound gain by 2 bits value max, 3rd bit is sign */
-               data->delta_gain_code[i] =
-                       min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
-
-               if (delta_g < 0)
-                       /*
-                        * set negative sign ...
-                        * note to Intel developers:  This is uCode API format,
-                        *   not the format of any internal device registers.
-                        *   Do not change this format for e.g. 6050 or similar
-                        *   devices.  Change format only if more resolution
-                        *   (i.e. more than 2 bits magnitude) is needed.
-                        */
-                       data->delta_gain_code[i] |= (1 << 2);
-       }
-
-       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
-                       data->delta_gain_code[1], data->delta_gain_code[2]);
-
-       if (!data->radio_write) {
-               struct iwl_calib_chain_noise_gain_cmd cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
-               cmd.hdr.first_group = 0;
-               cmd.hdr.groups_num = 1;
-               cmd.hdr.data_valid = 1;
-               cmd.delta_gain_1 = data->delta_gain_code[1];
-               cmd.delta_gain_2 = data->delta_gain_code[2];
-               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
-                       sizeof(cmd), &cmd, NULL);
-
-               data->radio_write = 1;
-               data->state = IWL_CHAIN_NOISE_CALIBRATED;
-       }
-
-       data->chain_noise_a = 0;
-       data->chain_noise_b = 0;
-       data->chain_noise_c = 0;
-       data->chain_signal_a = 0;
-       data->chain_signal_b = 0;
-       data->chain_signal_c = 0;
-       data->beacon_count = 0;
-}
-
-static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
-{
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-       int ret;
-
-       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-               struct iwl_calib_chain_noise_reset_cmd cmd;
-               memset(&cmd, 0, sizeof(cmd));
-
-               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
-               cmd.hdr.first_group = 0;
-               cmd.hdr.groups_num = 1;
-               cmd.hdr.data_valid = 1;
-               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-                                       sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv,
-                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
-               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
-       }
-}
-
-void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                       __le32 *tx_flags)
-{
-       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
-           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
-       else
-               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
-}
-
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .min_nrg_cck = 95,
        .max_nrg_cck = 0, /* not used, set to 0 */
@@ -318,14 +150,6 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
-                                          size_t offset)
-{
-       u32 address = eeprom_indirect_address(priv, offset);
-       BUG_ON(address >= priv->cfg->eeprom_size);
-       return &priv->eeprom[address];
-}
-
 static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 {
        const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
@@ -341,351 +165,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
        priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
-/*
- *  Calibration
- */
-static int iwl5000_set_Xtal_calib(struct iwl_priv *priv)
-{
-       struct iwl_calib_xtal_freq_cmd cmd;
-       __le16 *xtal_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
-
-       cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
-       cmd.hdr.first_group = 0;
-       cmd.hdr.groups_num = 1;
-       cmd.hdr.data_valid = 1;
-       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
-       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
-       return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
-                            (u8 *)&cmd, sizeof(cmd));
-}
-
-static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
-{
-       struct iwl_calib_cfg_cmd calib_cfg_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
-       };
-
-       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
-
-       return iwl_send_cmd(priv, &cmd);
-}
-
-static void iwl5000_rx_calib_result(struct iwl_priv *priv,
-                            struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
-       int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       int index;
-
-       /* reduce the size of the length field itself */
-       len -= 4;
-
-       /* Define the order in which the results will be sent to the runtime
-        * uCode. iwl_send_calib_results sends them in a row according to their
-        * index. We sort them here */
-       switch (hdr->op_code) {
-       case IWL_PHY_CALIBRATE_DC_CMD:
-               index = IWL_CALIB_DC;
-               break;
-       case IWL_PHY_CALIBRATE_LO_CMD:
-               index = IWL_CALIB_LO;
-               break;
-       case IWL_PHY_CALIBRATE_TX_IQ_CMD:
-               index = IWL_CALIB_TX_IQ;
-               break;
-       case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
-               index = IWL_CALIB_TX_IQ_PERD;
-               break;
-       case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
-               index = IWL_CALIB_BASE_BAND;
-               break;
-       default:
-               IWL_ERR(priv, "Unknown calibration notification %d\n",
-                         hdr->op_code);
-               return;
-       }
-       iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
-}
-
-static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb)
-{
-       IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
-       queue_work(priv->workqueue, &priv->restart);
-}
-
-/*
- * ucode
- */
-static int iwl5000_load_section(struct iwl_priv *priv, const char *name,
-                               struct fw_desc *image, u32 dst_addr)
-{
-       dma_addr_t phy_addr = image->p_addr;
-       u32 byte_cnt = image->len;
-       int ret;
-
-       priv->ucode_write_complete = 0;
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
-
-       iwl_write_direct32(priv,
-               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
-
-       iwl_write_direct32(priv,
-               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
-               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
-
-       iwl_write_direct32(priv,
-               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-               (iwl_get_dma_hi_addr(phy_addr)
-                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
-               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
-               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
-
-       IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-                                       priv->ucode_write_complete, 5 * HZ);
-       if (ret == -ERESTARTSYS) {
-               IWL_ERR(priv, "Could not load the %s uCode section due "
-                       "to interrupt\n", name);
-               return ret;
-       }
-       if (!ret) {
-               IWL_ERR(priv, "Could not load the %s uCode section\n",
-                       name);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int iwl5000_load_given_ucode(struct iwl_priv *priv,
-               struct fw_desc *inst_image,
-               struct fw_desc *data_image)
-{
-       int ret = 0;
-
-       ret = iwl5000_load_section(priv, "INST", inst_image,
-                                  IWL50_RTC_INST_LOWER_BOUND);
-       if (ret)
-               return ret;
-
-       return iwl5000_load_section(priv, "DATA", data_image,
-                                   IWL50_RTC_DATA_LOWER_BOUND);
-}
-
-int iwl5000_load_ucode(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       /* check whether init ucode should be loaded, or rather runtime ucode */
-       if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
-               IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
-               ret = iwl5000_load_given_ucode(priv,
-                       &priv->ucode_init, &priv->ucode_init_data);
-               if (!ret) {
-                       IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
-                       priv->ucode_type = UCODE_INIT;
-               }
-       } else {
-               IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
-                       "Loading runtime ucode...\n");
-               ret = iwl5000_load_given_ucode(priv,
-                       &priv->ucode_code, &priv->ucode_data);
-               if (!ret) {
-                       IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
-                       priv->ucode_type = UCODE_RT;
-               }
-       }
-
-       return ret;
-}
-
-void iwl5000_init_alive_start(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       /* Check alive response for "valid" sign from uCode */
-       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
-               /* We had an error bringing up the hardware, so take it
-                * all the way back down so we can try again */
-               IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n");
-               goto restart;
-       }
-
-       /* initialize uCode was loaded... verify inst image.
-        * This is a paranoid check, because we would not have gotten the
-        * "initialize" alive if code weren't properly loaded.  */
-       if (iwl_verify_ucode(priv)) {
-               /* Runtime instruction load was bad;
-                * take it all the way back down so we can try again */
-               IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
-               goto restart;
-       }
-
-       ret = priv->cfg->ops->lib->alive_notify(priv);
-       if (ret) {
-               IWL_WARN(priv,
-                       "Could not complete ALIVE transition: %d\n", ret);
-               goto restart;
-       }
-
-       iwl5000_send_calib_cfg(priv);
-       return;
-
-restart:
-       /* real restart (first load init_ucode) */
-       queue_work(priv->workqueue, &priv->restart);
-}
-
-static void iwl5000_set_wr_ptrs(struct iwl_priv *priv,
-                               int txq_id, u32 index)
-{
-       iwl_write_direct32(priv, HBUS_TARG_WRPTR,
-                       (index & 0xff) | (txq_id << 8));
-       iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
-}
-
-static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
-                                       struct iwl_tx_queue *txq,
-                                       int tx_fifo_id, int scd_retry)
-{
-       int txq_id = txq->q.id;
-       int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
-
-       iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
-                       (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                       (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
-                       (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
-                       IWL50_SCD_QUEUE_STTS_REG_MSK);
-
-       txq->sched_retry = scd_retry;
-
-       IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n",
-                      active ? "Activate" : "Deactivate",
-                      scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
-}
-
-int iwl5000_alive_notify(struct iwl_priv *priv)
-{
-       u32 a;
-       unsigned long flags;
-       int i, chan;
-       u32 reg_val;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
-       a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
-       for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
-               a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-       for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
-               a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-       for (; a < priv->scd_base_addr +
-              IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-
-       iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
-                      priv->scd_bc_tbls.dma >> 10);
-
-       /* Enable DMA channel */
-       for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
-               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-       /* Update FH chicken bits */
-       reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
-       iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
-                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-       iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
-               IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
-       iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
-
-       /* initiate the queues */
-       for (i = 0; i < priv->hw_params.max_txq_num; i++) {
-               iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
-               iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
-               iwl_write_targ_mem(priv, priv->scd_base_addr +
-                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
-               iwl_write_targ_mem(priv, priv->scd_base_addr +
-                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
-                               sizeof(u32),
-                               ((SCD_WIN_SIZE <<
-                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                               ((SCD_FRAME_LIMIT <<
-                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-       }
-
-       iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
-                       IWL_MASK(0, priv->hw_params.max_txq_num));
-
-       /* Activate all Tx DMA/FIFO channels */
-       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
-
-       iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
-
-       /* make sure all queue are not stopped */
-       memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
-       for (i = 0; i < 4; i++)
-               atomic_set(&priv->queue_stop_count[i], 0);
-
-       /* reset to 0 to enable all the queue first */
-       priv->txq_ctx_active_msk = 0;
-       /* map qos queues to fifos one-to-one */
-       BUILD_BUG_ON(ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo) != 10);
-
-       for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
-               int ac = iwl5000_default_queue_to_tx_fifo[i];
-
-               iwl_txq_ctx_activate(priv, i);
-
-               if (ac == IWL_TX_FIFO_UNUSED)
-                       continue;
-
-               iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       iwl_send_wimax_coex(priv);
-
-       iwl5000_set_Xtal_calib(priv);
-       iwl_send_calib_results(priv);
-
-       return 0;
-}
-
-int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -693,13 +176,13 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
-       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+       priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
        priv->hw_params.max_bsm_size = 0;
        priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
@@ -740,547 +223,6 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
        return 0;
 }
 
-/**
- * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
- */
-void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
-                                           struct iwl_tx_queue *txq,
-                                           u16 byte_cnt)
-{
-       struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
-       int write_ptr = txq->q.write_ptr;
-       int txq_id = txq->q.id;
-       u8 sec_ctl = 0;
-       u8 sta_id = 0;
-       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
-       __le16 bc_ent;
-
-       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       if (txq_id != IWL_CMD_QUEUE_NUM) {
-               sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
-               sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
-
-               switch (sec_ctl & TX_CMD_SEC_MSK) {
-               case TX_CMD_SEC_CCM:
-                       len += CCMP_MIC_LEN;
-                       break;
-               case TX_CMD_SEC_TKIP:
-                       len += TKIP_ICV_LEN;
-                       break;
-               case TX_CMD_SEC_WEP:
-                       len += WEP_IV_LEN + WEP_ICV_LEN;
-                       break;
-               }
-       }
-
-       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
-
-       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
-
-       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
-}
-
-void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
-                                          struct iwl_tx_queue *txq)
-{
-       struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
-       int txq_id = txq->q.id;
-       int read_ptr = txq->q.read_ptr;
-       u8 sta_id = 0;
-       __le16 bc_ent;
-
-       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       if (txq_id != IWL_CMD_QUEUE_NUM)
-               sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
-
-       bc_ent = cpu_to_le16(1 | (sta_id << 12));
-       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
-
-       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
-}
-
-static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
-                                       u16 txq_id)
-{
-       u32 tbl_dw_addr;
-       u32 tbl_dw;
-       u16 scd_q2ratid;
-
-       scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
-
-       tbl_dw_addr = priv->scd_base_addr +
-                       IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
-
-       tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
-
-       if (txq_id & 0x1)
-               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
-       else
-               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
-
-       iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
-
-       return 0;
-}
-static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
-{
-       /* Simply stop the queue, but don't change any configuration;
-        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-       iwl_write_prph(priv,
-               IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
-int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-                                 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
-{
-       unsigned long flags;
-       u16 ra_tid;
-
-       if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
-               IWL_WARN(priv,
-                       "queue number out of range: %d, must be %d to %d\n",
-                       txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
-               return -EINVAL;
-       }
-
-       ra_tid = BUILD_RAxTID(sta_id, tid);
-
-       /* Modify device's station table to Tx this TID */
-       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Stop this Tx queue before configuring it */
-       iwl5000_tx_queue_stop_scheduler(priv, txq_id);
-
-       /* Map receiver-address / traffic-ID to this queue */
-       iwl5000_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
-
-       /* Set this queue as a chain-building queue */
-       iwl_set_bits_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, (1<<txq_id));
-
-       /* enable aggregations for the queue */
-       iwl_set_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1<<txq_id));
-
-       /* Place first TFD at index corresponding to start sequence number.
-        * Assumes that ssn_idx is valid (!= 0xFFF) */
-       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
-       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
-       iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
-
-       /* Set up Tx window size and frame limit for this queue */
-       iwl_write_targ_mem(priv, priv->scd_base_addr +
-                       IWL50_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
-                       sizeof(u32),
-                       ((SCD_WIN_SIZE <<
-                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                       ((SCD_FRAME_LIMIT <<
-                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       iwl_set_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
-
-       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-                                  u16 ssn_idx, u8 tx_fifo)
-{
-       if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
-               IWL_ERR(priv,
-                       "queue number out of range: %d, must be %d to %d\n",
-                       txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
-               return -EINVAL;
-       }
-
-       iwl5000_tx_queue_stop_scheduler(priv, txq_id);
-
-       iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
-
-       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
-       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
-       /* supposes that ssn_idx is valid (!= 0xFFF) */
-       iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
-
-       iwl_clear_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
-       iwl_txq_ctx_deactivate(priv, txq_id);
-       iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
-
-       return 0;
-}
-
-u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
-{
-       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
-       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
-       memcpy(addsta, cmd, size);
-       /* resrved in 5000 */
-       addsta->rate_n_flags = cpu_to_le16(0);
-       return size;
-}
-
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->lock and mac access
- */
-void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
-{
-       iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
-}
-
-
-static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
-{
-       return le32_to_cpup((__le32 *)&tx_resp->status +
-                           tx_resp->frame_count) & MAX_SN;
-}
-
-static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
-                                     struct iwl_ht_agg *agg,
-                                     struct iwl5000_tx_resp *tx_resp,
-                                     int txq_id, u16 start_idx)
-{
-       u16 status;
-       struct agg_tx_status *frame_status = &tx_resp->status;
-       struct ieee80211_tx_info *info = NULL;
-       struct ieee80211_hdr *hdr = NULL;
-       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-       int i, sh, idx;
-       u16 seq;
-
-       if (agg->wait_for_ba)
-               IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n");
-
-       agg->frame_count = tx_resp->frame_count;
-       agg->start_idx = start_idx;
-       agg->rate_n_flags = rate_n_flags;
-       agg->bitmap = 0;
-
-       /* # frames attempted by Tx command */
-       if (agg->frame_count == 1) {
-               /* Only one frame was attempted; no block-ack will arrive */
-               status = le16_to_cpu(frame_status[0].status);
-               idx = start_idx;
-
-               /* FIXME: code repetition */
-               IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
-                                  agg->frame_count, agg->start_idx, idx);
-
-               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
-
-               /* FIXME: code repetition end */
-
-               IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
-                                   status & 0xff, tx_resp->failure_frame);
-               IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
-
-               agg->wait_for_ba = 0;
-       } else {
-               /* Two or more frames were attempted; expect block-ack */
-               u64 bitmap = 0;
-               int start = agg->start_idx;
-
-               /* Construct bit-map of pending frames within Tx window */
-               for (i = 0; i < agg->frame_count; i++) {
-                       u16 sc;
-                       status = le16_to_cpu(frame_status[i].status);
-                       seq  = le16_to_cpu(frame_status[i].sequence);
-                       idx = SEQ_TO_INDEX(seq);
-                       txq_id = SEQ_TO_QUEUE(seq);
-
-                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
-                                     AGG_TX_STATE_ABORT_MSK))
-                               continue;
-
-                       IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
-                                          agg->frame_count, txq_id, idx);
-
-                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
-                       if (!hdr) {
-                               IWL_ERR(priv,
-                                       "BUG_ON idx doesn't point to valid skb"
-                                       " idx=%d, txq_id=%d\n", idx, txq_id);
-                               return -1;
-                       }
-
-                       sc = le16_to_cpu(hdr->seq_ctrl);
-                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-                               IWL_ERR(priv,
-                                       "BUG_ON idx doesn't match seq control"
-                                       " idx=%d, seq_idx=%d, seq=%d\n",
-                                         idx, SEQ_TO_SN(sc),
-                                         hdr->seq_ctrl);
-                               return -1;
-                       }
-
-                       IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
-                                          i, idx, SEQ_TO_SN(sc));
-
-                       sh = idx - start;
-                       if (sh > 64) {
-                               sh = (start - idx) + 0xff;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                               start = idx;
-                       } else if (sh < -64)
-                               sh  = 0xff - (start - idx);
-                       else if (sh < 0) {
-                               sh = start - idx;
-                               start = idx;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                       }
-                       bitmap |= 1ULL << sh;
-                       IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
-                                          start, (unsigned long long)bitmap);
-               }
-
-               agg->bitmap = bitmap;
-               agg->start_idx = start;
-               IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
-                                  agg->frame_count, agg->start_idx,
-                                  (unsigned long long)agg->bitmap);
-
-               if (bitmap)
-                       agg->wait_for_ba = 1;
-       }
-       return 0;
-}
-
-static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int index = SEQ_TO_INDEX(sequence);
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct ieee80211_tx_info *info;
-       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-       u32  status = le16_to_cpu(tx_resp->status.status);
-       int tid;
-       int sta_id;
-       int freed;
-
-       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
-                         "is out of range [0-%d] %d %d\n", txq_id,
-                         index, txq->q.n_bd, txq->q.write_ptr,
-                         txq->q.read_ptr);
-               return;
-       }
-
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
-       memset(&info->status, 0, sizeof(info->status));
-
-       tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
-       sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
-
-       if (txq->sched_retry) {
-               const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
-               struct iwl_ht_agg *agg = NULL;
-
-               agg = &priv->stations[sta_id].tid[tid].agg;
-
-               iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
-
-               /* check if BAR is needed */
-               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
-                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
-               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-                       IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim "
-                                       "scd_ssn=%d idx=%d txq=%d swq=%d\n",
-                                       scd_ssn , index, txq_id, txq->swq_id);
-
-                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-                       if (priv->mac80211_registered &&
-                           (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
-                           (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
-                               if (agg->state == IWL_AGG_OFF)
-                                       iwl_wake_queue(priv, txq_id);
-                               else
-                                       iwl_wake_queue(priv, txq->swq_id);
-                       }
-               }
-       } else {
-               BUG_ON(txq_id != txq->swq_id);
-
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv,
-                                       le32_to_cpu(tx_resp->rate_n_flags),
-                                       info);
-
-               IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
-                                  "0x%x retries %d\n",
-                                  txq_id,
-                                  iwl_get_tx_fail_reason(status), status,
-                                  le32_to_cpu(tx_resp->rate_n_flags),
-                                  tx_resp->failure_frame);
-
-               freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-               if (priv->mac80211_registered &&
-                   (iwl_queue_space(&txq->q) > txq->q.low_mark))
-                       iwl_wake_queue(priv, txq_id);
-       }
-
-       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
-
-       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
-               IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
-}
-
-/* Currently 5000 is the superset of everything */
-u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
-{
-       return len;
-}
-
-void iwl5000_setup_deferred_work(struct iwl_priv *priv)
-{
-       /* in 5000 the tx power calibration is done in uCode */
-       priv->disable_tx_power_cal = 1;
-}
-
-void iwl5000_rx_handler_setup(struct iwl_priv *priv)
-{
-       /* init calibration handlers */
-       priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
-                                       iwl5000_rx_calib_result;
-       priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
-                                       iwl5000_rx_calib_complete;
-       priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx;
-}
-
-
-int iwl5000_hw_valid_rtc_data_addr(u32 addr)
-{
-       return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
-               (addr < IWL50_RTC_DATA_UPPER_BOUND);
-}
-
-static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
-{
-       int ret = 0;
-       struct iwl5000_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
-
-       if ((rxon1->flags == rxon2->flags) &&
-           (rxon1->filter_flags == rxon2->filter_flags) &&
-           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-           (rxon1->ofdm_ht_single_stream_basic_rates ==
-            rxon2->ofdm_ht_single_stream_basic_rates) &&
-           (rxon1->ofdm_ht_dual_stream_basic_rates ==
-            rxon2->ofdm_ht_dual_stream_basic_rates) &&
-           (rxon1->ofdm_ht_triple_stream_basic_rates ==
-            rxon2->ofdm_ht_triple_stream_basic_rates) &&
-           (rxon1->acquisition_data == rxon2->acquisition_data) &&
-           (rxon1->rx_chain == rxon2->rx_chain) &&
-           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
-               return 0;
-       }
-
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
-       rxon_assoc.reserved1 = 0;
-       rxon_assoc.reserved2 = 0;
-       rxon_assoc.reserved3 = 0;
-       rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
-       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
-       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
-       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
-
-       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
-                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-int  iwl5000_send_tx_power(struct iwl_priv *priv)
-{
-       struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
-       u8 tx_ant_cfg_cmd;
-
-       /* half dBm need to multiply */
-       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
-
-       if (priv->tx_power_lmt_in_half_dbm &&
-           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
-               /*
-                * For the newer devices which using enhanced/extend tx power
-                * table in EEPROM, the format is in half dBm. driver need to
-                * convert to dBm format before report to mac80211.
-                * By doing so, there is a possibility of 1/2 dBm resolution
-                * lost. driver will perform "round-up" operation before
-                * reporting, but it will cause 1/2 dBm tx power over the
-                * regulatory limit. Perform the checking here, if the
-                * "tx_power_user_lmt" is higher than EEPROM value (in
-                * half-dBm format), lower the tx power based on EEPROM
-                */
-               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
-       }
-       tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
-       tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
-
-       if (IWL_UCODE_API(priv->ucode_ver) == 1)
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
-       else
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
-
-       return  iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
-                                      sizeof(tx_power_cmd), &tx_power_cmd,
-                                      NULL);
-}
-
-void iwl5000_temperature(struct iwl_priv *priv)
-{
-       /* store temperature from statistics (in Celsius) */
-       priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
-       iwl_tt_handler(priv);
-}
-
 static void iwl5150_temperature(struct iwl_priv *priv)
 {
        u32 vt = 0;
@@ -1293,100 +235,6 @@ static void iwl5150_temperature(struct iwl_priv *priv)
        iwl_tt_handler(priv);
 }
 
-/* Calc max signal level (dBm) among 3 possible receivers */
-int iwl5000_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp)
-{
-       /* data from PHY/DSP regarding signal strength, etc.,
-        *   contents are always there, not configurable by host
-        */
-       struct iwl5000_non_cfg_phy *ncphy =
-               (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
-       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
-       u8 agc;
-
-       val  = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
-       agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
-
-       /* Find max rssi among 3 possible receivers.
-        * These values are measured by the digital signal processor (DSP).
-        * They should stay fairly constant even as the signal strength varies,
-        *   if the radio's automatic gain control (AGC) is working right.
-        * AGC value (see below) will provide the "interesting" info.
-        */
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
-       rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
-       rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
-       rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
-
-       max_rssi = max_t(u32, rssi_a, rssi_b);
-       max_rssi = max_t(u32, max_rssi, rssi_c);
-
-       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
-               rssi_a, rssi_b, rssi_c, max_rssi, agc);
-
-       /* dBm = max_rssi dB - agc dB - constant.
-        * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWL49_RSSI_OFFSET;
-}
-
-static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
-{
-       struct iwl_tx_ant_config_cmd tx_ant_cmd = {
-         .valid = cpu_to_le32(valid_tx_ant),
-       };
-
-       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
-               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
-                                       sizeof(struct iwl_tx_ant_config_cmd),
-                                       &tx_ant_cmd);
-       } else {
-               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
-               return -EOPNOTSUPP;
-       }
-}
-
-
-#define IWL5000_UCODE_GET(item)                                                \
-static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       if (api_ver <= 2)                                               \
-               return le32_to_cpu(ucode->u.v1.item);                   \
-       return le32_to_cpu(ucode->u.v2.item);                           \
-}
-
-static u32 iwl5000_ucode_get_header_size(u32 api_ver)
-{
-       if (api_ver <= 2)
-               return UCODE_HEADER_SIZE(1);
-       return UCODE_HEADER_SIZE(2);
-}
-
-static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       if (api_ver <= 2)
-               return 0;
-       return le32_to_cpu(ucode->u.v2.build);
-}
-
-static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       if (api_ver <= 2)
-               return (u8 *) ucode->u.v1.data;
-       return (u8 *) ucode->u.v2.data;
-}
-
-IWL5000_UCODE_GET(inst_size);
-IWL5000_UCODE_GET(data_size);
-IWL5000_UCODE_GET(init_size);
-IWL5000_UCODE_GET(init_data_size);
-IWL5000_UCODE_GET(boot_size);
-
 static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 {
        struct iwl5000_channel_switch_cmd cmd;
@@ -1419,54 +267,27 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
        return iwl_send_cmd_sync(priv, &hcmd);
 }
 
-struct iwl_hcmd_ops iwl5000_hcmd = {
-       .rxon_assoc = iwl5000_send_rxon_assoc,
-       .commit_rxon = iwl_commit_rxon,
-       .set_rxon_chain = iwl_set_rxon_chain,
-       .set_tx_ant = iwl5000_send_tx_ant_config,
-};
-
-struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
-       .get_hcmd_size = iwl5000_get_hcmd_size,
-       .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
-       .gain_computation = iwl5000_gain_computation,
-       .chain_noise_reset = iwl5000_chain_noise_reset,
-       .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
-       .calc_rssi = iwl5000_calc_rssi,
-};
-
-struct iwl_ucode_ops iwl5000_ucode = {
-       .get_header_size = iwl5000_ucode_get_header_size,
-       .get_build = iwl5000_ucode_get_build,
-       .get_inst_size = iwl5000_ucode_get_inst_size,
-       .get_data_size = iwl5000_ucode_get_data_size,
-       .get_init_size = iwl5000_ucode_get_init_size,
-       .get_init_data_size = iwl5000_ucode_get_init_data_size,
-       .get_boot_size = iwl5000_ucode_get_boot_size,
-       .get_data = iwl5000_ucode_get_data,
-};
-
-struct iwl_lib_ops iwl5000_lib = {
+static struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .load_ucode = iwl5000_load_ucode,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .load_ucode = iwlagn_load_ucode,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -1477,25 +298,25 @@ struct iwl_lib_ops iwl5000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
        .add_bcast_station = iwl_add_bcast_station,
@@ -1506,24 +327,24 @@ struct iwl_lib_ops iwl5000_lib = {
 
 static struct iwl_lib_ops iwl5150_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
-       .load_ucode = iwl5000_load_ucode,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .load_ucode = iwlagn_load_ucode,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -1534,19 +355,19 @@ static struct iwl_lib_ops iwl5150_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
@@ -1562,28 +383,21 @@ static struct iwl_lib_ops iwl5150_lib = {
 };
 
 static const struct iwl_ops iwl5000_ops = {
-       .ucode = &iwl5000_ucode,
+       .ucode = &iwlagn_ucode,
        .lib = &iwl5000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 static const struct iwl_ops iwl5150_ops = {
-       .ucode = &iwl5000_ucode,
+       .ucode = &iwlagn_ucode,
        .lib = &iwl5150_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_mod_params iwl50_mod_params = {
-       .amsdu_size_8K = 1,
-       .restart_fw = 1,
-       /* the rest are 0 by default */
-};
-
-
 struct iwl_cfg iwl5300_agn_cfg = {
        .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
        .fw_name_pre = IWL5000_FW_PRE,
@@ -1591,12 +405,12 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1609,6 +423,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1618,12 +433,12 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1636,6 +451,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -1645,12 +461,12 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1661,6 +477,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -1670,12 +487,12 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1688,6 +505,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1697,12 +515,12 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1715,6 +533,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1724,12 +543,12 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5150_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1742,6 +561,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
@@ -1751,12 +571,12 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
        .ops = &iwl5150_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1767,20 +587,8 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
-
-module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO);
-MODULE_PARM_DESC(swcrypto50,
-                 "using software crypto engine (default 0 [hardware])\n");
-module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
-module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
-module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
index d757999..dd03384 100644 (file)
@@ -44,7 +44,7 @@
 #include "iwl-sta.h"
 #include "iwl-agn.h"
 #include "iwl-helpers.h"
-#include "iwl-5000-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
 #include "iwl-agn-led.h"
 
@@ -57,6 +57,7 @@
 #define IWL6050_UCODE_API_MIN 4
 
 #define IWL6000_FW_PRE "iwlwifi-6000-"
+#define IWL6000_G2_FW_PRE "iwlwifi-6005-"
 #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
 #define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api)
 
@@ -137,7 +138,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
 static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -145,7 +146,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
@@ -226,25 +227,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 
 static struct iwl_lib_ops iwl6000_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -255,26 +256,26 @@ static struct iwl_lib_ops iwl6000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
         },
        .add_bcast_station = iwl_add_bcast_station,
@@ -284,34 +285,34 @@ static struct iwl_lib_ops iwl6000_lib = {
 };
 
 static const struct iwl_ops iwl6000_ops = {
-       .ucode = &iwl5000_ucode,
+       .ucode = &iwlagn_ucode,
        .lib = &iwl6000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 static struct iwl_lib_ops iwl6050_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -322,26 +323,26 @@ static struct iwl_lib_ops iwl6050_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
                .set_calib_version = iwl6050_set_calib_version,
         },
@@ -352,16 +353,50 @@ static struct iwl_lib_ops iwl6050_lib = {
 };
 
 static const struct iwl_ops iwl6050_ops = {
-       .ucode = &iwl5000_ucode,
+       .ucode = &iwlagn_ucode,
        .lib = &iwl6050_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 /*
  * "i": Internal configuration, use internal Power Amplifier
  */
+struct iwl_cfg iwl6000i_g2_2agn_cfg = {
+       .name = "6000 Series 2x2 AGN Gen2",
+       .fw_name_pre = IWL6000_G2_FW_PRE,
+       .ucode_api_max = IWL6000_UCODE_API_MAX,
+       .ucode_api_min = IWL6000_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = 0,
+       .set_l0s = true,
+       .use_bsm = false,
+       .pa_type = IWL_PA_INTERNAL,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .supports_idle = true,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+};
+
 struct iwl_cfg iwl6000i_2agn_cfg = {
        .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
        .fw_name_pre = IWL6000_FW_PRE,
@@ -371,10 +406,10 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -393,6 +428,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -404,10 +440,10 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -425,6 +461,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -436,10 +473,10 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -457,6 +494,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
@@ -468,10 +506,10 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .ops = &iwl6050_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
@@ -490,6 +528,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1500,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -501,10 +540,10 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .ops = &iwl6050_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
@@ -522,6 +561,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1500,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -533,10 +573,10 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = 0,
@@ -555,6 +595,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
new file mode 100644 (file)
index 0000000..28bc8f8
--- /dev/null
@@ -0,0 +1,274 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn.h"
+
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+{
+       int ret = 0;
+       struct iwl5000_rxon_assoc_cmd rxon_assoc;
+       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+       if ((rxon1->flags == rxon2->flags) &&
+           (rxon1->filter_flags == rxon2->filter_flags) &&
+           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+           (rxon1->ofdm_ht_single_stream_basic_rates ==
+            rxon2->ofdm_ht_single_stream_basic_rates) &&
+           (rxon1->ofdm_ht_dual_stream_basic_rates ==
+            rxon2->ofdm_ht_dual_stream_basic_rates) &&
+           (rxon1->ofdm_ht_triple_stream_basic_rates ==
+            rxon2->ofdm_ht_triple_stream_basic_rates) &&
+           (rxon1->acquisition_data == rxon2->acquisition_data) &&
+           (rxon1->rx_chain == rxon2->rx_chain) &&
+           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
+               return 0;
+       }
+
+       rxon_assoc.flags = priv->staging_rxon.flags;
+       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.reserved1 = 0;
+       rxon_assoc.reserved2 = 0;
+       rxon_assoc.reserved3 = 0;
+       rxon_assoc.ofdm_ht_single_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+
+       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+{
+       struct iwl_tx_ant_config_cmd tx_ant_cmd = {
+         .valid = cpu_to_le32(valid_tx_ant),
+       };
+
+       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+                                       sizeof(struct iwl_tx_ant_config_cmd),
+                                       &tx_ant_cmd);
+       } else {
+               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+/* Currently this is the superset of everything */
+static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len)
+{
+       return len;
+}
+
+static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
+       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+       memcpy(addsta, cmd, size);
+       /* resrved in 5000 */
+       addsta->rate_n_flags = cpu_to_le16(0);
+       return size;
+}
+
+static void iwlagn_gain_computation(struct iwl_priv *priv,
+               u32 average_noise[NUM_RX_CHAINS],
+               u16 min_average_noise_antenna_i,
+               u32 min_average_noise,
+               u8 default_chain)
+{
+       int i;
+       s32 delta_g;
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+       /*
+        * Find Gain Code for the chains based on "default chain"
+        */
+       for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
+               if ((data->disconn_array[i])) {
+                       data->delta_gain_code[i] = 0;
+                       continue;
+               }
+
+               delta_g = (priv->cfg->chain_noise_scale *
+                       ((s32)average_noise[default_chain] -
+                       (s32)average_noise[i])) / 1500;
+
+               /* bound gain by 2 bits value max, 3rd bit is sign */
+               data->delta_gain_code[i] =
+                       min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+               if (delta_g < 0)
+                       /*
+                        * set negative sign ...
+                        * note to Intel developers:  This is uCode API format,
+                        *   not the format of any internal device registers.
+                        *   Do not change this format for e.g. 6050 or similar
+                        *   devices.  Change format only if more resolution
+                        *   (i.e. more than 2 bits magnitude) is needed.
+                        */
+                       data->delta_gain_code[i] |= (1 << 2);
+       }
+
+       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
+                       data->delta_gain_code[1], data->delta_gain_code[2]);
+
+       if (!data->radio_write) {
+               struct iwl_calib_chain_noise_gain_cmd cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+               cmd.hdr.first_group = 0;
+               cmd.hdr.groups_num = 1;
+               cmd.hdr.data_valid = 1;
+               cmd.delta_gain_1 = data->delta_gain_code[1];
+               cmd.delta_gain_2 = data->delta_gain_code[2];
+               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
+                       sizeof(cmd), &cmd, NULL);
+
+               data->radio_write = 1;
+               data->state = IWL_CHAIN_NOISE_CALIBRATED;
+       }
+
+       data->chain_noise_a = 0;
+       data->chain_noise_b = 0;
+       data->chain_noise_c = 0;
+       data->chain_signal_a = 0;
+       data->chain_signal_b = 0;
+       data->chain_signal_c = 0;
+       data->beacon_count = 0;
+}
+
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+       int ret;
+
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+               struct iwl_calib_chain_noise_reset_cmd cmd;
+               memset(&cmd, 0, sizeof(cmd));
+
+               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+               cmd.hdr.first_group = 0;
+               cmd.hdr.groups_num = 1;
+               cmd.hdr.data_valid = 1;
+               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                                       sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv,
+                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+       }
+}
+
+static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+                       __le32 *tx_flags)
+{
+       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+       else
+               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwlagn_calc_rssi(struct iwl_priv *priv,
+                            struct iwl_rx_phy_res *rx_resp)
+{
+       /* data from PHY/DSP regarding signal strength, etc.,
+        *   contents are always there, not configurable by host
+        */
+       struct iwl5000_non_cfg_phy *ncphy =
+               (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+       u8 agc;
+
+       val  = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
+       agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
+
+       /* Find max rssi among 3 possible receivers.
+        * These values are measured by the digital signal processor (DSP).
+        * They should stay fairly constant even as the signal strength varies,
+        *   if the radio's automatic gain control (AGC) is working right.
+        * AGC value (see below) will provide the "interesting" info.
+        */
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
+       rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
+       rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
+       rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
+
+       max_rssi = max_t(u32, rssi_a, rssi_b);
+       max_rssi = max_t(u32, max_rssi, rssi_c);
+
+       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+               rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+       /* dBm = max_rssi dB - agc dB - constant.
+        * Higher AGC (higher radio gain) means lower signal. */
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
+}
+
+struct iwl_hcmd_ops iwlagn_hcmd = {
+       .rxon_assoc = iwlagn_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+       .set_tx_ant = iwlagn_send_tx_ant_config,
+};
+
+struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
+       .get_hcmd_size = iwlagn_get_hcmd_size,
+       .build_addsta_hcmd = iwlagn_build_addsta_hcmd,
+       .gain_computation = iwlagn_gain_computation,
+       .chain_noise_reset = iwlagn_chain_noise_reset,
+       .rts_tx_cmd_flag = iwlagn_rts_tx_cmd_flag,
+       .calc_rssi = iwlagn_calc_rssi,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
new file mode 100644 (file)
index 0000000..f9a3fbb
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-agn-hw.h) only for hardware-related definitions.
+ */
+
+#ifndef __iwl_agn_hw_h__
+#define __iwl_agn_hw_h__
+
+#define IWLAGN_RTC_INST_LOWER_BOUND            (0x000000)
+#define IWLAGN_RTC_INST_UPPER_BOUND            (0x020000)
+
+#define IWLAGN_RTC_DATA_LOWER_BOUND            (0x800000)
+#define IWLAGN_RTC_DATA_UPPER_BOUND            (0x80C000)
+
+#define IWLAGN_RTC_INST_SIZE (IWLAGN_RTC_INST_UPPER_BOUND - \
+                               IWLAGN_RTC_INST_LOWER_BOUND)
+#define IWLAGN_RTC_DATA_SIZE (IWLAGN_RTC_DATA_UPPER_BOUND - \
+                               IWLAGN_RTC_DATA_LOWER_BOUND)
+
+/* RSSI to dBm */
+#define IWLAGN_RSSI_OFFSET     44
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT  0x041
+
+/* PCI register values */
+#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
+#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
+
+#define IWLAGN_DEFAULT_TX_RETRY  15
+
+/* Limit range of txpower output target to be between these values */
+#define IWLAGN_TX_POWER_TARGET_POWER_MIN       (0)     /* 0 dBm: 1 milliwatt */
+#define IWLAGN_TX_POWER_TARGET_POWER_MAX       (16)    /* 16 dBm */
+
+/* EEPROM */
+#define IWLAGN_EEPROM_IMG_SIZE         2048
+
+#define IWLAGN_CMD_FIFO_NUM            7
+#define IWLAGN_NUM_QUEUES              20
+#define IWLAGN_NUM_AMPDU_QUEUES                10
+#define IWLAGN_FIRST_AMPDU_QUEUE       10
+
+/* Fixed (non-configurable) rx data from phy */
+
+/**
+ * struct iwlagn_schedq_bc_tbl scheduler byte count table
+ *     base physical address provided by SCD_DRAM_BASE_ADDR
+ * @tfd_offset  0-12 - tx command byte count
+ *            12-16 - station index
+ */
+struct iwlagn_scd_bc_tbl {
+       __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
+} __attribute__ ((packed));
+
+
+#endif /* __iwl_agn_hw_h__ */
index 4c5395e..a273e37 100644 (file)
@@ -141,13 +141,14 @@ static irqreturn_t iwl_isr(int irq, void *data)
 {
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
+       unsigned long flags;
 #ifdef CONFIG_IWLWIFI_DEBUG
        u32 inta_fh;
 #endif
        if (!priv)
                return IRQ_NONE;
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         *    back-to-back ISRs and sporadic interrupts from our NIC.
@@ -190,7 +191,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
                iwl_enable_interrupts(priv);
 
  unplugged:
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_HANDLED;
 
  none:
@@ -199,7 +200,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
        if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
                iwl_enable_interrupts(priv);
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_NONE;
 }
 
@@ -216,6 +217,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
        u32 val = 0;
+       unsigned long flags;
 
        if (!priv)
                return IRQ_NONE;
@@ -226,7 +228,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        if (!priv->_agn.use_ict)
                return iwl_isr(irq, data);
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         * back-to-back ISRs and sporadic interrupts from our NIC.
@@ -290,7 +292,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
                iwl_enable_interrupts(priv);
        }
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_HANDLED;
 
  none:
@@ -300,6 +302,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
                iwl_enable_interrupts(priv);
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_NONE;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
new file mode 100644 (file)
index 0000000..c465c85
--- /dev/null
@@ -0,0 +1,1113 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+{
+       return le32_to_cpup((__le32 *)&tx_resp->status +
+                           tx_resp->frame_count) & MAX_SN;
+}
+
+static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
+                                     struct iwl_ht_agg *agg,
+                                     struct iwl5000_tx_resp *tx_resp,
+                                     int txq_id, u16 start_idx)
+{
+       u16 status;
+       struct agg_tx_status *frame_status = &tx_resp->status;
+       struct ieee80211_tx_info *info = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       int i, sh, idx;
+       u16 seq;
+
+       if (agg->wait_for_ba)
+               IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n");
+
+       agg->frame_count = tx_resp->frame_count;
+       agg->start_idx = start_idx;
+       agg->rate_n_flags = rate_n_flags;
+       agg->bitmap = 0;
+
+       /* # frames attempted by Tx command */
+       if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
+               status = le16_to_cpu(frame_status[0].status);
+               idx = start_idx;
+
+               /* FIXME: code repetition */
+               IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
+                                  agg->frame_count, agg->start_idx, idx);
+
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_tx_status_to_mac80211(status);
+               iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
+
+               /* FIXME: code repetition end */
+
+               IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
+                                   status & 0xff, tx_resp->failure_frame);
+               IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
+
+               agg->wait_for_ba = 0;
+       } else {
+               /* Two or more frames were attempted; expect block-ack */
+               u64 bitmap = 0;
+               int start = agg->start_idx;
+
+               /* Construct bit-map of pending frames within Tx window */
+               for (i = 0; i < agg->frame_count; i++) {
+                       u16 sc;
+                       status = le16_to_cpu(frame_status[i].status);
+                       seq  = le16_to_cpu(frame_status[i].sequence);
+                       idx = SEQ_TO_INDEX(seq);
+                       txq_id = SEQ_TO_QUEUE(seq);
+
+                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+                                     AGG_TX_STATE_ABORT_MSK))
+                               continue;
+
+                       IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
+                                          agg->frame_count, txq_id, idx);
+
+                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+                       if (!hdr) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't point to valid skb"
+                                       " idx=%d, txq_id=%d\n", idx, txq_id);
+                               return -1;
+                       }
+
+                       sc = le16_to_cpu(hdr->seq_ctrl);
+                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't match seq control"
+                                       " idx=%d, seq_idx=%d, seq=%d\n",
+                                         idx, SEQ_TO_SN(sc),
+                                         hdr->seq_ctrl);
+                               return -1;
+                       }
+
+                       IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
+                                          i, idx, SEQ_TO_SN(sc));
+
+                       sh = idx - start;
+                       if (sh > 64) {
+                               sh = (start - idx) + 0xff;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                               start = idx;
+                       } else if (sh < -64)
+                               sh  = 0xff - (start - idx);
+                       else if (sh < 0) {
+                               sh = start - idx;
+                               start = idx;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                       }
+                       bitmap |= 1ULL << sh;
+                       IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
+                                          start, (unsigned long long)bitmap);
+               }
+
+               agg->bitmap = bitmap;
+               agg->start_idx = start;
+               IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
+                                  agg->frame_count, agg->start_idx,
+                                  (unsigned long long)agg->bitmap);
+
+               if (bitmap)
+                       agg->wait_for_ba = 1;
+       }
+       return 0;
+}
+
+void iwl_check_abort_status(struct iwl_priv *priv,
+                           u8 frame_count, u32 status)
+{
+       if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
+               IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
+       }
+}
+
+static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int index = SEQ_TO_INDEX(sequence);
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct ieee80211_tx_info *info;
+       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32  status = le16_to_cpu(tx_resp->status.status);
+       int tid;
+       int sta_id;
+       int freed;
+
+       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+               IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
+                         "is out of range [0-%d] %d %d\n", txq_id,
+                         index, txq->q.n_bd, txq->q.write_ptr,
+                         txq->q.read_ptr);
+               return;
+       }
+
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+
+       tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
+       sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+
+       if (txq->sched_retry) {
+               const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
+               struct iwl_ht_agg *agg = NULL;
+
+               agg = &priv->stations[sta_id].tid[tid].agg;
+
+               iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
+
+               /* check if BAR is needed */
+               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
+                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+
+               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+                       IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim "
+                                       "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+                                       scd_ssn , index, txq_id, txq->swq_id);
+
+                       freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+                       if (priv->mac80211_registered &&
+                           (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+                           (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
+                               if (agg->state == IWL_AGG_OFF)
+                                       iwl_wake_queue(priv, txq_id);
+                               else
+                                       iwl_wake_queue(priv, txq->swq_id);
+                       }
+               }
+       } else {
+               BUG_ON(txq_id != txq->swq_id);
+
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags |= iwl_tx_status_to_mac80211(status);
+               iwlagn_hwrate_to_tx_control(priv,
+                                       le32_to_cpu(tx_resp->rate_n_flags),
+                                       info);
+
+               IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
+                                  "0x%x retries %d\n",
+                                  txq_id,
+                                  iwl_get_tx_fail_reason(status), status,
+                                  le32_to_cpu(tx_resp->rate_n_flags),
+                                  tx_resp->failure_frame);
+
+               freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+               if (priv->mac80211_registered &&
+                   (iwl_queue_space(&txq->q) > txq->q.low_mark))
+                       iwl_wake_queue(priv, txq_id);
+       }
+
+       iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
+
+       iwl_check_abort_status(priv, tx_resp->frame_count, status);
+}
+
+void iwlagn_rx_handler_setup(struct iwl_priv *priv)
+{
+       /* init calibration handlers */
+       priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
+                                       iwlagn_rx_calib_result;
+       priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
+                                       iwlagn_rx_calib_complete;
+       priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
+}
+
+void iwlagn_setup_deferred_work(struct iwl_priv *priv)
+{
+       /* in agn, the tx power calibration is done in uCode */
+       priv->disable_tx_power_cal = 1;
+}
+
+int iwlagn_hw_valid_rtc_data_addr(u32 addr)
+{
+       return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
+               (addr < IWLAGN_RTC_DATA_UPPER_BOUND);
+}
+
+int iwlagn_send_tx_power(struct iwl_priv *priv)
+{
+       struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
+       u8 tx_ant_cfg_cmd;
+
+       /* half dBm need to multiply */
+       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+       if (priv->tx_power_lmt_in_half_dbm &&
+           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
+               /*
+                * For the newer devices which using enhanced/extend tx power
+                * table in EEPROM, the format is in half dBm. driver need to
+                * convert to dBm format before report to mac80211.
+                * By doing so, there is a possibility of 1/2 dBm resolution
+                * lost. driver will perform "round-up" operation before
+                * reporting, but it will cause 1/2 dBm tx power over the
+                * regulatory limit. Perform the checking here, if the
+                * "tx_power_user_lmt" is higher than EEPROM value (in
+                * half-dBm format), lower the tx power based on EEPROM
+                */
+               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
+       }
+       tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
+       tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
+
+       if (IWL_UCODE_API(priv->ucode_ver) == 1)
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
+       else
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
+
+       return  iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
+                                      sizeof(tx_power_cmd), &tx_power_cmd,
+                                      NULL);
+}
+
+void iwlagn_temperature(struct iwl_priv *priv)
+{
+       /* store temperature from statistics (in Celsius) */
+       priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+       iwl_tt_handler(priv);
+}
+
+u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv)
+{
+       struct iwl_eeprom_calib_hdr {
+               u8 version;
+               u8 pa_type;
+               u16 voltage;
+       } *hdr;
+
+       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
+                                                       EEPROM_5000_CALIB_ALL);
+       return hdr->version;
+
+}
+
+/*
+ * EEPROM
+ */
+static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
+{
+       u16 offset = 0;
+
+       if ((address & INDIRECT_ADDRESS) == 0)
+               return address;
+
+       switch (address & INDIRECT_TYPE_MSK) {
+       case INDIRECT_HOST:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST);
+               break;
+       case INDIRECT_GENERAL:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL);
+               break;
+       case INDIRECT_REGULATORY:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY);
+               break;
+       case INDIRECT_CALIBRATION:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION);
+               break;
+       case INDIRECT_PROCESS_ADJST:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST);
+               break;
+       case INDIRECT_OTHERS:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS);
+               break;
+       default:
+               IWL_ERR(priv, "illegal indirect type: 0x%X\n",
+               address & INDIRECT_TYPE_MSK);
+               break;
+       }
+
+       /* translate the offset from words to byte */
+       return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
+                                          size_t offset)
+{
+       u32 address = eeprom_indirect_address(priv, offset);
+       BUG_ON(address >= priv->cfg->eeprom_size);
+       return &priv->eeprom[address];
+}
+
+struct iwl_mod_params iwlagn_mod_params = {
+       .amsdu_size_8K = 1,
+       .restart_fw = 1,
+       /* the rest are 0 by default */
+};
+
+void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       unsigned long flags;
+       int i;
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].page != NULL) {
+                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+                       __iwl_free_pages(priv, rxq->pool[i].page);
+                       rxq->pool[i].page = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+
+       for (i = 0; i < RX_QUEUE_SIZE; i++)
+               rxq->queue[i] = NULL;
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->write_actual = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       u32 rb_size;
+       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+       u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+       if (!priv->cfg->use_isr_legacy)
+               rb_timeout = RX_RB_TIMEOUT;
+
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          (u32)(rxq->dma_addr >> 8));
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          rxq->rb_stts_dma >> 4);
+
+       /* Enable Rx DMA
+        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+        *      the credit mechanism in 5000 HW RX FIFO
+        * Direct rx interrupts to hosts
+        * Rx buffer size 4 or 8k
+        * RB timeout 0x10
+        * 256 RBDs
+        */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
+                          rb_size|
+                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+
+       return 0;
+}
+
+int iwlagn_hw_nic_init(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       int ret;
+
+       /* nic_init */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->cfg->ops->lib->apm_ops.init(priv);
+
+       /* Set interrupt coalescing calibration timer to default (512 usecs) */
+       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
+
+       priv->cfg->ops->lib->apm_ops.config(priv);
+
+       /* Allocate the RX queue, or reset if it is already allocated */
+       if (!rxq->bd) {
+               ret = iwl_rx_queue_alloc(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Unable to initialize Rx queue\n");
+                       return -ENOMEM;
+               }
+       } else
+               iwlagn_rx_queue_reset(priv, rxq);
+
+       iwlagn_rx_replenish(priv);
+
+       iwlagn_rx_init(priv, rxq);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rxq->need_update = 1;
+       iwl_rx_queue_update_write_ptr(priv, rxq);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Allocate or reset and init all Tx and Command queues */
+       if (!priv->txq) {
+               ret = iwlagn_txq_ctx_alloc(priv);
+               if (ret)
+                       return ret;
+       } else
+               iwlagn_txq_ctx_reset(priv);
+
+       set_bit(STATUS_INIT, &priv->status);
+
+       return 0;
+}
+
+/**
+ * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwlagn_dma_addr2rbd_ptr(struct iwl_priv *priv,
+                                         dma_addr_t dma_addr)
+{
+       return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+void iwlagn_rx_queue_restock(struct iwl_priv *priv)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+               /* The overwritten rxb must be a used one */
+               rxb = rxq->queue[rxq->write];
+               BUG_ON(rxb && rxb->page);
+
+               /* Get next free Rx buffer, remove from free list */
+               element = rxq->rx_free.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               /* Point to Rx buffer via next RBD in circular buffer */
+               rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(priv,
+                                                             rxb->page_dma);
+               rxq->queue[rxq->write] = rxb;
+               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+               rxq->free_count--;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+       /* If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8. */
+       if (rxq->write_actual != (rxq->write & ~0x7)) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               rxq->need_update = 1;
+               spin_unlock_irqrestore(&rxq->lock, flags);
+               iwl_rx_queue_update_write_ptr(priv, rxq);
+       }
+}
+
+/**
+ * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       struct page *page;
+       unsigned long flags;
+       gfp_t gfp_mask = priority;
+
+       while (1) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       return;
+               }
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
+
+               if (priv->hw_params.rx_page_order > 0)
+                       gfp_mask |= __GFP_COMP;
+
+               /* Alloc a new receive buffer */
+               page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+               if (!page) {
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(priv, "alloc_pages failed, "
+                                              "order: %d\n",
+                                              priv->hw_params.rx_page_order);
+
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
+                       return;
+               }
+
+               spin_lock_irqsave(&rxq->lock, flags);
+
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       __free_pages(page, priv->hw_params.rx_page_order);
+                       return;
+               }
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               BUG_ON(rxb->page);
+               rxb->page = page;
+               /* Get physical address of the RB */
+               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+               /* dma address must be no more than 36 bits */
+               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+               /* and also 256 byte aligned! */
+               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+               spin_lock_irqsave(&rxq->lock, flags);
+
+               list_add_tail(&rxb->list, &rxq->rx_free);
+               rxq->free_count++;
+               priv->alloc_rxb_page++;
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+       }
+}
+
+void iwlagn_rx_replenish(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       iwlagn_rx_allocate(priv, GFP_KERNEL);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwlagn_rx_queue_restock(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void iwlagn_rx_replenish_now(struct iwl_priv *priv)
+{
+       iwlagn_rx_allocate(priv, GFP_ATOMIC);
+
+       iwlagn_rx_queue_restock(priv);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       int i;
+       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+               if (rxq->pool[i].page != NULL) {
+                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+                       __iwl_free_pages(priv, rxq->pool[i].page);
+                       rxq->pool[i].page = NULL;
+               }
+       }
+
+       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                         rxq->dma_addr);
+       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+                         rxq->rb_stts, rxq->rb_stts_dma);
+       rxq->bd = NULL;
+       rxq->rb_stts  = NULL;
+}
+
+int iwlagn_rxq_stop(struct iwl_priv *priv)
+{
+
+       /* stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+
+       return 0;
+}
+
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+       int idx = 0;
+       int band_offset = 0;
+
+       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               idx = (rate_n_flags & 0xff);
+               return idx;
+       /* Legacy rate format, search for match in table */
+       } else {
+               if (band == IEEE80211_BAND_5GHZ)
+                       band_offset = IWL_FIRST_OFDM_RATE;
+               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+                               return idx - band_offset;
+       }
+
+       return -1;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static inline int iwlagn_calc_rssi(struct iwl_priv *priv,
+                               struct iwl_rx_phy_res *rx_resp)
+{
+       return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+/**
+ * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good data frames.
+ *    All beacon and probe response frames are printed.
+ */
+static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
+                     struct iwl_rx_phy_res *phy_res, u16 length,
+                     struct ieee80211_hdr *header, int group100)
+{
+       u32 to_us;
+       u32 print_summary = 0;
+       u32 print_dump = 0;     /* set to 1 to dump all frames' contents */
+       u32 hundred = 0;
+       u32 dataframe = 0;
+       __le16 fc;
+       u16 seq_ctl;
+       u16 channel;
+       u16 phy_flags;
+       u32 rate_n_flags;
+       u32 tsf_low;
+       int rssi;
+
+       if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
+               return;
+
+       /* MAC header */
+       fc = header->frame_control;
+       seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+       /* metadata */
+       channel = le16_to_cpu(phy_res->channel);
+       phy_flags = le16_to_cpu(phy_res->phy_flags);
+       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+       /* signal statistics */
+       rssi = iwlagn_calc_rssi(priv, phy_res);
+       tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
+
+       to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+       /* if data frame is to us and all is good,
+        *   (optionally) print summary for only 1 out of every 100 */
+       if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
+           cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+               dataframe = 1;
+               if (!group100)
+                       print_summary = 1;      /* print each frame */
+               else if (priv->framecnt_to_us < 100) {
+                       priv->framecnt_to_us++;
+                       print_summary = 0;
+               } else {
+                       priv->framecnt_to_us = 0;
+                       print_summary = 1;
+                       hundred = 1;
+               }
+       } else {
+               /* print summary for all other frames */
+               print_summary = 1;
+       }
+
+       if (print_summary) {
+               char *title;
+               int rate_idx;
+               u32 bitrate;
+
+               if (hundred)
+                       title = "100Frames";
+               else if (ieee80211_has_retry(fc))
+                       title = "Retry";
+               else if (ieee80211_is_assoc_resp(fc))
+                       title = "AscRsp";
+               else if (ieee80211_is_reassoc_resp(fc))
+                       title = "RasRsp";
+               else if (ieee80211_is_probe_resp(fc)) {
+                       title = "PrbRsp";
+                       print_dump = 1; /* dump frame contents */
+               } else if (ieee80211_is_beacon(fc)) {
+                       title = "Beacon";
+                       print_dump = 1; /* dump frame contents */
+               } else if (ieee80211_is_atim(fc))
+                       title = "ATIM";
+               else if (ieee80211_is_auth(fc))
+                       title = "Auth";
+               else if (ieee80211_is_deauth(fc))
+                       title = "DeAuth";
+               else if (ieee80211_is_disassoc(fc))
+                       title = "DisAssoc";
+               else
+                       title = "Frame";
+
+               rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+               if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
+                       bitrate = 0;
+                       WARN_ON_ONCE(1);
+               } else {
+                       bitrate = iwl_rates[rate_idx].ieee / 2;
+               }
+
+               /* print frame summary.
+                * MAC addresses show just the last byte (for brevity),
+                *    but you can hack it to show more, if you'd like to. */
+               if (dataframe)
+                       IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
+                                    "len=%u, rssi=%d, chnl=%d, rate=%u,\n",
+                                    title, le16_to_cpu(fc), header->addr1[5],
+                                    length, rssi, channel, bitrate);
+               else {
+                       /* src/dst addresses assume managed mode */
+                       IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
+                                    "len=%u, rssi=%d, tim=%lu usec, "
+                                    "phy=0x%02x, chnl=%d\n",
+                                    title, le16_to_cpu(fc), header->addr1[5],
+                                    header->addr3[5], length, rssi,
+                                    tsf_low - priv->scan_start_tsf,
+                                    phy_flags, channel);
+               }
+       }
+       if (print_dump)
+               iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+}
+#endif
+
+static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
+{
+       u32 decrypt_out = 0;
+
+       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
+                                       RX_RES_STATUS_STATION_FOUND)
+               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
+                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
+
+       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
+
+       /* packet was not encrypted */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_NONE)
+               return decrypt_out;
+
+       /* packet was encrypted with unknown alg */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_ERR)
+               return decrypt_out;
+
+       /* decryption was not done in HW */
+       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
+                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
+               return decrypt_out;
+
+       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
+
+       case RX_RES_STATUS_SEC_TYPE_CCMP:
+               /* alg is CCM: check MIC only */
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
+                       /* Bad MIC */
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+
+               break;
+
+       case RX_RES_STATUS_SEC_TYPE_TKIP:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
+                       /* Bad TTAK */
+                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
+                       break;
+               }
+               /* fall through if TTAK OK */
+       default:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+               break;
+       };
+
+       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
+                                       decrypt_in, decrypt_out);
+
+       return decrypt_out;
+}
+
+static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
+                                       struct ieee80211_hdr *hdr,
+                                       u16 len,
+                                       u32 ampdu_status,
+                                       struct iwl_rx_mem_buffer *rxb,
+                                       struct ieee80211_rx_status *stats)
+{
+       struct sk_buff *skb;
+       __le16 fc = hdr->frame_control;
+
+       /* We only process data packets if the interface is open */
+       if (unlikely(!priv->is_open)) {
+               IWL_DEBUG_DROP_LIMIT(priv,
+                   "Dropping packet while interface is not open.\n");
+               return;
+       }
+
+       /* In case of HW accelerated crypto and bad decryption, drop */
+       if (!priv->cfg->mod_params->sw_crypto &&
+           iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+               return;
+
+       skb = dev_alloc_skb(128);
+       if (!skb) {
+               IWL_ERR(priv, "dev_alloc_skb failed\n");
+               return;
+       }
+
+       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+
+       iwl_update_stats(priv, false, fc, len);
+       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+       ieee80211_rx(priv->hw, skb);
+       priv->alloc_rxb_page--;
+       rxb->page = NULL;
+}
+
+/* Called for REPLY_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+void iwlagn_rx_reply_rx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct ieee80211_hdr *header;
+       struct ieee80211_rx_status rx_status;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rx_phy_res *phy_res;
+       __le32 rx_pkt_status;
+       struct iwl4965_rx_mpdu_res_start *amsdu;
+       u32 len;
+       u32 ampdu_status;
+       u32 rate_n_flags;
+
+       /**
+        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+        *      REPLY_RX: physical layer info is in this buffer
+        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+        *              command and cached in priv->last_phy_res
+        *
+        * Here we set up local variables depending on which command is
+        * received.
+        */
+       if (pkt->hdr.cmd == REPLY_RX) {
+               phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
+               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
+                               + phy_res->cfg_phy_cnt);
+
+               len = le16_to_cpu(phy_res->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
+                               phy_res->cfg_phy_cnt + len);
+               ampdu_status = le32_to_cpu(rx_pkt_status);
+       } else {
+               if (!priv->_agn.last_phy_res_valid) {
+                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+                       return;
+               }
+               phy_res = &priv->_agn.last_phy_res;
+               amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
+               len = le16_to_cpu(amsdu->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
+               ampdu_status = iwlagn_translate_rx_status(priv,
+                               le32_to_cpu(rx_pkt_status));
+       }
+
+       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
+               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
+                               phy_res->cfg_phy_cnt);
+               return;
+       }
+
+       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+                               le32_to_cpu(rx_pkt_status));
+               return;
+       }
+
+       /* This will be used in several places later */
+       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+       /* rx_status carries information about the packet to mac80211 */
+       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+       rx_status.freq =
+               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
+       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+       rx_status.rate_idx =
+               iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
+       rx_status.flag = 0;
+
+       /* TSF isn't reliable. In order to allow smooth user experience,
+        * this W/A doesn't propagate it to the mac80211 */
+       /*rx_status.flag |= RX_FLAG_TSFT;*/
+
+       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
+
+       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+       rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       /* Set "1" to report good data frames in groups of 100 */
+       if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
+               iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
+#endif
+       iwl_dbg_log_rx_data_frame(priv, len, header);
+       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
+               rx_status.signal, (unsigned long long)rx_status.mactime);
+
+       /*
+        * "antenna number"
+        *
+        * It seems that the antenna field in the phy flags value
+        * is actually a bit field. This is undefined by radiotap,
+        * it wants an actual antenna number but I always get "7"
+        * for most legacy frames I receive indicating that the
+        * same frame was received on all three RX chains.
+        *
+        * I think this field should be removed in favor of a
+        * new 802.11n radiotap field "RX chains" that is defined
+        * as a bitmask.
+        */
+       rx_status.antenna =
+               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+       /* set the preamble flag if appropriate */
+       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+               rx_status.flag |= RX_FLAG_SHORTPRE;
+
+       /* Set up the HT phy flags */
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               rx_status.flag |= RX_FLAG_HT;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               rx_status.flag |= RX_FLAG_40MHZ;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               rx_status.flag |= RX_FLAG_SHORT_GI;
+
+       iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+                                   rxb, &rx_status);
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       priv->_agn.last_phy_res_valid = true;
+       memcpy(&priv->_agn.last_phy_res, pkt->u.raw,
+              sizeof(struct iwl_rx_phy_res));
+}
index 0de8091..f7d85a2 100644 (file)
@@ -2003,7 +2003,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        /* rates available for this association, and for modulation mode */
        rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
 
-       IWL_DEBUG_RATE(priv, "mask 0x%04X \n", rate_mask);
+       IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
 
        /* mask with station rate restriction */
        if (is_legacy(tbl->lq_type)) {
@@ -2410,7 +2410,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_supported_band *sband = txrc->sband;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = priv_sta;
        int rate_idx;
@@ -2934,8 +2934,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
                desc += sprintf(buff+desc,
                                "Bit Rate= %d Mb/s\n",
                                iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
-       desc += sprintf(buff+desc, "Noise Level= %d dBm\n",
-                       priv->last_rx_noise);
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
        return ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
new file mode 100644 (file)
index 0000000..3077eac
--- /dev/null
@@ -0,0 +1,1333 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+/*
+ * mac80211 queues, ACs, hardware queues, FIFOs.
+ *
+ * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
+ *
+ * Mac80211 uses the following numbers, which we get as from it
+ * by way of skb_get_queue_mapping(skb):
+ *
+ *     VO      0
+ *     VI      1
+ *     BE      2
+ *     BK      3
+ *
+ *
+ * Regular (not A-MPDU) frames are put into hardware queues corresponding
+ * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
+ * own queue per aggregation session (RA/TID combination), such queues are
+ * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
+ * order to map frames to the right queue, we also need an AC->hw queue
+ * mapping. This is implemented here.
+ *
+ * Due to the way hw queues are set up (by the hw specific modules like
+ * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity
+ * mapping.
+ */
+
+static const u8 tid_to_ac[] = {
+       /* this matches the mac80211 numbers */
+       2, 3, 3, 2, 1, 1, 0, 0
+};
+
+static const u8 ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static inline int get_fifo_from_ac(u8 ac)
+{
+       return ac_to_fifo[ac];
+}
+
+static inline int get_fifo_from_tid(u16 tid)
+{
+       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+               return get_fifo_from_ac(tid_to_ac[tid]);
+
+       /* no support for TIDs 8-15 yet */
+       return -EINVAL;
+}
+
+/**
+ * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+                                           struct iwl_tx_queue *txq,
+                                           u16 byte_cnt)
+{
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+       int write_ptr = txq->q.write_ptr;
+       int txq_id = txq->q.id;
+       u8 sec_ctl = 0;
+       u8 sta_id = 0;
+       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+       __le16 bc_ent;
+
+       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       if (txq_id != IWL_CMD_QUEUE_NUM) {
+               sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+               sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+
+               switch (sec_ctl & TX_CMD_SEC_MSK) {
+               case TX_CMD_SEC_CCM:
+                       len += CCMP_MIC_LEN;
+                       break;
+               case TX_CMD_SEC_TKIP:
+                       len += TKIP_ICV_LEN;
+                       break;
+               case TX_CMD_SEC_WEP:
+                       len += WEP_IV_LEN + WEP_ICV_LEN;
+                       break;
+               }
+       }
+
+       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+
+       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
+
+       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
+}
+
+void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+                                          struct iwl_tx_queue *txq)
+{
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+       int txq_id = txq->q.id;
+       int read_ptr = txq->q.read_ptr;
+       u8 sta_id = 0;
+       __le16 bc_ent;
+
+       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       if (txq_id != IWL_CMD_QUEUE_NUM)
+               sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
+
+       bc_ent = cpu_to_le16(1 | (sta_id << 12));
+       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+}
+
+static int iwlagn_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+                                       u16 txq_id)
+{
+       u32 tbl_dw_addr;
+       u32 tbl_dw;
+       u16 scd_q2ratid;
+
+       scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+       tbl_dw_addr = priv->scd_base_addr +
+                       IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+       tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
+
+       if (txq_id & 0x1)
+               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+       else
+               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+       iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
+
+       return 0;
+}
+
+static void iwlagn_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+{
+       /* Simply stop the queue, but don't change any configuration;
+        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+       iwl_write_prph(priv,
+               IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
+               (0 << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+               (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
+                               int txq_id, u32 index)
+{
+       iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+                       (index & 0xff) | (txq_id << 8));
+       iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
+                                       struct iwl_tx_queue *txq,
+                                       int tx_fifo_id, int scd_retry)
+{
+       int txq_id = txq->q.id;
+       int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
+
+       iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
+                       (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                       (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
+                       (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
+                       IWL50_SCD_QUEUE_STTS_REG_MSK);
+
+       txq->sched_retry = scd_retry;
+
+       IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n",
+                      active ? "Activate" : "Deactivate",
+                      scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
+}
+
+int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+                         int tx_fifo, int sta_id, int tid, u16 ssn_idx)
+{
+       unsigned long flags;
+       u16 ra_tid;
+
+       if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
+           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
+               IWL_WARN(priv,
+                       "queue number out of range: %d, must be %d to %d\n",
+                       txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
+                       IWLAGN_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
+               return -EINVAL;
+       }
+
+       ra_tid = BUILD_RAxTID(sta_id, tid);
+
+       /* Modify device's station table to Tx this TID */
+       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Stop this Tx queue before configuring it */
+       iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+
+       /* Map receiver-address / traffic-ID to this queue */
+       iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+       /* Set this queue as a chain-building queue */
+       iwl_set_bits_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+       /* enable aggregations for the queue */
+       iwl_set_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1<<txq_id));
+
+       /* Place first TFD at index corresponding to start sequence number.
+        * Assumes that ssn_idx is valid (!= 0xFFF) */
+       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+       iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+       /* Set up Tx window size and frame limit for this queue */
+       iwl_write_targ_mem(priv, priv->scd_base_addr +
+                       IWL50_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
+                       sizeof(u32),
+                       ((SCD_WIN_SIZE <<
+                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                       ((SCD_FRAME_LIMIT <<
+                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+       iwl_set_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
+
+       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
+       iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+                          u16 ssn_idx, u8 tx_fifo)
+{
+       if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
+           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
+               IWL_ERR(priv,
+                       "queue number out of range: %d, must be %d to %d\n",
+                       txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
+                       IWLAGN_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
+               return -EINVAL;
+       }
+
+       iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+
+       iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
+
+       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+       /* supposes that ssn_idx is valid (!= 0xFFF) */
+       iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+       iwl_clear_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
+       iwl_txq_ctx_deactivate(priv, txq_id);
+       iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+       return 0;
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
+ */
+void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
+{
+       iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
+}
+
+static inline int get_queue_from_ac(u16 ac)
+{
+       return ac;
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
+                                 struct iwl_tx_cmd *tx_cmd,
+                                 struct ieee80211_tx_info *info,
+                                 struct ieee80211_hdr *hdr,
+                                 u8 std_id)
+{
+       __le16 fc = hdr->frame_control;
+       __le32 tx_flags = tx_cmd->tx_flags;
+
+       tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               tx_flags |= TX_CMD_FLG_ACK_MSK;
+               if (ieee80211_is_mgmt(fc))
+                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+               if (ieee80211_is_probe_resp(fc) &&
+                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+                       tx_flags |= TX_CMD_FLG_TSF_MSK;
+       } else {
+               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       if (ieee80211_is_back_req(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
+       tx_cmd->sta_id = std_id;
+       if (ieee80211_has_morefrags(fc))
+               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+       if (ieee80211_is_data_qos(fc)) {
+               u8 *qc = ieee80211_get_qos_ctl(hdr);
+               tx_cmd->tid_tspec = qc[0] & 0xf;
+               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+       } else {
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
+
+       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+       if (ieee80211_is_mgmt(fc)) {
+               if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+               else
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+       } else {
+               tx_cmd->timeout.pm_frame_timeout = 0;
+       }
+
+       tx_cmd->driver_txop = 0;
+       tx_cmd->tx_flags = tx_flags;
+       tx_cmd->next_frame_len = 0;
+}
+
+#define RTS_DFAULT_RETRY_LIMIT         60
+
+static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
+                             struct iwl_tx_cmd *tx_cmd,
+                             struct ieee80211_tx_info *info,
+                             __le16 fc)
+{
+       u32 rate_flags;
+       int rate_idx;
+       u8 rts_retry_limit;
+       u8 data_retry_limit;
+       u8 rate_plcp;
+
+       /* Set retry limit on DATA packets and Probe Responses*/
+       if (ieee80211_is_probe_resp(fc))
+               data_retry_limit = 3;
+       else
+               data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
+       tx_cmd->data_retry_limit = data_retry_limit;
+
+       /* Set retry limit on RTS packets */
+       rts_retry_limit = RTS_DFAULT_RETRY_LIMIT;
+       if (data_retry_limit < rts_retry_limit)
+               rts_retry_limit = data_retry_limit;
+       tx_cmd->rts_retry_limit = rts_retry_limit;
+
+       /* DATA packets will use the uCode station table for rate/antenna
+        * selection */
+       if (ieee80211_is_data(fc)) {
+               tx_cmd->initial_rate_index = 0;
+               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+               return;
+       }
+
+       /**
+        * If the current TX rate stored in mac80211 has the MCS bit set, it's
+        * not really a TX rate.  Thus, we use the lowest supported rate for
+        * this band.  Also use the lowest supported rate if the stored rate
+        * index is invalid.
+        */
+       rate_idx = info->control.rates[0].idx;
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
+                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
+               rate_idx = rate_lowest_index(&priv->bands[info->band],
+                               info->control.sta);
+       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate_idx += IWL_FIRST_OFDM_RATE;
+       /* Get PLCP rate for tx_cmd->rate_n_flags */
+       rate_plcp = iwl_rates[rate_idx].plcp;
+       /* Zero out flags for this packet */
+       rate_flags = 0;
+
+       /* Set CCK flag as needed */
+       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+       /* Set up RTS and CTS flags for certain packets */
+       switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+       case cpu_to_le16(IEEE80211_STYPE_AUTH):
+       case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+       case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+       case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+               if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
+                       tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+                       tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* Set up antennas */
+       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+       /* Set the rate in the TX cmd */
+       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+                                     struct ieee80211_tx_info *info,
+                                     struct iwl_tx_cmd *tx_cmd,
+                                     struct sk_buff *skb_frag,
+                                     int sta_id)
+{
+       struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+       switch (keyconf->alg) {
+       case ALG_CCMP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
+               break;
+
+       case ALG_TKIP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+               ieee80211_get_tkip_key(keyconf, skb_frag,
+                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
+               break;
+
+       case ALG_WEP:
+               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+               if (keyconf->keylen == WEP_KEY_LEN_128)
+                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+
+               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
+                            "with key %d\n", keyconf->keyidx);
+               break;
+
+       default:
+               IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
+               break;
+       }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = info->control.sta;
+       struct iwl_station_priv *sta_priv = NULL;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       struct iwl_device_cmd *out_cmd;
+       struct iwl_cmd_meta *out_meta;
+       struct iwl_tx_cmd *tx_cmd;
+       int swq_id, txq_id;
+       dma_addr_t phys_addr;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       u16 len, len_org, firstlen, secondlen;
+       u16 seq_number = 0;
+       __le16 fc;
+       u8 hdr_len;
+       u8 sta_id;
+       u8 wait_write_ptr = 0;
+       u8 tid = 0;
+       u8 *qc = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
+               goto drop_unlock;
+       }
+
+       fc = hdr->frame_control;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (ieee80211_is_auth(fc))
+               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
+       else if (ieee80211_is_assoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
+       else if (ieee80211_is_reassoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
+#endif
+
+       hdr_len = ieee80211_hdrlen(fc);
+
+       /* Find (or create) index into station table for destination station */
+       if (info->flags & IEEE80211_TX_CTL_INJECTED)
+               sta_id = priv->hw_params.bcast_sta_id;
+       else
+               sta_id = iwl_get_sta_id(priv, hdr);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+                              hdr->addr1);
+               goto drop_unlock;
+       }
+
+       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
+
+       if (sta)
+               sta_priv = (void *)sta->drv_priv;
+
+       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
+           sta_priv->asleep) {
+               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+               /*
+                * This sends an asynchronous command to the device,
+                * but we can rely on it being processed before the
+                * next frame is processed -- and the next frame to
+                * this station is the one that will consume this
+                * counter.
+                * For now set the counter to just 1 since we do not
+                * support uAPSD yet.
+                */
+               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+       }
+
+       txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+       if (ieee80211_is_data_qos(fc)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+               if (unlikely(tid >= MAX_TID_COUNT))
+                       goto drop_unlock;
+               seq_number = priv->stations[sta_id].tid[tid].seq_number;
+               seq_number &= IEEE80211_SCTL_SEQ;
+               hdr->seq_ctrl = hdr->seq_ctrl &
+                               cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(seq_number);
+               seq_number += 0x10;
+               /* aggregation is on for this <sta,tid> */
+               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+                   priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
+                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+               }
+       }
+
+       txq = &priv->txq[txq_id];
+       swq_id = txq->swq_id;
+       q = &txq->q;
+
+       if (unlikely(iwl_queue_space(q) < q->high_mark))
+               goto drop_unlock;
+
+       if (ieee80211_is_data_qos(fc))
+               priv->stations[sta_id].tid[tid].tfds_in_queue++;
+
+       /* Set up driver data for this TFD */
+       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
+       txq->txb[q->write_ptr].skb[0] = skb;
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_cmd = txq->cmd[q->write_ptr];
+       out_meta = &txq->meta[q->write_ptr];
+       tx_cmd = &out_cmd->cmd.tx;
+       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+       memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
+
+       /*
+        * Set up the Tx-command (not MAC!) header.
+        * Store the chosen Tx queue and TFD index within the sequence field;
+        * after Tx, uCode's Tx response will return this value so driver can
+        * locate the frame within the tx queue and do post-tx processing.
+        */
+       out_cmd->hdr.cmd = REPLY_TX;
+       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                               INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+
+       /* Total # bytes to be transmitted */
+       len = (u16)skb->len;
+       tx_cmd->len = cpu_to_le16(len);
+
+       if (info->control.hw_key)
+               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
+
+       /* TODO need this for burst mode later on */
+       iwlagn_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+       iwl_dbg_log_tx_data_frame(priv, len, hdr);
+
+       iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
+
+       iwl_update_stats(priv, true, fc, len);
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+
+       len_org = len;
+       firstlen = len = (len + 3) & ~3;
+
+       if (len_org != len)
+               len_org = 1;
+       else
+               len_org = 0;
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (len_org)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = pci_map_single(priv->pci_dev,
+                                   &out_cmd->hdr, len,
+                                   PCI_DMA_BIDIRECTIONAL);
+       pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       pci_unmap_len_set(out_meta, len, len);
+       /* Add buffer containing Tx command and MAC(!) header to TFD's
+        * first entry */
+       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
+                                                  txcmd_phys, len, 1, 0);
+
+       if (!ieee80211_has_morefrags(hdr->frame_control)) {
+               txq->need_update = 1;
+               if (qc)
+                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
+       }
+
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       secondlen = len = skb->len - hdr_len;
+       if (len) {
+               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+                                          len, PCI_DMA_TODEVICE);
+               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
+                                                          phys_addr, len,
+                                                          0, 0);
+       }
+
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+                               offsetof(struct iwl_tx_cmd, scratch);
+
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+       /* take back ownership of DMA buffer to enable update */
+       pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
+                                   len, PCI_DMA_BIDIRECTIONAL);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+       IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
+                    le16_to_cpu(out_cmd->hdr.sequence));
+       IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+       /* Set up entry for this TFD in Tx byte-count array */
+       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
+                                                    le16_to_cpu(tx_cmd->len));
+
+       pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
+                                      len, PCI_DMA_BIDIRECTIONAL);
+
+       trace_iwlwifi_dev_tx(priv,
+                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &out_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_txq_update_write_ptr(priv, txq);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+
+       /* avoid atomic ops if it isn't an associated client */
+       if (sta_priv && sta_priv->client)
+               atomic_inc(&sta_priv->pending_frames);
+
+       if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
+               if (wait_write_ptr) {
+                       spin_lock_irqsave(&priv->lock, flags);
+                       txq->need_update = 1;
+                       iwl_txq_update_write_ptr(priv, txq);
+                       spin_unlock_irqrestore(&priv->lock, flags);
+               } else {
+                       iwl_stop_queue(priv, txq->swq_id);
+               }
+       }
+
+       return 0;
+
+drop_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return -1;
+}
+
+static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr, size_t size)
+{
+       ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
+                                      GFP_KERNEL);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
+/**
+ * iwlagn_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       /* Tx queues */
+       if (priv->txq) {
+               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                               iwl_cmd_queue_free(priv);
+                       else
+                               iwl_tx_queue_free(priv, txq_id);
+       }
+       iwlagn_free_dma_ptr(priv, &priv->kw);
+
+       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
+
+       /* free tx queue structure */
+       iwl_free_txq_mem(priv);
+}
+
+/**
+ * iwlagn_txq_ctx_alloc - allocate TX queue context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
+{
+       int ret;
+       int txq_id, slots_num;
+       unsigned long flags;
+
+       /* Free all tx/cmd queues and keep-warm buffer */
+       iwlagn_hw_txq_ctx_free(priv);
+
+       ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+                               priv->hw_params.scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
+               goto error_bc_tbls;
+       }
+       /* Alloc keep-warm buffer */
+       ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
+       if (ret) {
+               IWL_ERR(priv, "Keep Warm allocation failed\n");
+               goto error_kw;
+       }
+
+       /* allocate tx queue structure */
+       ret = iwl_alloc_txq_mem(priv);
+       if (ret)
+               goto error;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4) */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+                                      txq_id);
+               if (ret) {
+                       IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return ret;
+
+ error:
+       iwlagn_hw_txq_ctx_free(priv);
+       iwlagn_free_dma_ptr(priv, &priv->kw);
+ error_kw:
+       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
+ error_bc_tbls:
+       return ret;
+}
+
+void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
+{
+       int txq_id, slots_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4) */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+                           TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
+       }
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
+{
+       int ch;
+       unsigned long flags;
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                   1000);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
+ */
+static int iwlagn_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+                       return txq_id;
+       return -1;
+}
+
+int iwlagn_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
+{
+       int sta_id;
+       int tx_fifo;
+       int txq_id;
+       int ret;
+       unsigned long flags;
+       struct iwl_tid_data *tid_data;
+
+       tx_fifo = get_fifo_from_tid(tid);
+       if (unlikely(tx_fifo < 0))
+               return tx_fifo;
+
+       IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
+                       __func__, ra, tid);
+
+       sta_id = iwl_find_station(priv, ra);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Start AGG on invalid station\n");
+               return -ENXIO;
+       }
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
+               return -ENXIO;
+       }
+
+       txq_id = iwlagn_txq_ctx_activate_free(priv);
+       if (txq_id == -1) {
+               IWL_ERR(priv, "No free aggregation queue available\n");
+               return -ENXIO;
+       }
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       tid_data = &priv->stations[sta_id].tid[tid];
+       *ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.txq_id = txq_id;
+       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
+                                                 sta_id, tid, *ssn);
+       if (ret)
+               return ret;
+
+       if (tid_data->tfds_in_queue == 0) {
+               IWL_DEBUG_HT(priv, "HW queue is empty\n");
+               tid_data->agg.state = IWL_AGG_ON;
+               ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+       } else {
+               IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
+                            tid_data->tfds_in_queue);
+               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+       }
+       return ret;
+}
+
+int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
+{
+       int tx_fifo_id, txq_id, sta_id, ssn = -1;
+       struct iwl_tid_data *tid_data;
+       int write_ptr, read_ptr;
+       unsigned long flags;
+
+       if (!ra) {
+               IWL_ERR(priv, "ra = NULL\n");
+               return -EINVAL;
+       }
+
+       tx_fifo_id = get_fifo_from_tid(tid);
+       if (unlikely(tx_fifo_id < 0))
+               return tx_fifo_id;
+
+       sta_id = iwl_find_station(priv, ra);
+
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+               return -ENXIO;
+       }
+
+       if (priv->stations[sta_id].tid[tid].agg.state ==
+                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
+               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+               ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+               return 0;
+       }
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
+               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
+
+       tid_data = &priv->stations[sta_id].tid[tid];
+       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+       txq_id = tid_data->agg.txq_id;
+       write_ptr = priv->txq[txq_id].q.write_ptr;
+       read_ptr = priv->txq[txq_id].q.read_ptr;
+
+       /* The queue is not empty */
+       if (write_ptr != read_ptr) {
+               IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
+               priv->stations[sta_id].tid[tid].agg.state =
+                               IWL_EMPTYING_HW_QUEUE_DELBA;
+               return 0;
+       }
+
+       IWL_DEBUG_HT(priv, "HW queue is empty\n");
+       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /*
+        * the only reason this call can fail is queue number out of range,
+        * which can happen if uCode is reloaded and all the station
+        * information are lost. if it is outside the range, there is no need
+        * to deactivate the uCode queue, just return "success" to allow
+        *  mac80211 to clean up it own data.
+        */
+       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
+                                                  tx_fifo_id);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
+
+       return 0;
+}
+
+int iwlagn_txq_check_empty(struct iwl_priv *priv,
+                          int sta_id, u8 tid, int txq_id)
+{
+       struct iwl_queue *q = &priv->txq[txq_id].q;
+       u8 *addr = priv->stations[sta_id].sta.sta.addr;
+       struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+
+       switch (priv->stations[sta_id].tid[tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_DELBA:
+               /* We are reclaiming the last packet of the */
+               /* aggregated HW queue */
+               if ((txq_id  == tid_data->agg.txq_id) &&
+                   (q->read_ptr == q->write_ptr)) {
+                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+                       int tx_fifo = get_fifo_from_tid(tid);
+                       IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
+                       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
+                                                            ssn, tx_fifo);
+                       tid_data->agg.state = IWL_AGG_OFF;
+                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+               }
+               break;
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /* We are reclaiming the last packet of the queue */
+               if (tid_data->tfds_in_queue == 0) {
+                       IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
+                       tid_data->agg.state = IWL_AGG_ON;
+                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+               }
+               break;
+       }
+       return 0;
+}
+
+static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_sta *sta;
+       struct iwl_station_priv *sta_priv;
+
+       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+       if (sta) {
+               sta_priv = (void *)sta->drv_priv;
+               /* avoid atomic ops if this isn't a client */
+               if (sta_priv->client &&
+                   atomic_dec_return(&sta_priv->pending_frames) == 0)
+                       ieee80211_sta_block_awake(priv->hw, sta, false);
+       }
+
+       ieee80211_tx_status_irqsafe(priv->hw, skb);
+}
+
+int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       struct iwl_tx_info *tx_info;
+       int nfreed = 0;
+       struct ieee80211_hdr *hdr;
+
+       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
+                         "is out of range [0-%d] %d %d.\n", txq_id,
+                         index, q->n_bd, q->write_ptr, q->read_ptr);
+               return 0;
+       }
+
+       for (index = iwl_queue_inc_wrap(index, q->n_bd);
+            q->read_ptr != index;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               tx_info = &txq->txb[txq->q.read_ptr];
+               iwlagn_tx_status(priv, tx_info->skb[0]);
+
+               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+                       nfreed++;
+               tx_info->skb[0] = NULL;
+
+               if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
+                       priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
+
+               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+       }
+       return nfreed;
+}
+
+/**
+ * iwlagn_tx_status_reply_compressed_ba - Update tx status from block-ack
+ *
+ * Go through block-ack's bitmap of ACK'd frames, update driver's record of
+ * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
+ */
+static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
+                                struct iwl_ht_agg *agg,
+                                struct iwl_compressed_ba_resp *ba_resp)
+
+{
+       int i, sh, ack;
+       u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
+       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+       u64 bitmap;
+       int successes = 0;
+       struct ieee80211_tx_info *info;
+
+       if (unlikely(!agg->wait_for_ba))  {
+               IWL_ERR(priv, "Received BA when not expected\n");
+               return -EINVAL;
+       }
+
+       /* Mark that the expected block-ack response arrived */
+       agg->wait_for_ba = 0;
+       IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
+
+       /* Calculate shift to align block-ack bits with our Tx window bits */
+       sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
+       if (sh < 0) /* tbw something is wrong with indices */
+               sh += 0x100;
+
+       /* don't use 64-bit values for now */
+       bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
+
+       if (agg->frame_count > (64 - sh)) {
+               IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
+               return -1;
+       }
+
+       /* check for success or failure according to the
+        * transmitted bitmap and block-ack bitmap */
+       bitmap &= agg->bitmap;
+
+       /* For each frame attempted in aggregation,
+        * update driver's record of tx frame's status. */
+       for (i = 0; i < agg->frame_count ; i++) {
+               ack = bitmap & (1ULL << i);
+               successes += !!ack;
+               IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
+                       ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
+                       agg->start_idx + i);
+       }
+
+       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+       info->flags |= IEEE80211_TX_STAT_ACK;
+       info->flags |= IEEE80211_TX_STAT_AMPDU;
+       info->status.ampdu_ack_map = successes;
+       info->status.ampdu_ack_len = agg->frame_count;
+       iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
+
+       IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
+
+       return 0;
+}
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+                                 struct ieee80211_tx_info *info)
+{
+       struct ieee80211_tx_rate *r = &info->control.rates[0];
+
+       info->antenna_sel_tx =
+               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               r->flags |= IEEE80211_TX_RC_MCS;
+       if (rate_n_flags & RATE_MCS_GF_MSK)
+               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+       if (rate_n_flags & RATE_MCS_DUP_MSK)
+               r->flags |= IEEE80211_TX_RC_DUP_DATA;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               r->flags |= IEEE80211_TX_RC_SHORT_GI;
+       r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+}
+
+/**
+ * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                          struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+       struct iwl_tx_queue *txq = NULL;
+       struct iwl_ht_agg *agg;
+       int index;
+       int sta_id;
+       int tid;
+
+       /* "flow" corresponds to Tx queue */
+       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+       /* "ssn" is start of block-ack Tx window, corresponds to index
+        * (in Tx queue's circular buffer) of first TFD/frame in window */
+       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+       if (scd_flow >= priv->hw_params.max_txq_num) {
+               IWL_ERR(priv,
+                       "BUG_ON scd_flow is bigger than number of queues\n");
+               return;
+       }
+
+       txq = &priv->txq[scd_flow];
+       sta_id = ba_resp->sta_id;
+       tid = ba_resp->tid;
+       agg = &priv->stations[sta_id].tid[tid].agg;
+
+       /* Find index just before block-ack window */
+       index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+       /* TODO: Need to get this copy more safely - now good for debug */
+
+       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
+                          "sta_id = %d\n",
+                          agg->wait_for_ba,
+                          (u8 *) &ba_resp->sta_addr_lo32,
+                          ba_resp->sta_id);
+       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
+                          "%d, scd_ssn = %d\n",
+                          ba_resp->tid,
+                          ba_resp->seq_ctl,
+                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
+                          ba_resp->scd_flow,
+                          ba_resp->scd_ssn);
+       IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n",
+                          agg->start_idx,
+                          (unsigned long long)agg->bitmap);
+
+       /* Update driver's record of ACK vs. not for each frame in window */
+       iwlagn_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+
+       /* Release all TFDs before the SSN, i.e. all TFDs in front of
+        * block-ack window (we assume that they've been successfully
+        * transmitted ... if not, it's too late anyway). */
+       if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
+               /* calculate mac80211 ampdu sw queue to wake */
+               int freed = iwlagn_tx_queue_reclaim(priv, scd_flow, index);
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+               if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+                   priv->mac80211_registered &&
+                   (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+                       iwl_wake_queue(priv, txq->swq_id);
+
+               iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
+       }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
new file mode 100644 (file)
index 0000000..52ae157
--- /dev/null
@@ -0,0 +1,416 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+static const s8 iwlagn_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWLAGN_CMD_FIFO_NUM,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+};
+
+/*
+ * ucode
+ */
+static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
+                               struct fw_desc *image, u32 dst_addr)
+{
+       dma_addr_t phy_addr = image->p_addr;
+       u32 byte_cnt = image->len;
+       int ret;
+
+       priv->ucode_write_complete = 0;
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+       iwl_write_direct32(priv,
+               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
+
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+               (iwl_get_dma_hi_addr(phy_addr)
+                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
+               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+       IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                                       priv->ucode_write_complete, 5 * HZ);
+       if (ret == -ERESTARTSYS) {
+               IWL_ERR(priv, "Could not load the %s uCode section due "
+                       "to interrupt\n", name);
+               return ret;
+       }
+       if (!ret) {
+               IWL_ERR(priv, "Could not load the %s uCode section\n",
+                       name);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int iwlagn_load_given_ucode(struct iwl_priv *priv,
+               struct fw_desc *inst_image,
+               struct fw_desc *data_image)
+{
+       int ret = 0;
+
+       ret = iwlagn_load_section(priv, "INST", inst_image,
+                                  IWLAGN_RTC_INST_LOWER_BOUND);
+       if (ret)
+               return ret;
+
+       return iwlagn_load_section(priv, "DATA", data_image,
+                                   IWLAGN_RTC_DATA_LOWER_BOUND);
+}
+
+int iwlagn_load_ucode(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* check whether init ucode should be loaded, or rather runtime ucode */
+       if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
+               IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
+               ret = iwlagn_load_given_ucode(priv,
+                       &priv->ucode_init, &priv->ucode_init_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
+                       priv->ucode_type = UCODE_INIT;
+               }
+       } else {
+               IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
+                       "Loading runtime ucode...\n");
+               ret = iwlagn_load_given_ucode(priv,
+                       &priv->ucode_code, &priv->ucode_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
+                       priv->ucode_type = UCODE_RT;
+               }
+       }
+
+       return ret;
+}
+
+#define IWL_UCODE_GET(item)                                            \
+static u32 iwlagn_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+                                   u32 api_ver)                        \
+{                                                                      \
+       if (api_ver <= 2)                                               \
+               return le32_to_cpu(ucode->u.v1.item);                   \
+       return le32_to_cpu(ucode->u.v2.item);                           \
+}
+
+static u32 iwlagn_ucode_get_header_size(u32 api_ver)
+{
+       if (api_ver <= 2)
+               return UCODE_HEADER_SIZE(1);
+       return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwlagn_ucode_get_build(const struct iwl_ucode_header *ucode,
+                                  u32 api_ver)
+{
+       if (api_ver <= 2)
+               return 0;
+       return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwlagn_ucode_get_data(const struct iwl_ucode_header *ucode,
+                                 u32 api_ver)
+{
+       if (api_ver <= 2)
+               return (u8 *) ucode->u.v1.data;
+       return (u8 *) ucode->u.v2.data;
+}
+
+IWL_UCODE_GET(inst_size);
+IWL_UCODE_GET(data_size);
+IWL_UCODE_GET(init_size);
+IWL_UCODE_GET(init_data_size);
+IWL_UCODE_GET(boot_size);
+
+struct iwl_ucode_ops iwlagn_ucode = {
+       .get_header_size = iwlagn_ucode_get_header_size,
+       .get_build = iwlagn_ucode_get_build,
+       .get_inst_size = iwlagn_ucode_get_inst_size,
+       .get_data_size = iwlagn_ucode_get_data_size,
+       .get_init_size = iwlagn_ucode_get_init_size,
+       .get_init_data_size = iwlagn_ucode_get_init_data_size,
+       .get_boot_size = iwlagn_ucode_get_boot_size,
+       .get_data = iwlagn_ucode_get_data,
+};
+
+/*
+ *  Calibration
+ */
+static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
+{
+       struct iwl_calib_xtal_freq_cmd cmd;
+       __le16 *xtal_calib =
+               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
+
+       cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
+       cmd.hdr.first_group = 0;
+       cmd.hdr.groups_num = 1;
+       cmd.hdr.data_valid = 1;
+       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
+       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
+       return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
+                            (u8 *)&cmd, sizeof(cmd));
+}
+
+static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
+{
+       struct iwl_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = sizeof(struct iwl_calib_cfg_cmd),
+               .data = &calib_cfg_cmd,
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
+
+       return iwl_send_cmd(priv, &cmd);
+}
+
+void iwlagn_rx_calib_result(struct iwl_priv *priv,
+                            struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
+       int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       int index;
+
+       /* reduce the size of the length field itself */
+       len -= 4;
+
+       /* Define the order in which the results will be sent to the runtime
+        * uCode. iwl_send_calib_results sends them in a row according to
+        * their index. We sort them here
+        */
+       switch (hdr->op_code) {
+       case IWL_PHY_CALIBRATE_DC_CMD:
+               index = IWL_CALIB_DC;
+               break;
+       case IWL_PHY_CALIBRATE_LO_CMD:
+               index = IWL_CALIB_LO;
+               break;
+       case IWL_PHY_CALIBRATE_TX_IQ_CMD:
+               index = IWL_CALIB_TX_IQ;
+               break;
+       case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+               index = IWL_CALIB_TX_IQ_PERD;
+               break;
+       case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+               index = IWL_CALIB_BASE_BAND;
+               break;
+       default:
+               IWL_ERR(priv, "Unknown calibration notification %d\n",
+                         hdr->op_code);
+               return;
+       }
+       iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
+}
+
+void iwlagn_rx_calib_complete(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb)
+{
+       IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+void iwlagn_init_alive_start(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* Check alive response for "valid" sign from uCode */
+       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+               /* We had an error bringing up the hardware, so take it
+                * all the way back down so we can try again */
+               IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n");
+               goto restart;
+       }
+
+       /* initialize uCode was loaded... verify inst image.
+        * This is a paranoid check, because we would not have gotten the
+        * "initialize" alive if code weren't properly loaded.  */
+       if (iwl_verify_ucode(priv)) {
+               /* Runtime instruction load was bad;
+                * take it all the way back down so we can try again */
+               IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
+               goto restart;
+       }
+
+       ret = priv->cfg->ops->lib->alive_notify(priv);
+       if (ret) {
+               IWL_WARN(priv,
+                       "Could not complete ALIVE transition: %d\n", ret);
+               goto restart;
+       }
+
+       iwlagn_send_calib_cfg(priv);
+       return;
+
+restart:
+       /* real restart (first load init_ucode) */
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+int iwlagn_alive_notify(struct iwl_priv *priv)
+{
+       u32 a;
+       unsigned long flags;
+       int i, chan;
+       u32 reg_val;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
+       a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
+       for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < priv->scd_base_addr +
+              IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+
+       iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
+                      priv->scd_bc_tbls.dma >> 10);
+
+       /* Enable DMA channel */
+       for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+       /* Update FH chicken bits */
+       reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+       iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+       iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
+               IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
+       iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
+
+       /* initiate the queues */
+       for (i = 0; i < priv->hw_params.max_txq_num; i++) {
+               iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
+               iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
+                               sizeof(u32),
+                               ((SCD_WIN_SIZE <<
+                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                               ((SCD_FRAME_LIMIT <<
+                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+       }
+
+       iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
+                       IWL_MASK(0, priv->hw_params.max_txq_num));
+
+       /* Activate all Tx DMA/FIFO channels */
+       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+
+       iwlagn_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
+       /* make sure all queue are not stopped */
+       memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
+       for (i = 0; i < 4; i++)
+               atomic_set(&priv->queue_stop_count[i], 0);
+
+       /* reset to 0 to enable all the queue first */
+       priv->txq_ctx_active_msk = 0;
+       /* map qos queues to fifos one-to-one */
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
+
+       for (i = 0; i < ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); i++) {
+               int ac = iwlagn_default_queue_to_tx_fifo[i];
+
+               iwl_txq_ctx_activate(priv, i);
+
+               if (ac == IWL_TX_FIFO_UNUSED)
+                       continue;
+
+               iwlagn_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       iwl_send_wimax_coex(priv);
+
+       iwlagn_set_Xtal_calib(priv);
+       iwl_send_calib_results(priv);
+
+       return 0;
+}
index fe4cec6..0b497d4 100644 (file)
@@ -84,13 +84,6 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("iwl4965");
 
-/*************** STATION TABLE MANAGEMENT ****
- * mac80211 should be examined to determine if sta_info is duplicating
- * the functionality provided here
- */
-
-/**************************************************************/
-
 /**
  * iwl_commit_rxon - commit staging_rxon to hardware
  *
@@ -166,6 +159,11 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                }
                iwl_clear_ucode_stations(priv, false);
                iwl_restore_stations(priv);
+               ret = iwl_restore_default_wep_keys(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+                       return ret;
+               }
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -189,10 +187,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
-               IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON. \n");
+               IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
                memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
                iwl_clear_ucode_stations(priv, false);
                iwl_restore_stations(priv);
+               ret = iwl_restore_default_wep_keys(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+                       return ret;
+               }
        }
 
        priv->start_calib = 0;
@@ -885,10 +888,10 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
            iwl_rx_missed_beacon_notif;
        /* Rx handlers */
-       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy;
-       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx;
+       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy;
+       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx;
        /* block ack */
-       priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba;
+       priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba;
        /* Set up hardware specific Rx handlers */
        priv->cfg->ops->lib->rx_handler_setup(priv);
 }
@@ -1016,7 +1019,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
                        count++;
                        if (count >= 8) {
                                rxq->read = i;
-                               iwl_rx_replenish_now(priv);
+                               iwlagn_rx_replenish_now(priv);
                                count = 0;
                        }
                }
@@ -1025,9 +1028,9 @@ void iwl_rx_handle(struct iwl_priv *priv)
        /* Backtrack one entry */
        rxq->read = i;
        if (fill_rx)
-               iwl_rx_replenish_now(priv);
+               iwlagn_rx_replenish_now(priv);
        else
-               iwl_rx_queue_restock(priv);
+               iwlagn_rx_queue_restock(priv);
 }
 
 /* call this function to flush any scheduled tasklet */
@@ -1426,6 +1429,60 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                iwl_enable_interrupts(priv);
 }
 
+/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
+#define ACK_CNT_RATIO (50)
+#define BA_TIMEOUT_CNT (5)
+#define BA_TIMEOUT_MAX (16)
+
+/**
+ * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
+ *
+ * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding
+ * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
+ * operation state.
+ */
+bool iwl_good_ack_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       bool rc = true;
+       int actual_ack_cnt_delta, expected_ack_cnt_delta;
+       int ba_timeout_delta;
+
+       actual_ack_cnt_delta =
+               le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+       expected_ack_cnt_delta =
+               le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+       ba_timeout_delta =
+               le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
+               le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+       if ((priv->_agn.agg_tids_count > 0) &&
+           (expected_ack_cnt_delta > 0) &&
+           (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
+               < ACK_CNT_RATIO) &&
+           (ba_timeout_delta > BA_TIMEOUT_CNT)) {
+               IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d,"
+                               " expected_ack_cnt = %d\n",
+                               actual_ack_cnt_delta, expected_ack_cnt_delta);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+               IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
+                               priv->delta_statistics.tx.rx_detected_cnt);
+               IWL_DEBUG_RADIO(priv,
+                               "ack_or_ba_timeout_collision delta = %d\n",
+                               priv->delta_statistics.tx.
+                               ack_or_ba_timeout_collision);
+#endif
+               IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
+                               ba_timeout_delta);
+               if (!actual_ack_cnt_delta &&
+                   (ba_timeout_delta >= BA_TIMEOUT_MAX))
+                       rc = false;
+       }
+       return rc;
+}
+
 
 /******************************************************************************
  *
@@ -1787,6 +1844,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        u32 data2, line;
        u32 desc, time, count, base, data1;
        u32 blink1, blink2, ilink1, ilink2;
+       u32 pc, hcmd;
 
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
@@ -1809,6 +1867,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        }
 
        desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
        blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
        blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
        ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
@@ -1817,6 +1876,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
        line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
        time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+       hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
 
        trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
                                      blink1, blink2, ilink1, ilink2);
@@ -1825,10 +1885,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
                "data1      data2      line\n");
        IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
                desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
-               ilink1, ilink2);
-
+       IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
+       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
+               pc, blink1, blink2, ilink1, ilink2, hcmd);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -1944,9 +2003,6 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
        return pos;
 }
 
-/* For sanity check only.  Actual size is determined by uCode, typ. 512 */
-#define MAX_EVENT_LOG_SIZE (512)
-
 #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
 
 int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
@@ -1979,16 +2035,16 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > MAX_EVENT_LOG_SIZE) {
+       if (capacity > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, MAX_EVENT_LOG_SIZE);
-               capacity = MAX_EVENT_LOG_SIZE;
+                       capacity, priv->cfg->max_event_log_size);
+               capacity = priv->cfg->max_event_log_size;
        }
 
-       if (next_entry > MAX_EVENT_LOG_SIZE) {
+       if (next_entry > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, MAX_EVENT_LOG_SIZE);
-               next_entry = MAX_EVENT_LOG_SIZE;
+                       next_entry, priv->cfg->max_event_log_size);
+               next_entry = priv->cfg->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -2204,8 +2260,8 @@ static void __iwl_down(struct iwl_priv *priv)
        /* device going down, Stop using ICT table */
        iwl_disable_ict(priv);
 
-       iwl_txq_ctx_stop(priv);
-       iwl_rxq_stop(priv);
+       iwlagn_txq_ctx_stop(priv);
+       iwlagn_rxq_stop(priv);
 
        /* Power-down device's busmaster DMA clocks */
        iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
@@ -2265,7 +2321,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 {
        int ret = 0;
 
-       IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+       IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n");
 
        ret = iwl_set_hw_ready(priv);
        if (priv->hw_ready)
@@ -2326,7 +2382,7 @@ static int __iwl_up(struct iwl_priv *priv)
 
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-       ret = iwl_hw_nic_init(priv);
+       ret = iwlagn_hw_nic_init(priv);
        if (ret) {
                IWL_ERR(priv, "Unable to init nic\n");
                return ret;
@@ -2476,7 +2532,7 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       iwl_rx_replenish(priv);
+       iwlagn_rx_replenish(priv);
        mutex_unlock(&priv->mutex);
 }
 
@@ -2486,7 +2542,6 @@ void iwl_post_associate(struct iwl_priv *priv)
 {
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
-       unsigned long flags;
 
        if (priv->iw_mode == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
@@ -2567,10 +2622,6 @@ void iwl_post_associate(struct iwl_priv *priv)
                break;
        }
 
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_activate_qos(priv, 0);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        /* the chain noise calibration will enabled PM upon completion
         * If chain noise has already been run, then we need to enable
         * power management here */
@@ -2737,7 +2788,7 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
                     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 
-       if (iwl_tx_skb(priv, skb))
+       if (iwlagn_tx_skb(priv, skb))
                dev_kfree_skb_any(skb);
 
        IWL_DEBUG_MACDUMP(priv, "leave\n");
@@ -2747,7 +2798,6 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 void iwl_config_ap(struct iwl_priv *priv)
 {
        int ret = 0;
-       unsigned long flags;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -2799,10 +2849,6 @@ void iwl_config_ap(struct iwl_priv *priv)
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_reset_qos(priv);
-               spin_lock_irqsave(&priv->lock, flags);
-               iwl_activate_qos(priv, 1);
-               spin_unlock_irqrestore(&priv->lock, flags);
                iwl_add_bcast_station(priv);
        }
        iwl_send_beacon_cmd(priv);
@@ -2858,12 +2904,13 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
 
-       /* If we are getting WEP group key and we didn't receive any key mapping
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
         * so far, we are in legacy wep mode (group key only), otherwise we are
         * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode */
-       if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
-               priv->iw_mode != NL80211_IFTYPE_AP) {
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if (key->alg == ALG_WEP && !sta && vif->type != NL80211_IFTYPE_AP) {
                if (cmd == SET_KEY)
                        is_default_wep_key = !priv->key_mapping_key;
                else
@@ -2925,7 +2972,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                        return ret;
        case IEEE80211_AMPDU_TX_START:
                IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn);
+               ret = iwlagn_tx_agg_start(priv, sta->addr, tid, ssn);
                if (ret == 0) {
                        priv->_agn.agg_tids_count++;
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -2934,7 +2981,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                return ret;
        case IEEE80211_AMPDU_TX_STOP:
                IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwl_tx_agg_stop(priv, sta->addr, tid);
+               ret = iwlagn_tx_agg_stop(priv, sta->addr, tid);
                if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) {
                        priv->_agn.agg_tids_count--;
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
@@ -2997,19 +3044,6 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
        }
 }
 
-/**
- * iwl_restore_wepkeys - Restore WEP keys to device
- */
-static void iwl_restore_wepkeys(struct iwl_priv *priv)
-{
-       mutex_lock(&priv->mutex);
-       if (priv->iw_mode == NL80211_IFTYPE_STATION &&
-           priv->default_wep_key &&
-           iwl_send_static_wepkey_cmd(priv, 0))
-               IWL_ERR(priv, "Could not send WEP static key\n");
-       mutex_unlock(&priv->mutex);
-}
-
 static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta)
@@ -3036,10 +3070,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
                return ret;
        }
 
-       iwl_restore_wepkeys(priv);
-
        /* Initialize rate scaling */
-       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n",
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl_rs_rate_init(priv, sta, sta_id);
 
@@ -3337,15 +3369,10 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        iwl_init_scan_params(priv);
 
-       iwl_reset_qos(priv);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
-
        /* Set the tx_power_user_lmt to the lowest power level
         * this value will get overwritten by channel max power avg
         * from eeprom */
-       priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN;
+       priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
 
        ret = iwl_init_channel_map(priv);
        if (ret) {
@@ -3692,8 +3719,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
        iwl_dealloc_ucode_pci(priv);
 
        if (priv->rxq.bd)
-               iwl_rx_queue_free(priv, &priv->rxq);
-       iwl_hw_txq_ctx_free(priv);
+               iwlagn_rx_queue_free(priv, &priv->rxq);
+       iwlagn_hw_txq_ctx_free(priv);
 
        iwl_eeprom_free(priv);
 
@@ -3808,6 +3835,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000i_g2_2agn_cfg)},
 
 /* 6x50 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
@@ -3890,3 +3918,33 @@ module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "debug output mask");
 #endif
 
+module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO);
+MODULE_PARM_DESC(swcrypto50,
+                "using crypto in software (default 0 [hardware]) (deprecated)");
+module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
+MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
+module_param_named(queues_num50,
+                  iwlagn_mod_params.num_of_queues, int, S_IRUGO);
+MODULE_PARM_DESC(queues_num50,
+                "number of hw queues in 50xx series (deprecated)");
+module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO);
+MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)");
+module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO);
+MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
+module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K,
+                  int, S_IRUGO);
+MODULE_PARM_DESC(amsdu_size_8K50,
+                "enable 8K amsdu size in 50XX series (deprecated)");
+module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K,
+                  int, S_IRUGO);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
+module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO);
+MODULE_PARM_DESC(fw_restart50,
+                "restart firmware in case of error (deprecated)");
+module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
+MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
+module_param_named(
+       disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
index 26eeb58..5d31422 100644 (file)
 
 #include "iwl-dev.h"
 
+extern struct iwl_mod_params iwlagn_mod_params;
+extern struct iwl_ucode_ops iwlagn_ucode;
+extern struct iwl_hcmd_ops iwlagn_hcmd;
+extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
+
 int iwl_reset_ict(struct iwl_priv *priv);
 void iwl_disable_ict(struct iwl_priv *priv);
 int iwl_alloc_isr_ict(struct iwl_priv *priv);
 void iwl_free_isr_ict(struct iwl_priv *priv);
 irqreturn_t iwl_isr_ict(int irq, void *data);
+bool iwl_good_ack_health(struct iwl_priv *priv,
+                        struct iwl_rx_packet *pkt);
+
+/* tx queue */
+void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
+                    int txq_id, u32 index);
+void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
+                            struct iwl_tx_queue *txq,
+                            int tx_fifo_id, int scd_retry);
+void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+                                   struct iwl_tx_queue *txq,
+                                   u16 byte_cnt);
+void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+                                  struct iwl_tx_queue *txq);
+int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+                         int tx_fifo, int sta_id, int tid, u16 ssn_idx);
+int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+                          u16 ssn_idx, u8 tx_fifo);
+void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
+
+/* uCode */
+int iwlagn_load_ucode(struct iwl_priv *priv);
+void iwlagn_rx_calib_result(struct iwl_priv *priv,
+                        struct iwl_rx_mem_buffer *rxb);
+void iwlagn_rx_calib_complete(struct iwl_priv *priv,
+                          struct iwl_rx_mem_buffer *rxb);
+void iwlagn_init_alive_start(struct iwl_priv *priv);
+int iwlagn_alive_notify(struct iwl_priv *priv);
+
+/* lib */
+void iwl_check_abort_status(struct iwl_priv *priv,
+                           u8 frame_count, u32 status);
+void iwlagn_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_setup_deferred_work(struct iwl_priv *priv);
+int iwlagn_hw_valid_rtc_data_addr(u32 addr);
+int iwlagn_send_tx_power(struct iwl_priv *priv);
+void iwlagn_temperature(struct iwl_priv *priv);
+u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
+const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
+                                  size_t offset);
+void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_hw_nic_init(struct iwl_priv *priv);
+
+/* rx */
+void iwlagn_rx_queue_restock(struct iwl_priv *priv);
+void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
+void iwlagn_rx_replenish(struct iwl_priv *priv);
+void iwlagn_rx_replenish_now(struct iwl_priv *priv);
+void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_rxq_stop(struct iwl_priv *priv);
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
+void iwlagn_rx_reply_rx(struct iwl_priv *priv,
+                    struct iwl_rx_mem_buffer *rxb);
+void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+                        struct iwl_rx_mem_buffer *rxb);
+
+/* tx */
+void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+                             struct ieee80211_tx_info *info);
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+int iwlagn_tx_agg_start(struct iwl_priv *priv,
+                       const u8 *ra, u16 tid, u16 *ssn);
+int iwlagn_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
+int iwlagn_txq_check_empty(struct iwl_priv *priv,
+                          int sta_id, u8 tid, int txq_id);
+void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb);
+int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
+int iwlagn_txq_ctx_alloc(struct iwl_priv *priv);
+void iwlagn_txq_ctx_reset(struct iwl_priv *priv);
+void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
+
+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_SUCCESS:
+       case TX_STATUS_DIRECT_DONE:
+               return IEEE80211_TX_STAT_ACK;
+       case TX_STATUS_FAIL_DEST_PS:
+               return IEEE80211_TX_STAT_TX_FILTERED;
+       default:
+               return 0;
+       }
+}
+
+static inline bool iwl_is_tx_success(u32 status)
+{
+       status &= TX_STATUS_MSK;
+       return (status == TX_STATUS_SUCCESS) ||
+              (status == TX_STATUS_DIRECT_DONE);
+}
 
 #endif /* __iwl_agn_h__ */
index de3b3f4..0471c3f 100644 (file)
@@ -593,7 +593,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
        IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
 
        if (!rx_enable_time) {
-               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0! \n");
+               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
                return;
        }
 
index 6383d9f..d830086 100644 (file)
@@ -106,7 +106,7 @@ enum {
        REPLY_TX = 0x1c,
        REPLY_RATE_SCALE = 0x47,        /* 3945 only */
        REPLY_LEDS_CMD = 0x48,
-       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */
 
        /* WiMAX coexistence */
        COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */
@@ -512,8 +512,9 @@ struct iwl_init_alive_resp {
  *
  *     Entries without timestamps contain only event_id and data.
  *
+ *
  * 2)  error_event_table_ptr indicates base of the error log.  This contains
- *     information about any uCode error that occurs.  For 4965, the format
+ *     information about any uCode error that occurs.  For agn, the format
  *     of the error log is:
  *
  *     __le32 valid;        (nonzero) valid, (0) log is empty
@@ -529,6 +530,30 @@ struct iwl_init_alive_resp {
  *     __le32 bcon_time;    beacon timer
  *     __le32 tsf_low;      network timestamp function timer
  *     __le32 tsf_hi;       network timestamp function timer
+ *     __le32 gp1;          GP1 timer register
+ *     __le32 gp2;          GP2 timer register
+ *     __le32 gp3;          GP3 timer register
+ *     __le32 ucode_ver;    uCode version
+ *     __le32 hw_ver;       HW Silicon version
+ *     __le32 brd_ver;      HW board version
+ *     __le32 log_pc;       log program counter
+ *     __le32 frame_ptr;    frame pointer
+ *     __le32 stack_ptr;    stack pointer
+ *     __le32 hcmd;         last host command
+ *     __le32 isr0;         isr status register LMPM_NIC_ISR0: rxtx_flag
+ *     __le32 isr1;         isr status register LMPM_NIC_ISR1: host_flag
+ *     __le32 isr2;         isr status register LMPM_NIC_ISR2: enc_flag
+ *     __le32 isr3;         isr status register LMPM_NIC_ISR3: time_flag
+ *     __le32 isr4;         isr status register LMPM_NIC_ISR4: wico interrupt
+ *     __le32 isr_pref;     isr status register LMPM_NIC_PREF_STAT
+ *     __le32 wait_event;   wait event() caller address
+ *     __le32 l2p_control;  L2pControlField
+ *     __le32 l2p_duration; L2pDurationField
+ *     __le32 l2p_mhvalid;  L2pMhValidBits
+ *     __le32 l2p_addr_match; L2pAddrMatchStat
+ *     __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
+ *     __le32 u_timestamp;  indicate when the date and time of the compilation
+ *     __le32 reserved;
  *
  * The Linux driver can print both logs to the system log when a uCode error
  * occurs.
@@ -1637,7 +1662,7 @@ struct iwl_tx_cmd {
        struct ieee80211_hdr hdr[0];
 } __attribute__ ((packed));
 
-/* TX command response is sent after *all* transmission attempts.
+/* TX command response is sent after *3945* transmission attempts.
  *
  * NOTES:
  *
@@ -1665,24 +1690,65 @@ struct iwl_tx_cmd {
  * control line.  Receiving is still allowed in this case.
  */
 enum {
+       TX_3945_STATUS_SUCCESS = 0x01,
+       TX_3945_STATUS_DIRECT_DONE = 0x02,
+       TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82,
+       TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83,
+       TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+       TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85,
+       TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86,
+       TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+       TX_3945_STATUS_FAIL_DEST_PS = 0x88,
+       TX_3945_STATUS_FAIL_ABORTED = 0x89,
+       TX_3945_STATUS_FAIL_BT_RETRY = 0x8a,
+       TX_3945_STATUS_FAIL_STA_INVALID = 0x8b,
+       TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+       TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d,
+       TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+       TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+       TX_3945_STATUS_FAIL_TX_LOCKED = 0x90,
+       TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+/*
+ * TX command response is sent after *agn* transmission attempts.
+ *
+ * both postpone and abort status are expected behavior from uCode. there is
+ * no special operation required from driver; except for RFKILL_FLUSH,
+ * which required tx flush host command to flush all the tx frames in queues
+ */
+enum {
        TX_STATUS_SUCCESS = 0x01,
        TX_STATUS_DIRECT_DONE = 0x02,
+       /* postpone TX */
+       TX_STATUS_POSTPONE_DELAY = 0x40,
+       TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+       TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+       TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+       TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+       /* abort TX */
+       TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
        TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
        TX_STATUS_FAIL_LONG_LIMIT = 0x83,
        TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-       TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
-       TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+       TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+       TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
        TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
        TX_STATUS_FAIL_DEST_PS = 0x88,
-       TX_STATUS_FAIL_ABORTED = 0x89,
+       TX_STATUS_FAIL_HOST_ABORTED = 0x89,
        TX_STATUS_FAIL_BT_RETRY = 0x8a,
        TX_STATUS_FAIL_STA_INVALID = 0x8b,
        TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
        TX_STATUS_FAIL_TID_DISABLE = 0x8d,
-       TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+       TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
        TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-       TX_STATUS_FAIL_TX_LOCKED = 0x90,
-       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+       /* uCode drop due to FW drop request */
+       TX_STATUS_FAIL_FW_DROP = 0x90,
+       /*
+        * uCode drop due to station color mismatch
+        * between tx command and station table
+        */
+       TX_STATUS_FAIL_STA_COLOR_MISMATCH_DROP = 0x91,
 };
 
 #define        TX_PACKET_MODE_REGULAR          0x0000
@@ -1704,30 +1770,6 @@ enum {
        TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
 };
 
-static inline u32 iwl_tx_status_to_mac80211(u32 status)
-{
-       status &= TX_STATUS_MSK;
-
-       switch (status) {
-       case TX_STATUS_SUCCESS:
-       case TX_STATUS_DIRECT_DONE:
-               return IEEE80211_TX_STAT_ACK;
-       case TX_STATUS_FAIL_DEST_PS:
-               return IEEE80211_TX_STAT_TX_FILTERED;
-       default:
-               return 0;
-       }
-}
-
-static inline bool iwl_is_tx_success(u32 status)
-{
-       status &= TX_STATUS_MSK;
-       return (status == TX_STATUS_SUCCESS) ||
-              (status == TX_STATUS_DIRECT_DONE);
-}
-
-
-
 /* *******************************
  * TX aggregation status
  ******************************* */
index 0ee8cc2..2a89747 100644 (file)
@@ -66,7 +66,7 @@ MODULE_LICENSE("GPL");
  */
 static bool bt_coex_active = true;
 module_param(bt_coex_active, bool, S_IRUGO);
-MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n");
+MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
 
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
@@ -141,30 +141,6 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
 };
 EXPORT_SYMBOL(iwl_rates);
 
-/**
- * translate ucode response to mac80211 tx status control values
- */
-void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                                 struct ieee80211_tx_info *info)
-{
-       struct ieee80211_tx_rate *r = &info->control.rates[0];
-
-       info->antenna_sel_tx =
-               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               r->flags |= IEEE80211_TX_RC_MCS;
-       if (rate_n_flags & RATE_MCS_GF_MSK)
-               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-       if (rate_n_flags & RATE_MCS_DUP_MSK)
-               r->flags |= IEEE80211_TX_RC_DUP_DATA;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               r->flags |= IEEE80211_TX_RC_SHORT_GI;
-       r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band);
-}
-EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
-
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 {
        int idx = 0;
@@ -196,27 +172,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 }
 EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
 
-int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
-{
-       int idx = 0;
-       int band_offset = 0;
-
-       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
-       if (rate_n_flags & RATE_MCS_HT_MSK) {
-               idx = (rate_n_flags & 0xff);
-               return idx;
-       /* Legacy rate format, search for match in table */
-       } else {
-               if (band == IEEE80211_BAND_5GHZ)
-                       band_offset = IWL_FIRST_OFDM_RATE;
-               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
-                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
-                               return idx - band_offset;
-       }
-
-       return -1;
-}
-
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
 {
        int i;
@@ -266,74 +221,16 @@ void iwl_hw_detect(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_hw_detect);
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
-{
-       unsigned long flags;
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       int ret;
-
-       /* nic_init */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->cfg->ops->lib->apm_ops.init(priv);
-
-       /* Set interrupt coalescing calibration timer to default (512 usecs) */
-       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
-
-       priv->cfg->ops->lib->apm_ops.config(priv);
-
-       /* Allocate the RX queue, or reset if it is already allocated */
-       if (!rxq->bd) {
-               ret = iwl_rx_queue_alloc(priv);
-               if (ret) {
-                       IWL_ERR(priv, "Unable to initialize Rx queue\n");
-                       return -ENOMEM;
-               }
-       } else
-               iwl_rx_queue_reset(priv, rxq);
-
-       iwl_rx_replenish(priv);
-
-       iwl_rx_init(priv, rxq);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       rxq->need_update = 1;
-       iwl_rx_queue_update_write_ptr(priv, rxq);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Allocate or reset and init all Tx and Command queues */
-       if (!priv->txq) {
-               ret = iwl_txq_ctx_alloc(priv);
-               if (ret)
-                       return ret;
-       } else
-               iwl_txq_ctx_reset(priv);
-
-       set_bit(STATUS_INIT, &priv->status);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_hw_nic_init);
-
 /*
  * QoS  support
 */
-void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl_update_qos(struct iwl_priv *priv)
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        priv->qos_data.def_qos_parm.qos_flags = 0;
 
-       if (priv->qos_data.qos_cap.q_AP.queue_request &&
-           !priv->qos_data.qos_cap.q_AP.txop_request)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
        if (priv->qos_data.qos_active)
                priv->qos_data.def_qos_parm.qos_flags |=
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
@@ -341,118 +238,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force)
        if (priv->current_ht_config.is_ht)
                priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-       if (force || iwl_is_associated(priv)) {
-               IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                               priv->qos_data.qos_active,
-                               priv->qos_data.def_qos_parm.qos_flags);
-
-               iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
-                                      sizeof(struct iwl_qosparam_cmd),
-                                      &priv->qos_data.def_qos_parm, NULL);
-       }
-}
-EXPORT_SYMBOL(iwl_activate_qos);
-
-/*
- * AC        CWmin         CW max      AIFSN      TXOP Limit    TXOP Limit
- *                                              (802.11b)      (802.11a/g)
- * AC_BK      15            1023        7           0               0
- * AC_BE      15            1023        3           0               0
- * AC_VI       7              15        2          6.016ms       3.008ms
- * AC_VO       3               7        2          3.264ms       1.504ms
- */
-void iwl_reset_qos(struct iwl_priv *priv)
-{
-       u16 cw_min = 15;
-       u16 cw_max = 1023;
-       u8 aifs = 2;
-       bool is_legacy = false;
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       /* QoS always active in AP and ADHOC mode
-        * In STA mode wait for association
-        */
-       if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
-           priv->iw_mode == NL80211_IFTYPE_AP)
-               priv->qos_data.qos_active = 1;
-       else
-               priv->qos_data.qos_active = 0;
-
-       /* check for legacy mode */
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
-           (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
-           (priv->iw_mode == NL80211_IFTYPE_STATION &&
-           (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
-               cw_min = 31;
-               is_legacy = 1;
-       }
-
-       if (priv->qos_data.qos_active)
-               aifs = 3;
-
-       /* AC_BE */
-       priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
-       priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
-       priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
-       priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
-       priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
-
-       if (priv->qos_data.qos_active) {
-               /* AC_BK */
-               i = 1;
-               priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
-               priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
-               priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
-               /* AC_VI */
-               i = 2;
-               priv->qos_data.def_qos_parm.ac[i].cw_min =
-                       cpu_to_le16((cw_min + 1) / 2 - 1);
-               priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16(cw_min);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
-               if (is_legacy)
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(6016);
-               else
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(3008);
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
-               /* AC_VO */
-               i = 3;
-               priv->qos_data.def_qos_parm.ac[i].cw_min =
-                       cpu_to_le16((cw_min + 1) / 4 - 1);
-               priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16((cw_min + 1) / 2 - 1);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-               if (is_legacy)
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(3264);
-               else
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(1504);
-       } else {
-               for (i = 1; i < 4; i++) {
-                       priv->qos_data.def_qos_parm.ac[i].cw_min =
-                               cpu_to_le16(cw_min);
-                       priv->qos_data.def_qos_parm.ac[i].cw_max =
-                               cpu_to_le16(cw_max);
-                       priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
-                       priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-               }
-       }
-       IWL_DEBUG_QOS(priv, "set QoS to default \n");
+       IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+                     priv->qos_data.qos_active,
+                     priv->qos_data.def_qos_parm.qos_flags);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+                              sizeof(struct iwl_qosparam_cmd),
+                              &priv->qos_data.def_qos_parm, NULL);
 }
-EXPORT_SYMBOL(iwl_reset_qos);
 
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
 #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
@@ -1092,12 +885,12 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
        rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
 
        /* copied from 'iwl_bg_request_scan()' */
-       /* Force use of chains B and C (0x6) for Rx for 4965
-        * Avoid A (0x1) because of its off-channel reception on A-band.
+       /* Force use of chains B and C (0x6) for Rx
+        * Avoid A (0x1) for the device has off-channel reception on A-band.
         * MIMO is not used here, but value is required */
        if (iwl_is_monitor_mode(priv) &&
            !(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) &&
-           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) {
+           priv->cfg->off_channel_workaround) {
                rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS;
                rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS;
                rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
@@ -1584,10 +1377,11 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        int ret = 0;
        s8 prev_tx_power = priv->tx_power_user_lmt;
 
-       if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
-               IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
+       if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
+               IWL_WARN(priv,
+                        "Requested user TXPOWER %d below lower limit %d.\n",
                         tx_power,
-                        IWL_TX_POWER_TARGET_POWER_MIN);
+                        IWLAGN_TX_POWER_TARGET_POWER_MIN);
                return -EINVAL;
        }
 
@@ -1631,10 +1425,11 @@ irqreturn_t iwl_isr_legacy(int irq, void *data)
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
        u32 inta_fh;
+       unsigned long flags;
        if (!priv)
                return IRQ_NONE;
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         *    back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1672,7 +1467,7 @@ irqreturn_t iwl_isr_legacy(int irq, void *data)
                tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_HANDLED;
 
  none:
@@ -1680,7 +1475,7 @@ irqreturn_t iwl_isr_legacy(int irq, void *data)
        /* only Re-enable if diabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_NONE;
 }
 EXPORT_SYMBOL(iwl_isr_legacy);
@@ -1993,12 +1788,6 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                        cpu_to_le16((params->txop * 32));
 
        priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-       priv->qos_data.qos_active = 1;
-
-       if (priv->iw_mode == NL80211_IFTYPE_AP)
-               iwl_activate_qos(priv, 1);
-       else if (priv->assoc_id && iwl_is_associated(priv))
-               iwl_activate_qos(priv, 0);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2013,7 +1802,7 @@ static void iwl_ht_conf(struct iwl_priv *priv,
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
        struct ieee80211_sta *sta;
 
-       IWL_DEBUG_MAC80211(priv, "enter: \n");
+       IWL_DEBUG_MAC80211(priv, "enter:\n");
 
        if (!ht_conf->is_ht)
                return;
@@ -2269,11 +2058,8 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_reset_qos(priv);
-
        priv->cfg->ops->lib->post_associate(priv);
 
-
        return 0;
 }
 EXPORT_SYMBOL(iwl_mac_beacon_update);
@@ -2495,6 +2281,15 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_tx_power(priv, conf->power_level, false);
        }
 
+       if (changed & IEEE80211_CONF_CHANGE_QOS) {
+               bool qos_active = !!(conf->flags & IEEE80211_CONF_QOS);
+
+               spin_lock_irqsave(&priv->lock, flags);
+               priv->qos_data.qos_active = qos_active;
+               iwl_update_qos(priv);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
@@ -2529,8 +2324,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
        memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_reset_qos(priv);
-
        spin_lock_irqsave(&priv->lock, flags);
        priv->assoc_id = 0;
        priv->assoc_capability = 0;
@@ -2574,7 +2367,7 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv)
                        sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
                        GFP_KERNEL);
        if (!priv->txq) {
-               IWL_ERR(priv, "Not enough memory for txq \n");
+               IWL_ERR(priv, "Not enough memory for txq\n");
                return -ENOMEM;
        }
        return 0;
index f3b6c72..d89755f 100644 (file)
@@ -305,6 +305,9 @@ struct iwl_cfg {
        s32 chain_noise_scale;
        /* timer period for monitor the driver queues */
        u32 monitor_recover_period;
+       bool temperature_kelvin;
+       bool off_channel_workaround;
+       u32 max_event_log_size;
 };
 
 /***************************
@@ -314,8 +317,7 @@ struct iwl_cfg {
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
                struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_reset_qos(struct iwl_priv *priv);
-void iwl_activate_qos(struct iwl_priv *priv, u8 force);
+void iwl_activate_qos(struct iwl_priv *priv);
 int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                    const struct ieee80211_tx_queue_params *params);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
@@ -336,7 +338,6 @@ void iwl_irq_handle_error(struct iwl_priv *priv);
 void iwl_configure_filter(struct ieee80211_hw *hw,
                          unsigned int changed_flags,
                          unsigned int *total_flags, u64 multicast);
-int iwl_hw_nic_init(struct iwl_priv *priv);
 int iwl_set_hw_params(struct iwl_priv *priv);
 bool iwl_is_monitor_mode(struct iwl_priv *priv);
 void iwl_post_associate(struct iwl_priv *priv);
@@ -420,21 +421,13 @@ void iwl_rx_reply_error(struct iwl_priv *priv,
 /*****************************************************
 * RX
 ******************************************************/
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 void iwl_cmd_queue_free(struct iwl_priv *priv);
 int iwl_rx_queue_alloc(struct iwl_priv *priv);
 void iwl_rx_handle(struct iwl_priv *priv);
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
                                  struct iwl_rx_queue *q);
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-void iwl_rx_replenish(struct iwl_priv *priv);
-void iwl_rx_replenish_now(struct iwl_priv *priv);
-int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-void iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
-void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 /* Handlers */
 void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb);
@@ -455,14 +448,10 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 /*****************************************************
 * TX
 ******************************************************/
-int iwl_txq_ctx_alloc(struct iwl_priv *priv);
-void iwl_txq_ctx_reset(struct iwl_priv *priv);
 void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
                                 struct iwl_tx_queue *txq,
                                 dma_addr_t addr, u16 len, u8 reset, u8 pad);
-int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
                         struct iwl_tx_queue *txq);
 void iwl_free_tfds_in_queue(struct iwl_priv *priv,
@@ -473,9 +462,6 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                        int slots_num, u32 txq_id);
 void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
-int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
-int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
-int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
 /*****************************************************
  * TX power
  ****************************************************/
@@ -485,10 +471,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
  * Rate
  ******************************************************************************/
 
-void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                             struct ieee80211_tx_info *info);
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
-int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 
 u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
 
@@ -688,12 +671,6 @@ extern int iwl_send_statistics_request(struct iwl_priv *priv,
 extern int iwl_verify_ucode(struct iwl_priv *priv);
 extern int iwl_send_lq_cmd(struct iwl_priv *priv,
                struct iwl_link_quality_cmd *lq, u8 flags, bool init);
-extern void iwl_rx_reply_rx(struct iwl_priv *priv,
-               struct iwl_rx_mem_buffer *rxb);
-extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb);
-void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl_rx_mem_buffer *rxb);
 void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
index e847e61..9466e90 100644 (file)
@@ -43,6 +43,7 @@
 #include "iwl-debug.h"
 #include "iwl-4965-hw.h"
 #include "iwl-3945-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-led.h"
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
@@ -57,6 +58,7 @@ extern struct iwl_cfg iwl5100_abg_cfg;
 extern struct iwl_cfg iwl5150_agn_cfg;
 extern struct iwl_cfg iwl5150_abg_cfg;
 extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_g2_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2abg_cfg;
 extern struct iwl_cfg iwl6000i_2bg_cfg;
 extern struct iwl_cfg iwl6000_3agn_cfg;
@@ -67,45 +69,6 @@ extern struct iwl_cfg iwl1000_bg_cfg;
 
 struct iwl_tx_queue;
 
-/* shared structures from iwl-5000.c */
-extern struct iwl_mod_params iwl50_mod_params;
-extern struct iwl_ucode_ops iwl5000_ucode;
-extern struct iwl_lib_ops iwl5000_lib;
-extern struct iwl_hcmd_ops iwl5000_hcmd;
-extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
-
-/* shared functions from iwl-5000.c */
-extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
-extern u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd,
-                                    u8 *data);
-extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                                   __le32 *tx_flags);
-extern int iwl5000_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp);
-extern void iwl5000_nic_config(struct iwl_priv *priv);
-extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
-extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
-                                   size_t offset);
-extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
-                                           struct iwl_tx_queue *txq,
-                                           u16 byte_cnt);
-extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
-                                   struct iwl_tx_queue *txq);
-extern int iwl5000_load_ucode(struct iwl_priv *priv);
-extern void iwl5000_init_alive_start(struct iwl_priv *priv);
-extern int iwl5000_alive_notify(struct iwl_priv *priv);
-extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
-extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-                          int tx_fifo, int sta_id, int tid, u16 ssn_idx);
-extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-                           u16 ssn_idx, u8 tx_fifo);
-extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
-extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
-extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
-extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
-extern int iwl5000_send_tx_power(struct iwl_priv *priv);
-extern void iwl5000_temperature(struct iwl_priv *priv);
-
 /* CT-KILL constants */
 #define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
 #define CT_KILL_THRESHOLD         114 /* in Celsius */
@@ -363,13 +326,6 @@ enum {
 
 #define DEF_CMD_PAYLOAD_SIZE 320
 
-/*
- * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
- * SNAP header and alignment. It should also be big enough for 802.11
- * control frames.
- */
-#define IWL_LINK_HDR_MAX 64
-
 /**
  * struct iwl_device_cmd
  *
@@ -521,30 +477,9 @@ struct iwl_ht_config {
        u8 non_GF_STA_present;
 };
 
-union iwl_qos_capabity {
-       struct {
-               u8 edca_count:4;        /* bit 0-3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 queue_request:1;     /* bit 5 */
-               u8 txop_request:1;      /* bit 6 */
-               u8 reserved:1;          /* bit 7 */
-       } q_AP;
-       struct {
-               u8 acvo_APSD:1;         /* bit 0 */
-               u8 acvi_APSD:1;         /* bit 1 */
-               u8 ac_bk_APSD:1;        /* bit 2 */
-               u8 ac_be_APSD:1;        /* bit 3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 max_len:2;           /* bit 5-6 */
-               u8 more_data_ack:1;     /* bit 7 */
-       } q_STA;
-       u8 val;
-};
-
 /* QoS structures */
 struct iwl_qos_info {
        int qos_active;
-       union iwl_qos_capabity qos_cap;
        struct iwl_qosparam_cmd def_qos_parm;
 };
 
@@ -1185,7 +1120,6 @@ struct iwl_priv {
        __le16 sensitivity_tbl[HD_TABLE_SIZE];
 
        struct iwl_ht_config current_ht_config;
-       u8 last_phy_res[100];
 
        /* Rate scaling data */
        u8 retry_rate;
@@ -1205,8 +1139,6 @@ struct iwl_priv {
 
        unsigned long status;
 
-       int last_rx_noise;      /* From beacon statistics */
-
        /* counts mgmt, ctl, and data packets */
        struct traffic_stats tx_stats;
        struct traffic_stats rx_stats;
@@ -1234,7 +1166,6 @@ struct iwl_priv {
        int num_stations;
        struct iwl_station_entry stations[IWL_STATION_COUNT];
        struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
-       u8 default_wep_key;
        u8 key_mapping_key;
        unsigned long ucode_key_table;
 
@@ -1305,6 +1236,9 @@ struct iwl_priv {
                         * no AGGREGATION
                         */
                        u8 agg_tids_count;
+
+                       struct iwl_rx_phy_res last_phy_res;
+                       bool last_phy_res_valid;
                } _agn;
 #endif
        };
index 2ffc2ed..4a48763 100644 (file)
@@ -37,6 +37,7 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
index 4e1ba82..cb6d50b 100644 (file)
@@ -188,19 +188,19 @@ struct iwl_eeprom_enhanced_txpwr {
 /* 5000 regulatory - indirect access */
 #define EEPROM_5000_REG_SKU_ID ((0x02)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 4  bytes */
-#define EEPROM_5000_REG_BAND_1_CHANNELS       ((0x08)\
+#define EEPROM_REG_BAND_1_CHANNELS       ((0x08)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 28 bytes */
-#define EEPROM_5000_REG_BAND_2_CHANNELS       ((0x26)\
+#define EEPROM_REG_BAND_2_CHANNELS       ((0x26)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 26 bytes */
-#define EEPROM_5000_REG_BAND_3_CHANNELS       ((0x42)\
+#define EEPROM_REG_BAND_3_CHANNELS       ((0x42)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 24 bytes */
-#define EEPROM_5000_REG_BAND_4_CHANNELS       ((0x5C)\
+#define EEPROM_REG_BAND_4_CHANNELS       ((0x5C)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22 bytes */
-#define EEPROM_5000_REG_BAND_5_CHANNELS       ((0x74)\
+#define EEPROM_REG_BAND_5_CHANNELS       ((0x74)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 12 bytes */
-#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS  ((0x82)\
+#define EEPROM_REG_BAND_24_HT40_CHANNELS  ((0x82)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS  ((0x92)\
+#define EEPROM_REG_BAND_52_HT40_CHANNELS  ((0x92)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
 
 /* 6000 and up regulatory tx power - indirect access */
@@ -261,12 +261,15 @@ struct iwl_eeprom_enhanced_txpwr {
 #define EEPROM_5050_EEPROM_VERSION     (0x21E)
 
 /* 1000 Specific */
+#define EEPROM_1000_TX_POWER_VERSION    (4)
 #define EEPROM_1000_EEPROM_VERSION     (0x15C)
 
 /* 6x00 Specific */
+#define EEPROM_6000_TX_POWER_VERSION    (4)
 #define EEPROM_6000_EEPROM_VERSION     (0x434)
 
 /* 6x50 Specific */
+#define EEPROM_6050_TX_POWER_VERSION    (4)
 #define EEPROM_6050_EEPROM_VERSION     (0x532)
 
 /* OTP */
index 73681c4..51f89e7 100644 (file)
@@ -169,7 +169,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        mutex_lock(&priv->sync_cmd_mutex);
 
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
-       IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
+       IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
 
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
@@ -191,7 +191,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
                        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-                       IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+                       IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                                       get_cmd_string(cmd->id));
                        ret = -ETIMEDOUT;
                        goto cancel;
index 16eb3ce..0203a3b 100644 (file)
@@ -298,7 +298,7 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l,
                                        struct iwl_priv *priv, u32 reg)
 {
        u32 value = _iwl_read_direct32(priv, reg);
-       IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+       IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value,
                     f, l);
        return value;
 }
index a6f9c91..db5bfcb 100644 (file)
@@ -46,7 +46,7 @@
 static int led_mode;
 module_param(led_mode, int, S_IRUGO);
 MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
-                          "(default 0)\n");
+                          "(default 0)");
 
 
 static const struct {
index 548dac2..581c683 100644 (file)
@@ -384,10 +384,10 @@ EXPORT_SYMBOL(iwl_ht_enabled);
 
 bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
 {
-       s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
        bool within_margin = false;
 
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+       if (priv->cfg->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -840,12 +840,12 @@ EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
 static void iwl_bg_tt_work(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
-       s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+       if (priv->cfg->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -875,7 +875,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
        int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
        struct iwl_tt_trans *transaction;
 
-       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
+       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
 
        memset(tt, 0, sizeof(struct iwl_tt_mgmt));
 
index d3b2fb3..267eb89 100644 (file)
@@ -163,197 +163,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
        spin_unlock_irqrestore(&q->lock, flags);
 }
 EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
-/**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
-                                         dma_addr_t dma_addr)
-{
-       return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-void iwl_rx_queue_restock(struct iwl_priv *priv)
-{
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       unsigned long flags;
-       int write;
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       write = rxq->write & ~0x7;
-       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-               /* Get next free Rx buffer, remove from free list */
-               element = rxq->rx_free.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
-               rxq->queue[rxq->write] = rxb;
-               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
-               rxq->free_count--;
-       }
-       spin_unlock_irqrestore(&rxq->lock, flags);
-       /* If the pre-allocated buffer pool is dropping low, schedule to
-        * refill it */
-       if (rxq->free_count <= RX_LOW_WATERMARK)
-               queue_work(priv->workqueue, &priv->rx_replenish);
-
-
-       /* If we've added more space for the firmware to place data, tell it.
-        * Increment device's write pointer in multiples of 8. */
-       if (rxq->write_actual != (rxq->write & ~0x7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
-               iwl_rx_queue_update_write_ptr(priv, rxq);
-       }
-}
-EXPORT_SYMBOL(iwl_rx_queue_restock);
-
-
-/**
- * iwl_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
-{
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       struct page *page;
-       unsigned long flags;
-       gfp_t gfp_mask = priority;
-
-       while (1) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       return;
-               }
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               if (rxq->free_count > RX_LOW_WATERMARK)
-                       gfp_mask |= __GFP_NOWARN;
-
-               if (priv->hw_params.rx_page_order > 0)
-                       gfp_mask |= __GFP_COMP;
-
-               /* Alloc a new receive buffer */
-               page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
-               if (!page) {
-                       if (net_ratelimit())
-                               IWL_DEBUG_INFO(priv, "alloc_pages failed, "
-                                              "order: %d\n",
-                                              priv->hw_params.rx_page_order);
-
-                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
-                           net_ratelimit())
-                               IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
-                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
-                                        rxq->free_count);
-                       /* We don't reschedule replenish work here -- we will
-                        * call the restock method and if it still needs
-                        * more buffers it will schedule replenish */
-                       return;
-               }
-
-               spin_lock_irqsave(&rxq->lock, flags);
-
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       __free_pages(page, priv->hw_params.rx_page_order);
-                       return;
-               }
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               rxb->page = page;
-               /* Get physical address of the RB */
-               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-               /* dma address must be no more than 36 bits */
-               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-               /* and also 256 byte aligned! */
-               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-               spin_lock_irqsave(&rxq->lock, flags);
-
-               list_add_tail(&rxb->list, &rxq->rx_free);
-               rxq->free_count++;
-               priv->alloc_rxb_page++;
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-       }
-}
-
-void iwl_rx_replenish(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       iwl_rx_allocate(priv, GFP_KERNEL);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_rx_queue_restock(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_rx_replenish);
-
-void iwl_rx_replenish_now(struct iwl_priv *priv)
-{
-       iwl_rx_allocate(priv, GFP_ATOMIC);
-
-       iwl_rx_queue_restock(priv);
-}
-EXPORT_SYMBOL(iwl_rx_replenish_now);
-
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       int i;
-       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-               if (rxq->pool[i].page != NULL) {
-                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-                       __iwl_free_pages(priv, rxq->pool[i].page);
-                       rxq->pool[i].page = NULL;
-               }
-       }
-
-       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                         rxq->dma_addr);
-       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
-                         rxq->rb_stts, rxq->rb_stts_dma);
-       rxq->bd = NULL;
-       rxq->rb_stts  = NULL;
-}
-EXPORT_SYMBOL(iwl_rx_queue_free);
 
 int iwl_rx_queue_alloc(struct iwl_priv *priv)
 {
@@ -396,98 +205,6 @@ err_bd:
 }
 EXPORT_SYMBOL(iwl_rx_queue_alloc);
 
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       unsigned long flags;
-       int i;
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-               /* In the reset function, these buffers may have been allocated
-                * to an SKB, so we need to unmap and free potential storage */
-               if (rxq->pool[i].page != NULL) {
-                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-                       __iwl_free_pages(priv, rxq->pool[i].page);
-                       rxq->pool[i].page = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       u32 rb_size;
-       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-       u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-       if (!priv->cfg->use_isr_legacy)
-               rb_timeout = RX_RB_TIMEOUT;
-
-       if (priv->cfg->mod_params->amsdu_size_8K)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          (u32)(rxq->dma_addr >> 8));
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          rxq->rb_stts_dma >> 4);
-
-       /* Enable Rx DMA
-        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-        *      the credit mechanism in 5000 HW RX FIFO
-        * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
-        * RB timeout 0x10
-        * 256 RBDs
-        */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
-                          rb_size|
-                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-       /* Set interrupt coalescing timer to default (2048 usecs) */
-       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-
-       return 0;
-}
-
-int iwl_rxq_stop(struct iwl_priv *priv)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
-                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_rxq_stop);
-
 void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 
@@ -543,6 +260,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
                le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
        int bcn_silence_c =
                le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+       int last_rx_noise;
 
        if (bcn_silence_a) {
                total_silence += bcn_silence_a;
@@ -559,13 +277,13 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
 
        /* Average among active antennas */
        if (num_active_rx)
-               priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+               last_rx_noise = (total_silence / num_active_rx) - 107;
        else
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
        IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
                        bcn_silence_a, bcn_silence_b, bcn_silence_c,
-                       priv->last_rx_noise);
+                       last_rx_noise);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -617,63 +335,6 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
 
 #define REG_RECALIB_PERIOD (60)
 
-/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
-#define ACK_CNT_RATIO (50)
-#define BA_TIMEOUT_CNT (5)
-#define BA_TIMEOUT_MAX (16)
-
-#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE)
-/**
- * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
- *
- * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding
- * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
- * operation state.
- */
-bool iwl_good_ack_health(struct iwl_priv *priv,
-                               struct iwl_rx_packet *pkt)
-{
-       bool rc = true;
-       int actual_ack_cnt_delta, expected_ack_cnt_delta;
-       int ba_timeout_delta;
-
-       actual_ack_cnt_delta =
-               le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
-               le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
-       expected_ack_cnt_delta =
-               le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
-               le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
-       ba_timeout_delta =
-               le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
-               le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
-       if ((priv->_agn.agg_tids_count > 0) &&
-           (expected_ack_cnt_delta > 0) &&
-           (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
-               < ACK_CNT_RATIO) &&
-           (ba_timeout_delta > BA_TIMEOUT_CNT)) {
-               IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d,"
-                               " expected_ack_cnt = %d\n",
-                               actual_ack_cnt_delta, expected_ack_cnt_delta);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-               IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
-                               priv->delta_statistics.tx.rx_detected_cnt);
-               IWL_DEBUG_RADIO(priv,
-                               "ack_or_ba_timeout_collision delta = %d\n",
-                               priv->delta_statistics.tx.
-                               ack_or_ba_timeout_collision);
-#endif
-               IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
-                               ba_timeout_delta);
-               if (!actual_ack_cnt_delta &&
-                   (ba_timeout_delta >= BA_TIMEOUT_MAX))
-                       rc = false;
-       }
-       return rc;
-}
-EXPORT_SYMBOL(iwl_good_ack_health);
-#endif
-
 /**
  * iwl_good_plcp_health - checks for plcp error.
  *
@@ -830,139 +491,6 @@ void iwl_reply_statistics(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_reply_statistics);
 
-/* Calc max signal level (dBm) among 3 possible receivers */
-static inline int iwl_calc_rssi(struct iwl_priv *priv,
-                               struct iwl_rx_phy_res *rx_resp)
-{
-       return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-/**
- * iwl_dbg_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good data frames.
- *    All beacon and probe response frames are printed.
- */
-static void iwl_dbg_report_frame(struct iwl_priv *priv,
-                     struct iwl_rx_phy_res *phy_res, u16 length,
-                     struct ieee80211_hdr *header, int group100)
-{
-       u32 to_us;
-       u32 print_summary = 0;
-       u32 print_dump = 0;     /* set to 1 to dump all frames' contents */
-       u32 hundred = 0;
-       u32 dataframe = 0;
-       __le16 fc;
-       u16 seq_ctl;
-       u16 channel;
-       u16 phy_flags;
-       u32 rate_n_flags;
-       u32 tsf_low;
-       int rssi;
-
-       if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
-               return;
-
-       /* MAC header */
-       fc = header->frame_control;
-       seq_ctl = le16_to_cpu(header->seq_ctrl);
-
-       /* metadata */
-       channel = le16_to_cpu(phy_res->channel);
-       phy_flags = le16_to_cpu(phy_res->phy_flags);
-       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-       /* signal statistics */
-       rssi = iwl_calc_rssi(priv, phy_res);
-       tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
-
-       to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
-       /* if data frame is to us and all is good,
-        *   (optionally) print summary for only 1 out of every 100 */
-       if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
-           cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
-               dataframe = 1;
-               if (!group100)
-                       print_summary = 1;      /* print each frame */
-               else if (priv->framecnt_to_us < 100) {
-                       priv->framecnt_to_us++;
-                       print_summary = 0;
-               } else {
-                       priv->framecnt_to_us = 0;
-                       print_summary = 1;
-                       hundred = 1;
-               }
-       } else {
-               /* print summary for all other frames */
-               print_summary = 1;
-       }
-
-       if (print_summary) {
-               char *title;
-               int rate_idx;
-               u32 bitrate;
-
-               if (hundred)
-                       title = "100Frames";
-               else if (ieee80211_has_retry(fc))
-                       title = "Retry";
-               else if (ieee80211_is_assoc_resp(fc))
-                       title = "AscRsp";
-               else if (ieee80211_is_reassoc_resp(fc))
-                       title = "RasRsp";
-               else if (ieee80211_is_probe_resp(fc)) {
-                       title = "PrbRsp";
-                       print_dump = 1; /* dump frame contents */
-               } else if (ieee80211_is_beacon(fc)) {
-                       title = "Beacon";
-                       print_dump = 1; /* dump frame contents */
-               } else if (ieee80211_is_atim(fc))
-                       title = "ATIM";
-               else if (ieee80211_is_auth(fc))
-                       title = "Auth";
-               else if (ieee80211_is_deauth(fc))
-                       title = "DeAuth";
-               else if (ieee80211_is_disassoc(fc))
-                       title = "DisAssoc";
-               else
-                       title = "Frame";
-
-               rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
-               if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
-                       bitrate = 0;
-                       WARN_ON_ONCE(1);
-               } else {
-                       bitrate = iwl_rates[rate_idx].ieee / 2;
-               }
-
-               /* print frame summary.
-                * MAC addresses show just the last byte (for brevity),
-                *    but you can hack it to show more, if you'd like to. */
-               if (dataframe)
-                       IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
-                                    title, le16_to_cpu(fc), header->addr1[5],
-                                    length, rssi, channel, bitrate);
-               else {
-                       /* src/dst addresses assume managed mode */
-                       IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
-                                    "len=%u, rssi=%d, tim=%lu usec, "
-                                    "phy=0x%02x, chnl=%d\n",
-                                    title, le16_to_cpu(fc), header->addr1[5],
-                                    header->addr3[5], length, rssi,
-                                    tsf_low - priv->scan_start_tsf,
-                                    phy_flags, channel);
-               }
-       }
-       if (print_dump)
-               iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
-}
-#endif
-
 /*
  * returns non-zero if packet should be dropped
  */
@@ -1010,281 +538,3 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
        return 0;
 }
 EXPORT_SYMBOL(iwl_set_decrypted_flag);
-
-static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
-{
-       u32 decrypt_out = 0;
-
-       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
-                                       RX_RES_STATUS_STATION_FOUND)
-               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
-                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
-
-       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
-
-       /* packet was not encrypted */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_NONE)
-               return decrypt_out;
-
-       /* packet was encrypted with unknown alg */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_ERR)
-               return decrypt_out;
-
-       /* decryption was not done in HW */
-       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
-                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
-               return decrypt_out;
-
-       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
-
-       case RX_RES_STATUS_SEC_TYPE_CCMP:
-               /* alg is CCM: check MIC only */
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
-                       /* Bad MIC */
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-
-               break;
-
-       case RX_RES_STATUS_SEC_TYPE_TKIP:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
-                       /* Bad TTAK */
-                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
-                       break;
-               }
-               /* fall through if TTAK OK */
-       default:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-               break;
-       };
-
-       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
-                                       decrypt_in, decrypt_out);
-
-       return decrypt_out;
-}
-
-static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
-                                       struct ieee80211_hdr *hdr,
-                                       u16 len,
-                                       u32 ampdu_status,
-                                       struct iwl_rx_mem_buffer *rxb,
-                                       struct ieee80211_rx_status *stats)
-{
-       struct sk_buff *skb;
-       int ret = 0;
-       __le16 fc = hdr->frame_control;
-
-       /* We only process data packets if the interface is open */
-       if (unlikely(!priv->is_open)) {
-               IWL_DEBUG_DROP_LIMIT(priv,
-                   "Dropping packet while interface is not open.\n");
-               return;
-       }
-
-       /* In case of HW accelerated crypto and bad decryption, drop */
-       if (!priv->cfg->mod_params->sw_crypto &&
-           iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
-               return;
-
-       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
-       if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
-               return;
-       }
-
-       skb_reserve(skb, IWL_LINK_HDR_MAX);
-       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
-
-       /* mac80211 currently doesn't support paged SKB. Convert it to
-        * linear SKB for management frame and data frame requires
-        * software decryption or software defragementation. */
-       if (ieee80211_is_mgmt(fc) ||
-           ieee80211_has_protected(fc) ||
-           ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
-           (ieee80211_is_data_qos(fc) &&
-            *ieee80211_get_qos_ctl(hdr) &
-            IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
-               ret = skb_linearize(skb);
-       else
-               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
-                        0 : -ENOMEM;
-
-       if (ret) {
-               kfree_skb(skb);
-               goto out;
-       }
-
-       /*
-        * XXX: We cannot touch the page and its virtual memory (hdr) after
-        * here. It might have already been freed by the above skb change.
-        */
-
-       iwl_update_stats(priv, false, fc, len);
-       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
-
-       ieee80211_rx(priv->hw, skb);
- out:
-       priv->alloc_rxb_page--;
-       rxb->page = NULL;
-}
-
-/* Called for REPLY_RX (legacy ABG frames), or
- * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-void iwl_rx_reply_rx(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_rx_phy_res *phy_res;
-       __le32 rx_pkt_status;
-       struct iwl4965_rx_mpdu_res_start *amsdu;
-       u32 len;
-       u32 ampdu_status;
-       u32 rate_n_flags;
-
-       /**
-        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
-        *      REPLY_RX: physical layer info is in this buffer
-        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
-        *              command and cached in priv->last_phy_res
-        *
-        * Here we set up local variables depending on which command is
-        * received.
-        */
-       if (pkt->hdr.cmd == REPLY_RX) {
-               phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
-                               + phy_res->cfg_phy_cnt);
-
-               len = le16_to_cpu(phy_res->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
-                               phy_res->cfg_phy_cnt + len);
-               ampdu_status = le32_to_cpu(rx_pkt_status);
-       } else {
-               if (!priv->last_phy_res[0]) {
-                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-                       return;
-               }
-               phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
-               amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
-               len = le16_to_cpu(amsdu->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
-               ampdu_status = iwl_translate_rx_status(priv,
-                               le32_to_cpu(rx_pkt_status));
-       }
-
-       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
-               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
-                               phy_res->cfg_phy_cnt);
-               return;
-       }
-
-       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
-           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
-                               le32_to_cpu(rx_pkt_status));
-               return;
-       }
-
-       /* This will be used in several places later */
-       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-       /* rx_status carries information about the packet to mac80211 */
-       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
-       rx_status.freq =
-               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
-       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-       rx_status.rate_idx =
-               iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
-       rx_status.flag = 0;
-
-       /* TSF isn't reliable. In order to allow smooth user experience,
-        * this W/A doesn't propagate it to the mac80211 */
-       /*rx_status.flag |= RX_FLAG_TSFT;*/
-
-       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
-
-       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
-       rx_status.signal = iwl_calc_rssi(priv, phy_res);
-
-       /* Meaningful noise values are available only from beacon statistics,
-        *   which are gathered only when associated, and indicate noise
-        *   only for the associated network channel ...
-        * Ignore these noise values while scanning (other channels) */
-       if (iwl_is_associated(priv) &&
-           !test_bit(STATUS_SCANNING, &priv->status)) {
-               rx_status.noise = priv->last_rx_noise;
-       } else {
-               rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-       }
-
-       /* Reset beacon noise level if not associated. */
-       if (!iwl_is_associated(priv))
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       /* Set "1" to report good data frames in groups of 100 */
-       if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
-               iwl_dbg_report_frame(priv, phy_res, len, header, 1);
-#endif
-       iwl_dbg_log_rx_data_frame(priv, len, header);
-       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n",
-               rx_status.signal, rx_status.noise,
-               (unsigned long long)rx_status.mactime);
-
-       /*
-        * "antenna number"
-        *
-        * It seems that the antenna field in the phy flags value
-        * is actually a bit field. This is undefined by radiotap,
-        * it wants an actual antenna number but I always get "7"
-        * for most legacy frames I receive indicating that the
-        * same frame was received on all three RX chains.
-        *
-        * I think this field should be removed in favor of a
-        * new 802.11n radiotap field "RX chains" that is defined
-        * as a bitmask.
-        */
-       rx_status.antenna =
-               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
-               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
-
-       /* set the preamble flag if appropriate */
-       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-               rx_status.flag |= RX_FLAG_SHORTPRE;
-
-       /* Set up the HT phy flags */
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               rx_status.flag |= RX_FLAG_HT;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               rx_status.flag |= RX_FLAG_40MHZ;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               rx_status.flag |= RX_FLAG_SHORT_GI;
-
-       iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
-                                   rxb, &rx_status);
-}
-EXPORT_SYMBOL(iwl_rx_reply_rx);
-
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       priv->last_phy_res[0] = 1;
-       memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
-              sizeof(struct iwl_rx_phy_res));
-}
-EXPORT_SYMBOL(iwl_rx_reply_rx_phy);
index e8e4b54..ae98193 100644 (file)
@@ -454,7 +454,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                added++;
        }
 
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d \n", added);
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
        return added;
 }
 
@@ -814,10 +814,11 @@ static void iwl_bg_request_scan(struct work_struct *data)
                 */
                scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
 
-               /* Force use of chains B and C (0x6) for scan Rx for 4965
-                * Avoid A (0x1) because of its off-channel reception on A-band.
+               /* Force use of chains B and C (0x6) for scan Rx
+                * Avoid A (0x1) for the device has off-channel reception
+                * on A-band.
                 */
-               if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+               if (priv->cfg->off_channel_workaround)
                        rx_ant = ANT_BC;
        } else {
                IWL_WARN(priv, "Invalid scan band count\n");
index d401b6f..d86ecd2 100644 (file)
@@ -71,7 +71,7 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
            (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) ||
             ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) &&
              (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) {
-               IWL_ERR(priv, "Requested station info for sta %d before ready. \n",
+               IWL_ERR(priv, "Requested station info for sta %d before ready.\n",
                        ret);
                ret = IWL_INVALID_STATION;
        }
@@ -143,7 +143,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
                        sta_id);
                break;
        case ADD_STA_MODIFY_NON_EXIST_STA:
-               IWL_ERR(priv, "Attempting to modify non-existing station %d \n",
+               IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
                        sta_id);
                break;
        default:
@@ -194,7 +194,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                .flags = flags,
                .data = data,
        };
-       u8 sta_id = sta->sta.sta_id;
+       u8 sta_id __maybe_unused = sta->sta.sta_id;
 
        IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
                       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
@@ -425,6 +425,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
                .reserved1 = 0,
        };
        u32 rate_flags;
+       int ret = 0;
 
        /* Set up the rate scaling to start at selected rate, fall back
         * all the way down to 1M in IEEE order, and then spin on 1M */
@@ -458,8 +459,10 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
        /* Update the rate scaling for control frame Tx to AP */
        link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
 
-       iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD,
+       ret = iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD,
                               sizeof(link_cmd), &link_cmd);
+       if (ret)
+               IWL_ERR(priv, "REPLY_TX_LINK_QUALITY_CMD failed (%d)\n", ret);
 }
 
 /*
@@ -571,7 +574,7 @@ static int iwl_remove_station(struct iwl_priv *priv, struct ieee80211_sta *sta)
 
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_INFO(priv,
-                       "Unable to remove station %pM, device not ready. \n",
+                       "Unable to remove station %pM, device not ready.\n",
                        sta->addr);
                /*
                 * It is typical for stations to be removed when we are
@@ -668,7 +671,7 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force)
        } else {
                for (i = 0; i < priv->hw_params.max_stations; i++) {
                        if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
-                               IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d \n", i);
+                               IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
                                priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
                                cleared = true;
                        }
@@ -759,7 +762,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
 
-int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 {
        int i, not_empty = 0;
        u8 buff[sizeof(struct iwl_wep_cmd) +
@@ -803,7 +806,14 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        else
                return 0;
 }
-EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
+
+int iwl_restore_default_wep_keys(struct iwl_priv *priv)
+{
+       WARN_ON(!mutex_is_locked(&priv->mutex));
+
+       return iwl_send_static_wepkey_cmd(priv, 0);
+}
+EXPORT_SYMBOL(iwl_restore_default_wep_keys);
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *keyconf)
@@ -815,11 +825,6 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
        IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
                      keyconf->keyidx);
 
-       if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
-               IWL_ERR(priv, "index %d not used in uCode key table.\n",
-                         keyconf->keyidx);
-
-       priv->default_wep_key--;
        memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
@@ -851,12 +856,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
        keyconf->hw_key_idx = HW_KEY_DEFAULT;
        priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
 
-       priv->default_wep_key++;
-
-       if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
-               IWL_ERR(priv, "index %d already used in uCode key table.\n",
-                         keyconf->keyidx);
-
        priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
        memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
                                                        keyconf->keylen);
@@ -1105,7 +1104,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
        if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+               IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n");
                spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
@@ -1191,13 +1190,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
                .data = lq,
        };
 
-       if ((lq->sta_id == 0xFF) &&
-           (priv->iw_mode == NL80211_IFTYPE_ADHOC))
+       if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
                return -EINVAL;
 
-       if (lq->sta_id == 0xFF)
-               lq->sta_id = IWL_AP_ID;
-
        iwl_dump_lq_cmd(priv, lq);
        BUG_ON(init && (cmd.flags & CMD_ASYNC));
 
@@ -1207,7 +1202,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
                return ret;
 
        if (init) {
-               IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d \n",
+               IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d\n",
                               lq->sta_id);
                spin_lock_irqsave(&priv->sta_lock, flags_spin);
                priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
@@ -1395,6 +1390,7 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 
        iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
+EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
 
 int iwl_mac_sta_remove(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
index 87a3499..42cd2f4 100644 (file)
  */
 u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
 
-int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
                            struct ieee80211_key_conf *key);
+int iwl_restore_default_wep_keys(struct iwl_priv *priv);
 int iwl_set_dynamic_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *key, u8 sta_id);
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
index b798fba..1ece2ea 100644 (file)
 #include "iwl-io.h"
 #include "iwl-helpers.h"
 
-/*
- * mac80211 queues, ACs, hardware queues, FIFOs.
- *
- * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
- *
- * Mac80211 uses the following numbers, which we get as from it
- * by way of skb_get_queue_mapping(skb):
- *
- *     VO      0
- *     VI      1
- *     BE      2
- *     BK      3
- *
- *
- * Regular (not A-MPDU) frames are put into hardware queues corresponding
- * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
- * own queue per aggregation session (RA/TID combination), such queues are
- * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
- * order to map frames to the right queue, we also need an AC->hw queue
- * mapping. This is implemented here.
- *
- * Due to the way hw queues are set up (by the hw specific modules like
- * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity
- * mapping.
- */
-
-static const u8 tid_to_ac[] = {
-       /* this matches the mac80211 numbers */
-       2, 3, 3, 2, 1, 1, 0, 0
-};
-
-static const u8 ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-
-static inline int get_fifo_from_ac(u8 ac)
-{
-       return ac_to_fifo[ac];
-}
-
-static inline int get_queue_from_ac(u16 ac)
-{
-       return ac;
-}
-
-static inline int get_fifo_from_tid(u16 tid)
-{
-       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
-               return get_fifo_from_ac(tid_to_ac[tid]);
-
-       /* no support for TIDs 8-15 yet */
-       return -EINVAL;
-}
-
-static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr, size_t size)
-{
-       ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
-                                      GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
 /**
  * iwl_txq_update_write_ptr - Send new write index to hardware
  */
@@ -493,598 +415,6 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 }
 EXPORT_SYMBOL(iwl_tx_queue_reset);
 
-/**
- * iwl_hw_txq_ctx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       /* Tx queues */
-       if (priv->txq) {
-               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
-                               iwl_cmd_queue_free(priv);
-                       else
-                               iwl_tx_queue_free(priv, txq_id);
-       }
-       iwl_free_dma_ptr(priv, &priv->kw);
-
-       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
-
-       /* free tx queue structure */
-       iwl_free_txq_mem(priv);
-}
-EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
-
-/**
- * iwl_txq_ctx_alloc - allocate TX queue context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-int iwl_txq_ctx_alloc(struct iwl_priv *priv)
-{
-       int ret;
-       int txq_id, slots_num;
-       unsigned long flags;
-
-       /* Free all tx/cmd queues and keep-warm buffer */
-       iwl_hw_txq_ctx_free(priv);
-
-       ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
-                               priv->hw_params.scd_bc_tbls_size);
-       if (ret) {
-               IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
-               goto error_bc_tbls;
-       }
-       /* Alloc keep-warm buffer */
-       ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
-       if (ret) {
-               IWL_ERR(priv, "Keep Warm allocation failed\n");
-               goto error_kw;
-       }
-
-       /* allocate tx queue structure */
-       ret = iwl_alloc_txq_mem(priv);
-       if (ret)
-               goto error;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4) */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
-                                      txq_id);
-               if (ret) {
-                       IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return ret;
-
- error:
-       iwl_hw_txq_ctx_free(priv);
-       iwl_free_dma_ptr(priv, &priv->kw);
- error_kw:
-       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
- error_bc_tbls:
-       return ret;
-}
-
-void iwl_txq_ctx_reset(struct iwl_priv *priv)
-{
-       int txq_id, slots_num;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4) */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
-                           TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
-       }
-}
-
-/**
- * iwl_txq_ctx_stop - Stop all Tx DMA channels
- */
-void iwl_txq_ctx_stop(struct iwl_priv *priv)
-{
-       int ch;
-       unsigned long flags;
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
-               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_txq_ctx_stop);
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
-                                 struct iwl_tx_cmd *tx_cmd,
-                                 struct ieee80211_tx_info *info,
-                                 struct ieee80211_hdr *hdr,
-                                 u8 std_id)
-{
-       __le16 fc = hdr->frame_control;
-       __le32 tx_flags = tx_cmd->tx_flags;
-
-       tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-               tx_flags |= TX_CMD_FLG_ACK_MSK;
-               if (ieee80211_is_mgmt(fc))
-                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-               if (ieee80211_is_probe_resp(fc) &&
-                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
-                       tx_flags |= TX_CMD_FLG_TSF_MSK;
-       } else {
-               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       if (ieee80211_is_back_req(fc))
-               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
-
-
-       tx_cmd->sta_id = std_id;
-       if (ieee80211_has_morefrags(fc))
-               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-
-       if (ieee80211_is_data_qos(fc)) {
-               u8 *qc = ieee80211_get_qos_ctl(hdr);
-               tx_cmd->tid_tspec = qc[0] & 0xf;
-               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       } else {
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
-
-       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
-       if (ieee80211_is_mgmt(fc)) {
-               if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
-                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
-               else
-                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
-       } else {
-               tx_cmd->timeout.pm_frame_timeout = 0;
-       }
-
-       tx_cmd->driver_txop = 0;
-       tx_cmd->tx_flags = tx_flags;
-       tx_cmd->next_frame_len = 0;
-}
-
-#define RTS_DFAULT_RETRY_LIMIT         60
-
-static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
-                             struct iwl_tx_cmd *tx_cmd,
-                             struct ieee80211_tx_info *info,
-                             __le16 fc)
-{
-       u32 rate_flags;
-       int rate_idx;
-       u8 rts_retry_limit;
-       u8 data_retry_limit;
-       u8 rate_plcp;
-
-       /* Set retry limit on DATA packets and Probe Responses*/
-       if (ieee80211_is_probe_resp(fc))
-               data_retry_limit = 3;
-       else
-               data_retry_limit = IWL_DEFAULT_TX_RETRY;
-       tx_cmd->data_retry_limit = data_retry_limit;
-
-       /* Set retry limit on RTS packets */
-       rts_retry_limit = RTS_DFAULT_RETRY_LIMIT;
-       if (data_retry_limit < rts_retry_limit)
-               rts_retry_limit = data_retry_limit;
-       tx_cmd->rts_retry_limit = rts_retry_limit;
-
-       /* DATA packets will use the uCode station table for rate/antenna
-        * selection */
-       if (ieee80211_is_data(fc)) {
-               tx_cmd->initial_rate_index = 0;
-               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-               return;
-       }
-
-       /**
-        * If the current TX rate stored in mac80211 has the MCS bit set, it's
-        * not really a TX rate.  Thus, we use the lowest supported rate for
-        * this band.  Also use the lowest supported rate if the stored rate
-        * index is invalid.
-        */
-       rate_idx = info->control.rates[0].idx;
-       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
-                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
-               rate_idx = rate_lowest_index(&priv->bands[info->band],
-                               info->control.sta);
-       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate_idx += IWL_FIRST_OFDM_RATE;
-       /* Get PLCP rate for tx_cmd->rate_n_flags */
-       rate_plcp = iwl_rates[rate_idx].plcp;
-       /* Zero out flags for this packet */
-       rate_flags = 0;
-
-       /* Set CCK flag as needed */
-       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-       /* Set up RTS and CTS flags for certain packets */
-       switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-       case cpu_to_le16(IEEE80211_STYPE_AUTH):
-       case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-       case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-       case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-               if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
-                       tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-                       tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
-               }
-               break;
-       default:
-               break;
-       }
-
-       /* Set up antennas */
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
-       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
-
-       /* Set the rate in the TX cmd */
-       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
-                                     struct ieee80211_tx_info *info,
-                                     struct iwl_tx_cmd *tx_cmd,
-                                     struct sk_buff *skb_frag,
-                                     int sta_id)
-{
-       struct ieee80211_key_conf *keyconf = info->control.hw_key;
-
-       switch (keyconf->alg) {
-       case ALG_CCMP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
-               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
-               break;
-
-       case ALG_TKIP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_key(keyconf, skb_frag,
-                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
-               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
-               break;
-
-       case ALG_WEP:
-               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
-                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
-
-               if (keyconf->keylen == WEP_KEY_LEN_128)
-                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
-               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
-
-               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
-                            "with key %d\n", keyconf->keyidx);
-               break;
-
-       default:
-               IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
-               break;
-       }
-}
-
-/*
- * start REPLY_TX command process
- */
-int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_sta *sta = info->control.sta;
-       struct iwl_station_priv *sta_priv = NULL;
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       struct iwl_device_cmd *out_cmd;
-       struct iwl_cmd_meta *out_meta;
-       struct iwl_tx_cmd *tx_cmd;
-       int swq_id, txq_id;
-       dma_addr_t phys_addr;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       u16 len, len_org, firstlen, secondlen;
-       u16 seq_number = 0;
-       __le16 fc;
-       u8 hdr_len;
-       u8 sta_id;
-       u8 wait_write_ptr = 0;
-       u8 tid = 0;
-       u8 *qc = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
-               goto drop_unlock;
-       }
-
-       fc = hdr->frame_control;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (ieee80211_is_auth(fc))
-               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
-       else if (ieee80211_is_assoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
-       else if (ieee80211_is_reassoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
-#endif
-
-       hdr_len = ieee80211_hdrlen(fc);
-
-       /* Find (or create) index into station table for destination station */
-       if (info->flags & IEEE80211_TX_CTL_INJECTED)
-               sta_id = priv->hw_params.bcast_sta_id;
-       else
-               sta_id = iwl_get_sta_id(priv, hdr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-                              hdr->addr1);
-               goto drop_unlock;
-       }
-
-       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
-       if (sta)
-               sta_priv = (void *)sta->drv_priv;
-
-       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
-           sta_priv->asleep) {
-               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
-               /*
-                * This sends an asynchronous command to the device,
-                * but we can rely on it being processed before the
-                * next frame is processed -- and the next frame to
-                * this station is the one that will consume this
-                * counter.
-                * For now set the counter to just 1 since we do not
-                * support uAPSD yet.
-                */
-               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
-       }
-
-       txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
-       if (ieee80211_is_data_qos(fc)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               if (unlikely(tid >= MAX_TID_COUNT))
-                       goto drop_unlock;
-               seq_number = priv->stations[sta_id].tid[tid].seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = hdr->seq_ctrl &
-                               cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               seq_number += 0x10;
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
-                   priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
-                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-               }
-       }
-
-       txq = &priv->txq[txq_id];
-       swq_id = txq->swq_id;
-       q = &txq->q;
-
-       if (unlikely(iwl_queue_space(q) < q->high_mark))
-               goto drop_unlock;
-
-       if (ieee80211_is_data_qos(fc))
-               priv->stations[sta_id].tid[tid].tfds_in_queue++;
-
-       /* Set up driver data for this TFD */
-       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_cmd = txq->cmd[q->write_ptr];
-       out_meta = &txq->meta[q->write_ptr];
-       tx_cmd = &out_cmd->cmd.tx;
-       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
-       memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
-
-       /*
-        * Set up the Tx-command (not MAC!) header.
-        * Store the chosen Tx queue and TFD index within the sequence field;
-        * after Tx, uCode's Tx response will return this value so driver can
-        * locate the frame within the tx queue and do post-tx processing.
-        */
-       out_cmd->hdr.cmd = REPLY_TX;
-       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                               INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
-
-
-       /* Total # bytes to be transmitted */
-       len = (u16)skb->len;
-       tx_cmd->len = cpu_to_le16(len);
-
-       if (info->control.hw_key)
-               iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
-
-       /* TODO need this for burst mode later on */
-       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
-       iwl_dbg_log_tx_data_frame(priv, len, hdr);
-
-       iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc);
-
-       iwl_update_stats(priv, true, fc, len);
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-
-       len_org = len;
-       firstlen = len = (len + 3) & ~3;
-
-       if (len_org != len)
-               len_org = 1;
-       else
-               len_org = 0;
-
-       /* Tell NIC about any 2-byte padding after MAC header */
-       if (len_org)
-               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = pci_map_single(priv->pci_dev,
-                                   &out_cmd->hdr, len,
-                                   PCI_DMA_BIDIRECTIONAL);
-       pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       pci_unmap_len_set(out_meta, len, len);
-       /* Add buffer containing Tx command and MAC(!) header to TFD's
-        * first entry */
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  txcmd_phys, len, 1, 0);
-
-       if (!ieee80211_has_morefrags(hdr->frame_control)) {
-               txq->need_update = 1;
-               if (qc)
-                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       secondlen = len = skb->len - hdr_len;
-       if (len) {
-               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
-                                          len, PCI_DMA_TODEVICE);
-               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                          phys_addr, len,
-                                                          0, 0);
-       }
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-                               offsetof(struct iwl_tx_cmd, scratch);
-
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-       /* take back ownership of DMA buffer to enable update */
-       pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
-                                   len, PCI_DMA_BIDIRECTIONAL);
-       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-       IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
-                    le16_to_cpu(out_cmd->hdr.sequence));
-       IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-               priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
-                                                    le16_to_cpu(tx_cmd->len));
-
-       pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
-                                      len, PCI_DMA_BIDIRECTIONAL);
-
-       trace_iwlwifi_dev_tx(priv,
-                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &out_cmd->hdr, firstlen,
-                            skb->data + hdr_len, secondlen);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(priv, txq);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /*
-        * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
-        */
-
-       /* avoid atomic ops if it isn't an associated client */
-       if (sta_priv && sta_priv->client)
-               atomic_inc(&sta_priv->pending_frames);
-
-       if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
-               if (wait_write_ptr) {
-                       spin_lock_irqsave(&priv->lock, flags);
-                       txq->need_update = 1;
-                       iwl_txq_update_write_ptr(priv, txq);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-               } else {
-                       iwl_stop_queue(priv, txq->swq_id);
-               }
-       }
-
-       return 0;
-
-drop_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
-       return -1;
-}
-EXPORT_SYMBOL(iwl_tx_skb);
-
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
 /**
@@ -1218,61 +548,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        return idx;
 }
 
-static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_sta *sta;
-       struct iwl_station_priv *sta_priv;
-
-       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
-       if (sta) {
-               sta_priv = (void *)sta->drv_priv;
-               /* avoid atomic ops if this isn't a client */
-               if (sta_priv->client &&
-                   atomic_dec_return(&sta_priv->pending_frames) == 0)
-                       ieee80211_sta_block_awake(priv->hw, sta, false);
-       }
-
-       ieee80211_tx_status_irqsafe(priv->hw, skb);
-}
-
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
-{
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       struct iwl_tx_info *tx_info;
-       int nfreed = 0;
-       struct ieee80211_hdr *hdr;
-
-       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
-                         "is out of range [0-%d] %d %d.\n", txq_id,
-                         index, q->n_bd, q->write_ptr, q->read_ptr);
-               return 0;
-       }
-
-       for (index = iwl_queue_inc_wrap(index, q->n_bd);
-            q->read_ptr != index;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-               tx_info = &txq->txb[txq->q.read_ptr];
-               iwl_tx_status(priv, tx_info->skb[0]);
-
-               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
-               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
-                       nfreed++;
-               tx_info->skb[0] = NULL;
-
-               if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
-                       priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
-
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
-       }
-       return nfreed;
-}
-EXPORT_SYMBOL(iwl_tx_queue_reclaim);
-
-
 /**
  * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
  *
@@ -1366,7 +641,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(cmd->hdr.cmd));
                wake_up_interruptible(&priv->wait_command_queue);
        }
@@ -1374,353 +649,37 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 }
 EXPORT_SYMBOL(iwl_tx_cmd_complete);
 
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
- */
-static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
-                       return txq_id;
-       return -1;
-}
-
-int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
-{
-       int sta_id;
-       int tx_fifo;
-       int txq_id;
-       int ret;
-       unsigned long flags;
-       struct iwl_tid_data *tid_data;
-
-       tx_fifo = get_fifo_from_tid(tid);
-       if (unlikely(tx_fifo < 0))
-               return tx_fifo;
-
-       IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
-                       __func__, ra, tid);
-
-       sta_id = iwl_find_station(priv, ra);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Start AGG on invalid station\n");
-               return -ENXIO;
-       }
-       if (unlikely(tid >= MAX_TID_COUNT))
-               return -EINVAL;
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
-               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
-               return -ENXIO;
-       }
-
-       txq_id = iwl_txq_ctx_activate_free(priv);
-       if (txq_id == -1) {
-               IWL_ERR(priv, "No free aggregation queue available\n");
-               return -ENXIO;
-       }
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       tid_data = &priv->stations[sta_id].tid[tid];
-       *ssn = SEQ_TO_SN(tid_data->seq_number);
-       tid_data->agg.txq_id = txq_id;
-       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
-                                                 sta_id, tid, *ssn);
-       if (ret)
-               return ret;
-
-       if (tid_data->tfds_in_queue == 0) {
-               IWL_DEBUG_HT(priv, "HW queue is empty\n");
-               tid_data->agg.state = IWL_AGG_ON;
-               ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-       } else {
-               IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
-                            tid_data->tfds_in_queue);
-               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
-       }
-       return ret;
-}
-EXPORT_SYMBOL(iwl_tx_agg_start);
-
-int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
-{
-       int tx_fifo_id, txq_id, sta_id, ssn = -1;
-       struct iwl_tid_data *tid_data;
-       int write_ptr, read_ptr;
-       unsigned long flags;
-
-       if (!ra) {
-               IWL_ERR(priv, "ra = NULL\n");
-               return -EINVAL;
-       }
-
-       tx_fifo_id = get_fifo_from_tid(tid);
-       if (unlikely(tx_fifo_id < 0))
-               return tx_fifo_id;
-
-       sta_id = iwl_find_station(priv, ra);
-
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-               return -ENXIO;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state ==
-                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
-               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-               return 0;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
-               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
-
-       tid_data = &priv->stations[sta_id].tid[tid];
-       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
-       txq_id = tid_data->agg.txq_id;
-       write_ptr = priv->txq[txq_id].q.write_ptr;
-       read_ptr = priv->txq[txq_id].q.read_ptr;
-
-       /* The queue is not empty */
-       if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
-               priv->stations[sta_id].tid[tid].agg.state =
-                               IWL_EMPTYING_HW_QUEUE_DELBA;
-               return 0;
-       }
-
-       IWL_DEBUG_HT(priv, "HW queue is empty\n");
-       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       /*
-        * the only reason this call can fail is queue number out of range,
-        * which can happen if uCode is reloaded and all the station
-        * information are lost. if it is outside the range, there is no need
-        * to deactivate the uCode queue, just return "success" to allow
-        *  mac80211 to clean up it own data.
-        */
-       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
-                                                  tx_fifo_id);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_tx_agg_stop);
-
-int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
-{
-       struct iwl_queue *q = &priv->txq[txq_id].q;
-       u8 *addr = priv->stations[sta_id].sta.sta.addr;
-       struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
-
-       switch (priv->stations[sta_id].tid[tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if ((txq_id  == tid_data->agg.txq_id) &&
-                   (q->read_ptr == q->write_ptr)) {
-                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
-                       int tx_fifo = get_fifo_from_tid(tid);
-                       IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
-                       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
-                                                            ssn, tx_fifo);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
-               }
-               break;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iwl_txq_check_empty);
-
-/**
- * iwl_tx_status_reply_compressed_ba - Update tx status from block-ack
- *
- * Go through block-ack's bitmap of ACK'd frames, update driver's record of
- * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
- */
-static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
-                                struct iwl_ht_agg *agg,
-                                struct iwl_compressed_ba_resp *ba_resp)
-
-{
-       int i, sh, ack;
-       u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
-       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-       u64 bitmap;
-       int successes = 0;
-       struct ieee80211_tx_info *info;
-
-       if (unlikely(!agg->wait_for_ba))  {
-               IWL_ERR(priv, "Received BA when not expected\n");
-               return -EINVAL;
-       }
-
-       /* Mark that the expected block-ack response arrived */
-       agg->wait_for_ba = 0;
-       IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
-
-       /* Calculate shift to align block-ack bits with our Tx window bits */
-       sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
-       if (sh < 0) /* tbw something is wrong with indices */
-               sh += 0x100;
-
-       /* don't use 64-bit values for now */
-       bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
-
-       if (agg->frame_count > (64 - sh)) {
-               IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
-               return -1;
-       }
-
-       /* check for success or failure according to the
-        * transmitted bitmap and block-ack bitmap */
-       bitmap &= agg->bitmap;
-
-       /* For each frame attempted in aggregation,
-        * update driver's record of tx frame's status. */
-       for (i = 0; i < agg->frame_count ; i++) {
-               ack = bitmap & (1ULL << i);
-               successes += !!ack;
-               IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
-                       ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
-                       agg->start_idx + i);
-       }
-
-       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
-       memset(&info->status, 0, sizeof(info->status));
-       info->flags |= IEEE80211_TX_STAT_ACK;
-       info->flags |= IEEE80211_TX_STAT_AMPDU;
-       info->status.ampdu_ack_map = successes;
-       info->status.ampdu_ack_len = agg->frame_count;
-       iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
-
-       IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
-
-       return 0;
-}
-
-/**
- * iwl_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
- *
- * Handles block-acknowledge notification from device, which reports success
- * of frames sent via aggregation.
- */
-void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
-       struct iwl_tx_queue *txq = NULL;
-       struct iwl_ht_agg *agg;
-       int index;
-       int sta_id;
-       int tid;
-
-       /* "flow" corresponds to Tx queue */
-       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-
-       /* "ssn" is start of block-ack Tx window, corresponds to index
-        * (in Tx queue's circular buffer) of first TFD/frame in window */
-       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
-
-       if (scd_flow >= priv->hw_params.max_txq_num) {
-               IWL_ERR(priv,
-                       "BUG_ON scd_flow is bigger than number of queues\n");
-               return;
-       }
-
-       txq = &priv->txq[scd_flow];
-       sta_id = ba_resp->sta_id;
-       tid = ba_resp->tid;
-       agg = &priv->stations[sta_id].tid[tid].agg;
-
-       /* Find index just before block-ack window */
-       index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
-
-       /* TODO: Need to get this copy more safely - now good for debug */
-
-       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
-                          "sta_id = %d\n",
-                          agg->wait_for_ba,
-                          (u8 *) &ba_resp->sta_addr_lo32,
-                          ba_resp->sta_id);
-       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
-                          "%d, scd_ssn = %d\n",
-                          ba_resp->tid,
-                          ba_resp->seq_ctl,
-                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
-                          ba_resp->scd_flow,
-                          ba_resp->scd_ssn);
-       IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx \n",
-                          agg->start_idx,
-                          (unsigned long long)agg->bitmap);
-
-       /* Update driver's record of ACK vs. not for each frame in window */
-       iwl_tx_status_reply_compressed_ba(priv, agg, ba_resp);
-
-       /* Release all TFDs before the SSN, i.e. all TFDs in front of
-        * block-ack window (we assume that they've been successfully
-        * transmitted ... if not, it's too late anyway). */
-       if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
-               /* calculate mac80211 ampdu sw queue to wake */
-               int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-               if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
-                   priv->mac80211_registered &&
-                   (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
-                       iwl_wake_queue(priv, txq->swq_id);
-
-               iwl_txq_check_empty(priv, sta_id, tid, scd_flow);
-       }
-}
-EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
-
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
 
 const char *iwl_get_tx_fail_reason(u32 status)
 {
        switch (status & TX_STATUS_MSK) {
        case TX_STATUS_SUCCESS:
                return "SUCCESS";
-               TX_STATUS_ENTRY(SHORT_LIMIT);
-               TX_STATUS_ENTRY(LONG_LIMIT);
-               TX_STATUS_ENTRY(FIFO_UNDERRUN);
-               TX_STATUS_ENTRY(MGMNT_ABORT);
-               TX_STATUS_ENTRY(NEXT_FRAG);
-               TX_STATUS_ENTRY(LIFE_EXPIRE);
-               TX_STATUS_ENTRY(DEST_PS);
-               TX_STATUS_ENTRY(ABORTED);
-               TX_STATUS_ENTRY(BT_RETRY);
-               TX_STATUS_ENTRY(STA_INVALID);
-               TX_STATUS_ENTRY(FRAG_DROPPED);
-               TX_STATUS_ENTRY(TID_DISABLE);
-               TX_STATUS_ENTRY(FRAME_FLUSHED);
-               TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
-               TX_STATUS_ENTRY(TX_LOCKED);
-               TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+               TX_STATUS_POSTPONE(DELAY);
+               TX_STATUS_POSTPONE(FEW_BYTES);
+               TX_STATUS_POSTPONE(BT_PRIO);
+               TX_STATUS_POSTPONE(QUIET_PERIOD);
+               TX_STATUS_POSTPONE(CALC_TTAK);
+               TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+               TX_STATUS_FAIL(SHORT_LIMIT);
+               TX_STATUS_FAIL(LONG_LIMIT);
+               TX_STATUS_FAIL(FIFO_UNDERRUN);
+               TX_STATUS_FAIL(DRAIN_FLOW);
+               TX_STATUS_FAIL(RFKILL_FLUSH);
+               TX_STATUS_FAIL(LIFE_EXPIRE);
+               TX_STATUS_FAIL(DEST_PS);
+               TX_STATUS_FAIL(HOST_ABORTED);
+               TX_STATUS_FAIL(BT_RETRY);
+               TX_STATUS_FAIL(STA_INVALID);
+               TX_STATUS_FAIL(FRAG_DROPPED);
+               TX_STATUS_FAIL(TID_DISABLE);
+               TX_STATUS_FAIL(FIFO_FLUSHED);
+               TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
+               TX_STATUS_FAIL(FW_DROP);
+               TX_STATUS_FAIL(STA_COLOR_MISMATCH_DROP);
        }
 
        return "UNKNOWN";
index e0c05fe..9f36202 100644 (file)
@@ -598,9 +598,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                txq->need_update = 0;
        }
 
-       IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
+       IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
                     le16_to_cpu(out_cmd->hdr.sequence));
-       IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
+       IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
        iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd));
        iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr,
                           ieee80211_hdrlen(fc));
@@ -1604,9 +1604,6 @@ static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
        return pos;
 }
 
-/* For sanity check only.  Actual size is determined by uCode, typ. 512 */
-#define IWL3945_MAX_EVENT_LOG_SIZE (512)
-
 #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
 
 int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
@@ -1633,16 +1630,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) {
+       if (capacity > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, IWL3945_MAX_EVENT_LOG_SIZE);
-               capacity = IWL3945_MAX_EVENT_LOG_SIZE;
+                       capacity, priv->cfg->max_event_log_size);
+               capacity = priv->cfg->max_event_log_size;
        }
 
-       if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) {
+       if (next_entry > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, IWL3945_MAX_EVENT_LOG_SIZE);
-               next_entry = IWL3945_MAX_EVENT_LOG_SIZE;
+                       next_entry, priv->cfg->max_event_log_size);
+               next_entry = priv->cfg->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -1938,7 +1935,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                added++;
        }
 
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d \n", added);
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
        return added;
 }
 
@@ -3141,8 +3138,6 @@ void iwl3945_post_associate(struct iwl_priv *priv)
                break;
        }
 
-       iwl_activate_qos(priv, 0);
-
        /* we have just associated, don't start scan too early */
        priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 }
@@ -3404,7 +3399,7 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
        }
 
        /* Initialize rate scaling */
-       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n",
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
                       sta->addr);
        iwl3945_rs_rate_init(priv, sta, sta_id);
 
@@ -3890,11 +3885,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        priv->iw_mode = NL80211_IFTYPE_STATION;
        priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 
-       iwl_reset_qos(priv);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
-
        priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
 
        if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
index a48ccaf..6f5b843 100644 (file)
@@ -75,7 +75,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
                return -ENOMEM;
 
        pos += snprintf(buf+pos, len-pos,
-               "# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");
+               "# | ch  | rssi |       bssid       |   cap    | Qual | SSID\n");
 
        mutex_lock(&priv->lock);
        list_for_each_entry (iter_bss, &priv->network_list, list) {
index 7d1a3c6..cd464a2 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/host.h>
 
 #include "host.h"
 #include "decl.h"
@@ -943,6 +945,7 @@ static int if_sdio_probe(struct sdio_func *func,
        int ret, i;
        unsigned int model;
        struct if_sdio_packet *packet;
+       struct mmc_host *host = func->card->host;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
@@ -1023,6 +1026,25 @@ static int if_sdio_probe(struct sdio_func *func,
        if (ret)
                goto disable;
 
+       /* For 1-bit transfers to the 8686 model, we need to enable the
+        * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+        * bit to allow access to non-vendor registers. */
+       if ((card->model == IF_SDIO_MODEL_8686) &&
+           (host->caps & MMC_CAP_SDIO_IRQ) &&
+           (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+               u8 reg;
+
+               func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+               reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto release_int;
+
+               reg |= SDIO_BUS_ECSI;
+               sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto release_int;
+       }
+
        card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
        if (ret)
                goto release_int;
index 7cd5f56..dfff02f 100644 (file)
@@ -291,7 +291,8 @@ struct mac80211_hwsim_data {
        struct ieee80211_channel *channel;
        unsigned long beacon_int; /* in jiffies unit */
        unsigned int rx_filter;
-       bool started, idle;
+       bool started, idle, scanning;
+       struct mutex mutex;
        struct timer_list beacon_timer;
        enum ps_mode {
                PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
@@ -957,9 +958,9 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
        hsd->hw = hw;
        INIT_DELAYED_WORK(&hsd->w, hw_scan_done);
 
-       printk(KERN_DEBUG "hwsim scan request\n");
+       printk(KERN_DEBUG "hwsim hw_scan request\n");
        for (i = 0; i < req->n_channels; i++)
-               printk(KERN_DEBUG "hwsim scan freq %d\n",
+               printk(KERN_DEBUG "hwsim hw_scan freq %d\n",
                        req->channels[i]->center_freq);
 
        ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ);
@@ -967,6 +968,36 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
        return 0;
 }
 
+static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       mutex_lock(&hwsim->mutex);
+
+       if (hwsim->scanning) {
+               printk(KERN_DEBUG "two hwsim sw_scans detected!\n");
+               goto out;
+       }
+
+       printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n");
+       hwsim->scanning = true;
+
+out:
+       mutex_unlock(&hwsim->mutex);
+}
+
+static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       mutex_lock(&hwsim->mutex);
+
+       printk(KERN_DEBUG "hwsim sw_scan_complete\n");
+       hwsim->scanning = true;
+
+       mutex_unlock(&hwsim->mutex);
+}
+
 static struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -984,6 +1015,8 @@ static struct ieee80211_ops mac80211_hwsim_ops =
        .conf_tx = mac80211_hwsim_conf_tx,
        CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
        .ampdu_action = mac80211_hwsim_ampdu_action,
+       .sw_scan_start = mac80211_hwsim_sw_scan,
+       .sw_scan_complete = mac80211_hwsim_sw_scan_complete,
        .flush = mac80211_hwsim_flush,
 };
 
@@ -1179,8 +1212,11 @@ static int __init init_mac80211_hwsim(void)
        if (radios < 1 || radios > 100)
                return -EINVAL;
 
-       if (fake_hw_scan)
+       if (fake_hw_scan) {
                mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
+               mac80211_hwsim_ops.sw_scan_start = NULL;
+               mac80211_hwsim_ops.sw_scan_complete = NULL;
+       }
 
        spin_lock_init(&hwsim_radio_lock);
        INIT_LIST_HEAD(&hwsim_radios);
@@ -1285,6 +1321,7 @@ static int __init init_mac80211_hwsim(void)
                }
                /* By default all radios are belonging to the first group */
                data->group = 1;
+               mutex_init(&data->mutex);
 
                /* Work to be done prior to ieee80211_register_hw() */
                switch (regtest) {
index 269fda3..86f3e9a 100644 (file)
@@ -132,7 +132,7 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 
 static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
        int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       struct sk_buff **rx_buf)
+       struct sk_buff **rx_buf, u32 index)
 {
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
@@ -140,7 +140,7 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
 
        idx = le32_to_cpu(ring_control->host_idx[ring_index]);
        limit = idx;
-       limit -= le32_to_cpu(ring_control->device_idx[ring_index]);
+       limit -= le32_to_cpu(index);
        limit = ring_limit - limit;
 
        i = idx % ring_limit;
@@ -232,7 +232,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
                i %= ring_limit;
        }
 
-       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
+       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf, *index);
 }
 
 static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
@@ -277,14 +277,6 @@ static void p54p_tasklet(unsigned long dev_id)
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
 
-       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
-                          ARRAY_SIZE(ring_control->tx_mgmt),
-                          priv->tx_buf_mgmt);
-
-       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
-                          ARRAY_SIZE(ring_control->tx_data),
-                          priv->tx_buf_data);
-
        p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
                ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
 
@@ -293,6 +285,14 @@ static void p54p_tasklet(unsigned long dev_id)
 
        wmb();
        P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+
+       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
+                          ARRAY_SIZE(ring_control->tx_mgmt),
+                          priv->tx_buf_mgmt);
+
+       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
+                          ARRAY_SIZE(ring_control->tx_data),
+                          priv->tx_buf_data);
 }
 
 static irqreturn_t p54p_interrupt(int irq, void *dev_id)
@@ -445,10 +445,10 @@ static int p54p_open(struct ieee80211_hw *dev)
        priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
 
        p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
-               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
+               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data, 0);
 
        p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
-               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
+               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt, 0);
 
        P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
        P54P_READ(ring_control_base);
index 6605799..2ceff54 100644 (file)
@@ -38,7 +38,7 @@ static void p54_dump_tx_queue(struct p54_common *priv)
        u32 largest_hole = 0, free;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+       printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) ---\n",
               wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
 
        prev_addr = priv->rx_start;
index 689d59a..10d91af 100644 (file)
@@ -228,14 +228,14 @@ islpci_interrupt(int irq, void *config)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
                DEBUG(SHOW_FUNCTION_CALLS,
-                     "IRQ: Identification register 0x%p 0x%x \n", device, reg);
+                     "IRQ: Identification register 0x%p 0x%x\n", device, reg);
 #endif
 
                /* check for each bit in the register separately */
                if (reg & ISL38XX_INT_IDENT_UPDATE) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
                        /* Queue has been updated */
-                       DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Update flag\n");
 
                        DEBUG(SHOW_QUEUE_INDEXES,
                              "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
@@ -301,7 +301,7 @@ islpci_interrupt(int irq, void *config)
                                                ISL38XX_CB_RX_DATA_LQ) != 0) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
                                DEBUG(SHOW_TRACING,
-                                     "Received frame in Data Low Queue \n");
+                                     "Received frame in Data Low Queue\n");
 #endif
                                islpci_eth_receive(priv);
                        }
@@ -326,7 +326,7 @@ islpci_interrupt(int irq, void *config)
                        /* Device has been initialized */
 #if VERBOSE > SHOW_ERROR_MESSAGES
                        DEBUG(SHOW_TRACING,
-                             "IRQ: Init flag, device initialized \n");
+                             "IRQ: Init flag, device initialized\n");
 #endif
                        wake_up(&priv->reset_done);
                }
@@ -334,7 +334,7 @@ islpci_interrupt(int irq, void *config)
                if (reg & ISL38XX_INT_IDENT_SLEEP) {
                        /* Device intends to move to powersave state */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Sleep flag\n");
 #endif
                        isl38xx_handle_sleep_request(priv->control_block,
                                                     &powerstate,
@@ -344,7 +344,7 @@ islpci_interrupt(int irq, void *config)
                if (reg & ISL38XX_INT_IDENT_WAKEUP) {
                        /* Device has been woken up to active state */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Wakeup flag\n");
 #endif
 
                        isl38xx_handle_wakeup(priv->control_block,
@@ -635,7 +635,7 @@ islpci_alloc_memory(islpci_private *priv)
              ioremap(pci_resource_start(priv->pdev, 0),
                      ISL38XX_PCI_MEM_SIZE))) {
                /* error in remapping the PCI device memory address range */
-               printk(KERN_ERR "PCI memory remapping failed \n");
+               printk(KERN_ERR "PCI memory remapping failed\n");
                return -1;
        }
 
@@ -902,7 +902,7 @@ islpci_setup(struct pci_dev *pdev)
 
        if (register_netdev(ndev)) {
                DEBUG(SHOW_ERROR_MESSAGES,
-                     "ERROR: register_netdev() failed \n");
+                     "ERROR: register_netdev() failed\n");
                goto do_islpci_free_memory;
        }
 
index ac99eaa..64585da 100644 (file)
@@ -90,7 +90,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
        u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit\n");
 #endif
 
        /* lock the driver code */
@@ -141,7 +141,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
                        }
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
+                       DEBUG(SHOW_TRACING, "memmove %p %p %i\n", skb->data,
                              src, skb->len);
 #endif
                } else {
@@ -320,7 +320,7 @@ islpci_eth_receive(islpci_private *priv)
        int discard = 0;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive\n");
 #endif
 
        /* the device has written an Ethernet frame in the data area
@@ -432,7 +432,7 @@ islpci_eth_receive(islpci_private *priv)
                skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2);
                if (unlikely(skb == NULL)) {
                        /* error allocating an sk_buff structure elements */
-                       DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
+                       DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb\n");
                        break;
                }
                skb_reserve(skb, (4 - (long) skb->data) & 0x03);
index adb2897..a5224f6 100644 (file)
@@ -114,7 +114,7 @@ islpci_mgmt_rx_fill(struct net_device *ndev)
        u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill\n");
 #endif
 
        while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
@@ -212,7 +212,7 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
        {
                pimfor_header_t *h = buf.mem;
                DEBUG(SHOW_PIMFOR_FRAMES,
-                     "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n",
+                     "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x\n",
                      h->operation, oid, h->device_id, h->flags, length);
 
                /* display the buffer contents for debugging */
@@ -280,7 +280,7 @@ islpci_mgt_receive(struct net_device *ndev)
        u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive\n");
 #endif
 
        /* Only once per interrupt, determine fragment range to
@@ -339,7 +339,7 @@ islpci_mgt_receive(struct net_device *ndev)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
                DEBUG(SHOW_PIMFOR_FRAMES,
-                     "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
+                     "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x\n",
                      header->operation, header->oid, header->device_id,
                      header->flags, header->length);
 
index d66933d..9b796ca 100644 (file)
@@ -820,7 +820,7 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
                        k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
                        for (i = 0; i < list->nr; i++)
                                k += snprintf(str + k, PRIV_STR_SIZE - k,
-                                             "bss[%u] : \nage=%u\nchannel=%u\n"
+                                             "bss[%u] :\nage=%u\nchannel=%u\n"
                                              "capinfo=0x%X\nrates=0x%X\n"
                                              "basic_rates=0x%X\n",
                                              i, list->bsslist[i].age,
index 2940d7d..d9c45bf 100644 (file)
@@ -555,7 +555,7 @@ static int ray_init(struct net_device *dev)
        local->fw_ver = local->startup_res.firmware_version[0];
        local->fw_bld = local->startup_res.firmware_version[1];
        local->fw_var = local->startup_res.firmware_version[2];
-       dev_dbg(&link->dev, "ray_init firmware version %d.%d \n", local->fw_ver,
+       dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver,
              local->fw_bld);
 
        local->tib_length = 0x20;
@@ -2233,7 +2233,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
                            (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
                             FCS_LEN)) {
                                pr_debug(
-                                     "ray_cs invalid packet length %d received \n",
+                                     "ray_cs invalid packet length %d received\n",
                                      rx_len);
                                return;
                        }
@@ -2244,7 +2244,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
                            (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
                             FCS_LEN)) {
                                pr_debug(
-                                     "ray_cs invalid packet length %d received \n",
+                                     "ray_cs invalid packet length %d received\n",
                                      rx_len);
                                return;
                        }
@@ -2752,11 +2752,11 @@ static int ray_cs_proc_show(struct seq_file *m, void *v)
                        seq_printf(m, "Hop dwell            = %d Kus\n",
                                   pfh->dwell_time[0] +
                                   256 * pfh->dwell_time[1]);
-                       seq_printf(m, "Hop set              = %d \n",
+                       seq_printf(m, "Hop set              = %d\n",
                                   pfh->hop_set);
-                       seq_printf(m, "Hop pattern          = %d \n",
+                       seq_printf(m, "Hop pattern          = %d\n",
                                   pfh->hop_pattern);
-                       seq_printf(m, "Hop index            = %d \n",
+                       seq_printf(m, "Hop index            = %d\n",
                                   pfh->hop_index);
                        p += p[1] + 2;
                } else {
index 5f5204b..cdbf591 100644 (file)
@@ -526,6 +526,10 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
                rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+       } else {
+               rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+               rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
+               rt2x00pci_register_write(rt2x00dev, CSR20, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
index 2a73f59..89e986f 100644 (file)
@@ -574,6 +574,10 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
                rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+       } else {
+               rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+               rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
+               rt2x00pci_register_write(rt2x00dev, CSR20, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
index 8ebb705..7185cb0 100644 (file)
@@ -649,6 +649,10 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field16(&reg, MAC_CSR18_AUTO_WAKE, 1);
                rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
+       } else {
+               rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
+               rt2x00_set_field16(&reg, MAC_CSR18_AUTO_WAKE, 0);
+               rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -1644,11 +1648,6 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        unsigned int i;
 
        /*
-        * Disable powersaving as default.
-        */
-       rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-       /*
         * Initialize all hw fields.
         */
        rt2x00dev->hw->flags =
index 74c0433..ec89372 100644 (file)
 #define RF3021                         0x0007
 #define RF3022                         0x0008
 #define RF3052                         0x0009
+#define RF3320                         0x000b
 
 /*
- * Chipset version.
+ * Chipset revisions.
  */
-#define RT2860C_VERSION                        0x0100
-#define RT2860D_VERSION                        0x0101
-#define RT2880E_VERSION                        0x0200
-#define RT2883_VERSION                 0x0300
-#define RT3070_VERSION                 0x0200
+#define REV_RT2860C                    0x0100
+#define REV_RT2860D                    0x0101
+#define REV_RT2870D                    0x0101
+#define REV_RT2872E                    0x0200
+#define REV_RT3070E                    0x0200
+#define REV_RT3070F                    0x0201
+#define REV_RT3071E                    0x0211
+#define REV_RT3090E                    0x0211
+#define REV_RT3390E                    0x0211
 
 /*
  * Signal information.
 #define NUM_TX_QUEUES                  4
 
 /*
- * USB registers.
+ * Registers.
  */
 
 /*
+ * OPT_14: Unknown register used by rt3xxx devices.
+ */
+#define OPT_14_CSR                     0x0114
+#define OPT_14_CSR_BIT0                        FIELD32(0x00000001)
+
+/*
  * INT_SOURCE_CSR: Interrupt source register.
  * Write one to clear corresponding bit.
  * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c
 #define EFUSE_DATA3                    0x059c
 
 /*
+ * LDO_CFG0
+ */
+#define LDO_CFG0                       0x05d4
+#define LDO_CFG0_DELAY3                        FIELD32(0x000000ff)
+#define LDO_CFG0_DELAY2                        FIELD32(0x0000ff00)
+#define LDO_CFG0_DELAY1                        FIELD32(0x00ff0000)
+#define LDO_CFG0_BGSEL                 FIELD32(0x03000000)
+#define LDO_CFG0_LDO_CORE_VLEVEL       FIELD32(0x1c000000)
+#define LD0_CFG0_LDO25_LEVEL           FIELD32(0x60000000)
+#define LDO_CFG0_LDO25_LARGEA          FIELD32(0x80000000)
+
+/*
+ * GPIO_SWITCH
+ */
+#define GPIO_SWITCH                    0x05dc
+#define GPIO_SWITCH_0                  FIELD32(0x00000001)
+#define GPIO_SWITCH_1                  FIELD32(0x00000002)
+#define GPIO_SWITCH_2                  FIELD32(0x00000004)
+#define GPIO_SWITCH_3                  FIELD32(0x00000008)
+#define GPIO_SWITCH_4                  FIELD32(0x00000010)
+#define GPIO_SWITCH_5                  FIELD32(0x00000020)
+#define GPIO_SWITCH_6                  FIELD32(0x00000040)
+#define GPIO_SWITCH_7                  FIELD32(0x00000080)
+
+/*
  * MAC Control/Status Registers(CSR).
  * Some values are set in TU, whereas 1 TU == 1024 us.
  */
@@ -1492,14 +1528,32 @@ struct mac_iveiv_entry {
 #define BBP4_BANDWIDTH                 FIELD8(0x18)
 
 /*
+ * BBP 138: Unknown
+ */
+#define BBP138_RX_ADC1                 FIELD8(0x02)
+#define BBP138_RX_ADC2                 FIELD8(0x04)
+#define BBP138_TX_DAC1                 FIELD8(0x20)
+#define BBP138_TX_DAC2                 FIELD8(0x40)
+
+/*
  * RFCSR registers
  * The wordsize of the RFCSR is 8 bits.
  */
 
 /*
+ * RFCSR 1:
+ */
+#define RFCSR1_RF_BLOCK_EN             FIELD8(0x01)
+#define RFCSR1_RX0_PD                  FIELD8(0x04)
+#define RFCSR1_TX0_PD                  FIELD8(0x08)
+#define RFCSR1_RX1_PD                  FIELD8(0x10)
+#define RFCSR1_TX1_PD                  FIELD8(0x20)
+
+/*
  * RFCSR 6:
  */
-#define RFCSR6_R                       FIELD8(0x03)
+#define RFCSR6_R1                      FIELD8(0x03)
+#define RFCSR6_R2                      FIELD8(0x40)
 
 /*
  * RFCSR 7:
@@ -1512,6 +1566,28 @@ struct mac_iveiv_entry {
 #define RFCSR12_TX_POWER               FIELD8(0x1f)
 
 /*
+ * RFCSR 15:
+ */
+#define RFCSR15_TX_LO2_EN              FIELD8(0x08)
+
+/*
+ * RFCSR 17:
+ */
+#define RFCSR17_TXMIXER_GAIN           FIELD8(0x07)
+#define RFCSR17_TX_LO1_EN              FIELD8(0x08)
+#define RFCSR17_R                      FIELD8(0x20)
+
+/*
+ * RFCSR 20:
+ */
+#define RFCSR20_RX_LO1_EN              FIELD8(0x08)
+
+/*
+ * RFCSR 21:
+ */
+#define RFCSR21_RX_LO2_EN              FIELD8(0x08)
+
+/*
  * RFCSR 22:
  */
 #define RFCSR22_BASEBAND_LOOPBACK      FIELD8(0x01)
@@ -1522,6 +1598,14 @@ struct mac_iveiv_entry {
 #define RFCSR23_FREQ_OFFSET            FIELD8(0x7f)
 
 /*
+ * RFCSR 27:
+ */
+#define RFCSR27_R1                     FIELD8(0x03)
+#define RFCSR27_R2                     FIELD8(0x04)
+#define RFCSR27_R3                     FIELD8(0x30)
+#define RFCSR27_R4                     FIELD8(0x40)
+
+/*
  * RFCSR 30:
  */
 #define RFCSR30_RF_CALIBRATION         FIELD8(0x80)
@@ -1603,6 +1687,8 @@ struct mac_iveiv_entry {
 #define EEPROM_NIC_WPS_PBC             FIELD16(0x0080)
 #define EEPROM_NIC_BW40M_BG            FIELD16(0x0100)
 #define EEPROM_NIC_BW40M_A             FIELD16(0x0200)
+#define EEPROM_NIC_ANT_DIVERSITY       FIELD16(0x0800)
+#define EEPROM_NIC_DAC_TEST            FIELD16(0x8000)
 
 /*
  * EEPROM frequency
@@ -1659,6 +1745,12 @@ struct mac_iveiv_entry {
 #define EEPROM_RSSI_BG2_LNA_A1         FIELD16(0xff00)
 
 /*
+ * EEPROM TXMIXER GAIN BG offset (note overlaps with EEPROM RSSI BG2).
+ */
+#define EEPROM_TXMIXER_GAIN_BG         0x0024
+#define EEPROM_TXMIXER_GAIN_BG_VAL     FIELD16(0x0007)
+
+/*
  * EEPROM RSSI A offset
  */
 #define EEPROM_RSSI_A                  0x0025
index c015ce9..2648f31 100644 (file)
@@ -360,11 +360,6 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
        rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
        rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, *delay_on);
        rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, *delay_off);
-       rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
-       rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
        rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
 
        return 0;
@@ -610,10 +605,6 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
 {
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
-       rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20);
-       rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
-
        rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
                           !!erp->short_preamble);
@@ -632,15 +623,12 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
 
        rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
        rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
-       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
        rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
        rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
 
        rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
@@ -718,10 +706,10 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev,
        rt2x00dev->lna_gain = lna_gain;
 }
 
-static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
-                                      struct ieee80211_conf *conf,
-                                      struct rf_channel *rf,
-                                      struct channel_info *info)
+static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
 {
        rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
@@ -787,10 +775,10 @@ static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
        rt2800_rf_write(rt2x00dev, 4, rf->rf4);
 }
 
-static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
-                                      struct ieee80211_conf *conf,
-                                      struct rf_channel *rf,
-                                      struct channel_info *info)
+static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
 {
        u8 rfcsr;
 
@@ -798,7 +786,7 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3);
 
        rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
+       rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2);
        rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
@@ -827,15 +815,13 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp;
 
-       if ((rt2x00_rt(rt2x00dev, RT3070) ||
-            rt2x00_rt(rt2x00dev, RT3090)) &&
-           (rt2x00_rf(rt2x00dev, RF2020) ||
-            rt2x00_rf(rt2x00dev, RF3020) ||
-            rt2x00_rf(rt2x00dev, RF3021) ||
-            rt2x00_rf(rt2x00dev, RF3022)))
-               rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
+       if (rt2x00_rf(rt2x00dev, RF2020) ||
+           rt2x00_rf(rt2x00dev, RF3020) ||
+           rt2x00_rf(rt2x00dev, RF3021) ||
+           rt2x00_rf(rt2x00dev, RF3022))
+               rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
        else
-               rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
+               rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
 
        /*
         * Change BBP settings
@@ -899,8 +885,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
        rt2800_bbp_write(rt2x00dev, 3, bbp);
 
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
                if (conf_is_ht40(conf)) {
                        rt2800_bbp_write(rt2x00dev, 69, 0x1a);
                        rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@@ -988,10 +973,6 @@ static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
                           libconf->conf->short_frame_max_tx_count);
        rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT,
                           libconf->conf->long_frame_max_tx_count);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
        rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
 }
 
@@ -1015,13 +996,13 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
        } else {
-               rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
-
                rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
                rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+
+               rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
        }
 }
 
@@ -1062,9 +1043,10 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats);
 static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
 {
        if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-               if (rt2x00_is_usb(rt2x00dev) &&
-                   rt2x00_rt(rt2x00dev, RT3070) &&
-                   (rt2x00_rev(rt2x00dev) == RT3070_VERSION))
+               if (rt2x00_rt(rt2x00dev, RT3070) ||
+                   rt2x00_rt(rt2x00dev, RT3071) ||
+                   rt2x00_rt(rt2x00dev, RT3090) ||
+                   rt2x00_rt(rt2x00dev, RT3390))
                        return 0x1c + (2 * rt2x00dev->lna_gain);
                else
                        return 0x2e + rt2x00dev->lna_gain;
@@ -1095,8 +1077,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count)
 {
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION))
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C))
                return;
 
        /*
@@ -1114,8 +1095,17 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner);
 int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
+       u16 eeprom;
        unsigned int i;
 
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
        if (rt2x00_is_usb(rt2x00dev)) {
                /*
                 * Wait until BBP and RF are ready.
@@ -1135,8 +1125,25 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
                rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
                                      reg & ~0x00002000);
-       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
+       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
+               /*
+                * Reset DMA indexes
+                */
+               rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+               rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+               rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+               rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
                rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+       }
 
        rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
@@ -1181,12 +1188,42 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
+       rt2800_config_filter(rt2x00dev, FIF_ALLMULTI);
+
+       rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
+       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, 9);
+       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
+       rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-               rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
+                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+                       if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000002c);
+                       else
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000000f);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               }
+               rt2800_register_write(rt2x00dev, TX_SW_CFG2, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3070)) {
+               rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               }
        } else {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -1205,19 +1242,15 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
        rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9);
+       rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 32);
        rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10);
        rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
        rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-       if ((rt2x00_rt(rt2x00dev, RT2872) &&
-            (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) ||
-           rt2x00_rt(rt2x00dev, RT2880) ||
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT2872, REV_RT2872E) ||
            rt2x00_rt(rt2x00dev, RT2883) ||
-           rt2x00_rt(rt2x00dev, RT2890) ||
-           rt2x00_rt(rt2x00dev, RT3052) ||
-           (rt2x00_rt(rt2x00dev, RT3070) &&
-            (rt2x00_rev(rt2x00dev) < RT3070_VERSION)))
+           rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070E))
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
        else
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@@ -1225,38 +1258,61 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
        rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg);
 
+       rt2800_register_read(rt2x00dev, LED_CFG, &reg);
+       rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, 70);
+       rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, 30);
+       rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
+       rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
+       rt2800_register_write(rt2x00dev, LED_CFG, reg);
+
        rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f);
 
+       rt2800_register_read(rt2x00dev, TX_RTY_CFG, &reg);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT, 15);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT, 31);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
+       rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
+
        rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_AUTORESPONDER, 1);
+       rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY, 1);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MMODE, 0);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MREF, 0);
+       rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE, 1);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_DUAL_CTS_EN, 0);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0);
        rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
 
        rt2800_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 8);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 3);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
        rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 8);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 3);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
        rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
@@ -1269,11 +1325,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
-       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL,
+                          !rt2x00_is_usb(rt2x00dev));
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
@@ -1281,6 +1339,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
@@ -1293,6 +1352,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
@@ -1305,6 +1365,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
 
        if (rt2x00_is_usb(rt2x00dev)) {
@@ -1334,6 +1395,15 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg);
 
        rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
+
+       rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 32);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 32);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, 314);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
+       rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+
        rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
 
        /*
@@ -1483,38 +1553,67 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp_write(rt2x00dev, 65, 0x2c);
        rt2800_bbp_write(rt2x00dev, 66, 0x38);
-       rt2800_bbp_write(rt2x00dev, 69, 0x12);
+
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
+               rt2800_bbp_write(rt2x00dev, 69, 0x16);
+               rt2800_bbp_write(rt2x00dev, 73, 0x12);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 69, 0x12);
+               rt2800_bbp_write(rt2x00dev, 73, 0x10);
+       }
+
        rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-       rt2800_bbp_write(rt2x00dev, 73, 0x10);
-       rt2800_bbp_write(rt2x00dev, 81, 0x37);
+
+       if (rt2x00_rt(rt2x00dev, RT3070) ||
+           rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_bbp_write(rt2x00dev, 79, 0x13);
+               rt2800_bbp_write(rt2x00dev, 80, 0x05);
+               rt2800_bbp_write(rt2x00dev, 81, 0x33);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 81, 0x37);
+       }
+
        rt2800_bbp_write(rt2x00dev, 82, 0x62);
        rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-       rt2800_bbp_write(rt2x00dev, 84, 0x99);
+
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D) ||
+           rt2x00_rt_rev(rt2x00dev, RT2870, REV_RT2870D))
+               rt2800_bbp_write(rt2x00dev, 84, 0x19);
+       else
+               rt2800_bbp_write(rt2x00dev, 84, 0x99);
+
        rt2800_bbp_write(rt2x00dev, 86, 0x00);
        rt2800_bbp_write(rt2x00dev, 91, 0x04);
        rt2800_bbp_write(rt2x00dev, 92, 0x00);
-       rt2800_bbp_write(rt2x00dev, 103, 0x00);
+
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E))
+               rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+       else
+               rt2800_bbp_write(rt2x00dev, 103, 0x00);
+
        rt2800_bbp_write(rt2x00dev, 105, 0x05);
+       rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
-               rt2800_bbp_write(rt2x00dev, 69, 0x16);
-               rt2800_bbp_write(rt2x00dev, 73, 0x12);
-       }
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_bbp_read(rt2x00dev, 138, &value);
 
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) > RT2860D_VERSION))
-               rt2800_bbp_write(rt2x00dev, 84, 0x19);
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+                       value |= 0x20;
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+                       value &= ~0x02;
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
-               rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-               rt2800_bbp_write(rt2x00dev, 84, 0x99);
-               rt2800_bbp_write(rt2x00dev, 105, 0x05);
+               rt2800_bbp_write(rt2x00dev, 138, value);
        }
 
-       if (rt2x00_rt(rt2x00dev, RT3052)) {
+       if (rt2x00_rt(rt2x00dev, RT2872)) {
                rt2800_bbp_write(rt2x00dev, 31, 0x08);
                rt2800_bbp_write(rt2x00dev, 78, 0x0e);
                rt2800_bbp_write(rt2x00dev, 80, 0x08);
@@ -1598,19 +1697,15 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
        u8 rfcsr;
        u8 bbp;
+       u32 reg;
+       u16 eeprom;
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) != RT3070_VERSION))
+       if (!rt2x00_rt(rt2x00dev, RT3070) &&
+           !rt2x00_rt(rt2x00dev, RT3071) &&
+           !rt2x00_rt(rt2x00dev, RT3090) &&
+           !rt2x00_rt(rt2x00dev, RT3390))
                return 0;
 
-       if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
-               if (!rt2x00_rf(rt2x00dev, RF3020) &&
-                   !rt2x00_rf(rt2x00dev, RF3021) &&
-                   !rt2x00_rf(rt2x00dev, RF3022))
-                       return 0;
-       }
-
        /*
         * Init RF calibration.
         */
@@ -1621,13 +1716,15 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
        rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
 
-       if (rt2x00_is_usb(rt2x00dev)) {
+       if (rt2x00_rt(rt2x00dev, RT3070) ||
+           rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090)) {
                rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
                rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
                rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
                rt2800_rfcsr_write(rt2x00dev, 7, 0x70);
                rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x71);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
                rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
                rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
                rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
@@ -1640,48 +1737,88 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
                rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
                rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
                rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
-       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
-               rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
-               rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
-               rt2800_rfcsr_write(rt2x00dev, 3, 0x75);
+       } else if (rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
+               rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
+               rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
                rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
-               rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
-               rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 7, 0x50);
-               rt2800_rfcsr_write(rt2x00dev, 8, 0x39);
-               rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x60);
+               rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
+               rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
+               rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
+               rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
                rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
-               rt2800_rfcsr_write(rt2x00dev, 12, 0x75);
-               rt2800_rfcsr_write(rt2x00dev, 13, 0x75);
+               rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
                rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
-               rt2800_rfcsr_write(rt2x00dev, 15, 0x58);
-               rt2800_rfcsr_write(rt2x00dev, 16, 0xb3);
-               rt2800_rfcsr_write(rt2x00dev, 17, 0x92);
-               rt2800_rfcsr_write(rt2x00dev, 18, 0x2c);
-               rt2800_rfcsr_write(rt2x00dev, 19, 0x02);
-               rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
-               rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
+               rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
+               rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
+               rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
+               rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
                rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
-               rt2800_rfcsr_write(rt2x00dev, 23, 0x31);
+               rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
                rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
-               rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 26, 0x25);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
-               rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
-               rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+       }
+
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+                  rt2x00_rt(rt2x00dev, RT3090)) {
+               rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
+               rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
+
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
+                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+                       if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+                               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+                       else
+                               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
+               }
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+               rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
+               rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
        }
 
        /*
         * Set RX Filter calibration for 20MHz and 40MHz
         */
-       rt2x00dev->calibration[0] =
-           rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
-       rt2x00dev->calibration[1] =
-           rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+       if (rt2x00_rt(rt2x00dev, RT3070)) {
+               rt2x00dev->calibration[0] =
+                       rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
+               rt2x00dev->calibration[1] =
+                       rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+       } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+                  rt2x00_rt(rt2x00dev, RT3090) ||
+                  rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2x00dev->calibration[0] =
+                       rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x13);
+               rt2x00dev->calibration[1] =
+                       rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x15);
+       }
 
        /*
         * Set back to initial state
@@ -1699,6 +1836,81 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
        rt2800_bbp_write(rt2x00dev, 4, bbp);
 
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E))
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+
+       rt2800_register_read(rt2x00dev, OPT_14_CSR, &reg);
+       rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
+       rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
+
+       rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+                       rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
+       }
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
+       if (rt2x00_get_field16(eeprom, EEPROM_TXMIXER_GAIN_BG_VAL) >= 1)
+               rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN,
+                                 rt2x00_get_field16(eeprom,
+                                                  EEPROM_TXMIXER_GAIN_BG_VAL));
+       rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+
+       if (rt2x00_rt(rt2x00dev, RT3090)) {
+               rt2800_bbp_read(rt2x00dev, 138, &bbp);
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+                       rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+                       rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
+
+               rt2800_bbp_write(rt2x00dev, 138, bbp);
+       }
+
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+               rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 15, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
+       }
+
+       if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071)) {
+               rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E))
+                       rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
+               else
+                       rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R2, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R3, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R4, 0);
+               rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
@@ -1775,9 +1987,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        } else if (rt2x00_rt(rt2x00dev, RT2860) ||
                   rt2x00_rt(rt2x00dev, RT2870) ||
                   rt2x00_rt(rt2x00dev, RT2872) ||
-                  rt2x00_rt(rt2x00dev, RT2880) ||
-                  (rt2x00_rt(rt2x00dev, RT2883) &&
-                   (rt2x00_rev(rt2x00dev) < RT2883_VERSION))) {
+                  rt2x00_rt(rt2x00dev, RT2872)) {
                /*
                 * There is a max of 2 RX streams for RT28x0 series
                 */
@@ -1882,10 +2092,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00_rt(rt2x00dev, RT2860) &&
            !rt2x00_rt(rt2x00dev, RT2870) &&
            !rt2x00_rt(rt2x00dev, RT2872) &&
-           !rt2x00_rt(rt2x00dev, RT2880) &&
            !rt2x00_rt(rt2x00dev, RT2883) &&
-           !rt2x00_rt(rt2x00dev, RT2890) &&
-           !rt2x00_rt(rt2x00dev, RT3052) &&
            !rt2x00_rt(rt2x00dev, RT3070) &&
            !rt2x00_rt(rt2x00dev, RT3071) &&
            !rt2x00_rt(rt2x00dev, RT3090) &&
index b1f5643..2131f8f 100644 (file)
@@ -60,6 +60,12 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
        unsigned int i;
        u32 reg;
 
+       /*
+        * SOC devices don't support MCU requests.
+        */
+       if (rt2x00_is_soc(rt2x00dev))
+               return;
+
        for (i = 0; i < 200; i++) {
                rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
 
@@ -341,19 +347,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
        struct queue_entry_priv_pci *entry_priv;
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
-       rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
-       rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
        /*
         * Initialize registers.
         */
@@ -1009,6 +1002,14 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
        }
 }
 
+static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
+{
+       struct ieee80211_conf conf = { .flags = 0 };
+       struct rt2x00lib_conf libconf = { .conf = &conf };
+
+       rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+}
+
 static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -1033,6 +1034,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
                rt2800pci_txdone(rt2x00dev);
 
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
+               rt2800pci_wakeup(rt2x00dev);
+
        return IRQ_HANDLED;
 }
 
@@ -1212,6 +1216,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
+       { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) },
 #endif
        { 0, }
 };
index d27d7d5..6b809ab 100644 (file)
@@ -876,6 +876,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -905,8 +907,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AirTies */
        { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* ASUS */
+       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AzureWave */
        { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Conceptronic */
        { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Corega */
@@ -916,20 +923,46 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Draytek */
+       { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
        { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
        { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* I-O DATA */
        { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Logitec */
+       { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* MSI */
        { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Para */
+       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Pegatron */
        { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -944,9 +977,15 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sitecom */
        { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -966,6 +1005,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sitecom */
        { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
 #endif
@@ -985,18 +1025,14 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Amigo */
        { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Askey */
-       { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* ASUS */
        { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AzureWave */
        { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Belkin */
        { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Buffalo */
@@ -1015,14 +1051,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* EnGenius */
-       { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gemtek */
        { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
@@ -1030,9 +1060,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Hawking */
        { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* I-O DATA */
-       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* LevelOne */
        { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -1042,20 +1069,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Motorola */
        { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* MSI */
-       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ovislink */
        { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Para */
-       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Pegatron */
        { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -1064,19 +1079,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sweex */
index d9daa9c..4de505b 100644 (file)
@@ -177,16 +177,15 @@ struct rt2x00_chip {
 #define RT2573         0x2573
 #define RT2860         0x2860  /* 2.4GHz PCI/CB */
 #define RT2870         0x2870
-#define RT2872         0x2872
-#define RT2880         0x2880  /* WSOC */
+#define RT2872         0x2872  /* WSOC */
 #define RT2883         0x2883  /* WSOC */
-#define RT2890         0x2890  /* 2.4GHz PCIe */
-#define RT3052         0x3052  /* WSOC */
 #define RT3070         0x3070
 #define RT3071         0x3071
 #define RT3090         0x3090  /* 2.4GHz PCIe */
 #define RT3390         0x3390
 #define RT3572         0x3572
+#define RT3593         0x3593  /* PCIe */
+#define RT3883         0x3883  /* WSOC */
 
        u16 rf;
        u16 rev;
@@ -930,12 +929,12 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
             rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
 }
 
-static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
+static inline bool rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
 {
        return (rt2x00dev->chip.rt == rt);
 }
 
-static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
+static inline bool rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
 {
        return (rt2x00dev->chip.rf == rf);
 }
@@ -945,6 +944,24 @@ static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
        return rt2x00dev->chip.rev;
 }
 
+static inline bool rt2x00_rt_rev(struct rt2x00_dev *rt2x00dev,
+                                const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) == rev);
+}
+
+static inline bool rt2x00_rt_rev_lt(struct rt2x00_dev *rt2x00dev,
+                                   const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) < rev);
+}
+
+static inline bool rt2x00_rt_rev_gte(struct rt2x00_dev *rt2x00dev,
+                                    const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) >= rev);
+}
+
 static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
                                        enum rt2x00_chip_intf intf)
 {
index 432e75f..b988598 100644 (file)
@@ -2118,6 +2118,14 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
        }
 }
 
+static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
+{
+       struct ieee80211_conf conf = { .flags = 0 };
+       struct rt2x00lib_conf libconf = { .conf = &conf };
+
+       rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+}
+
 static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -2165,6 +2173,12 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
                rt2x00pci_register_write(rt2x00dev,
                                         M2H_CMD_DONE_CSR, 0xffffffff);
 
+       /*
+        * 4 - MCU Autowakeup interrupt.
+        */
+       if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
+               rt61pci_wakeup(rt2x00dev);
+
        return IRQ_HANDLED;
 }
 
index bb58d79..576ea9d 100644 (file)
@@ -861,15 +861,15 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
                rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
                                            USB_MODE_SLEEP, REGISTER_TIMEOUT);
        } else {
-               rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
-                                           USB_MODE_WAKEUP, REGISTER_TIMEOUT);
-
                rt2x00usb_register_read(rt2x00dev, MAC_CSR11, &reg);
                rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 0);
                rt2x00usb_register_write(rt2x00dev, MAC_CSR11, reg);
+
+               rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
+                                           USB_MODE_WAKEUP, REGISTER_TIMEOUT);
        }
 }
 
index 56b78e4..4d47970 100644 (file)
@@ -202,8 +202,8 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
                        goto out;
        }
 
-       /* No NVS from netlink, try to get it from the filesystem */
-       if (wl->nvs == NULL) {
+       if (wl->nvs == NULL && !wl->use_eeprom) {
+               /* No NVS from netlink, try to get it from the filesystem */
                ret = wl1251_fetch_nvs(wl);
                if (ret < 0)
                        goto out;
index 3bfb59b..e814742 100644 (file)
@@ -310,7 +310,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wl1251_spi_driver = {
        .driver = {
-               .name           = "wl1251",
+               .name           = DRIVER_NAME,
                .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
index 8f11506..75887e7 100644 (file)
@@ -55,6 +55,7 @@ enum {
        DEBUG_ACX       = BIT(13),
        DEBUG_SDIO      = BIT(14),
        DEBUG_FILTERS   = BIT(15),
+       DEBUG_ADHOC     = BIT(16),
        DEBUG_ALL       = ~0,
 };
 
@@ -147,14 +148,7 @@ struct wl1271_nvs_file {
  */
 #undef WL1271_80211A_ENABLED
 
-/*
- * FIXME: for the wl1271, a busy word count of 1 here will result in a more
- * optimal SPI interface. There is some SPI bug however, causing RXS time outs
- * with this mode occasionally on boot, so lets have three for now. A value of
- * three should make sure, that the chipset will always be ready, though this
- * will impact throughput and latencies slightly.
- */
-#define WL1271_BUSY_WORD_CNT 3
+#define WL1271_BUSY_WORD_CNT 1
 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
 
 #define WL1271_ELP_HW_STATE_ASLEEP 0
@@ -380,6 +374,7 @@ struct wl1271 {
 #define WL1271_FLAG_PSM_REQUESTED      (8)
 #define WL1271_FLAG_IRQ_PENDING        (9)
 #define WL1271_FLAG_IRQ_RUNNING       (10)
+#define WL1271_FLAG_IDLE              (11)
        unsigned long flags;
 
        struct wl1271_partition_set part;
@@ -396,6 +391,7 @@ struct wl1271 {
        u8 bssid[ETH_ALEN];
        u8 mac_addr[ETH_ALEN];
        u8 bss_type;
+       u8 set_bss_type;
        u8 ssid[IW_ESSID_MAX_SIZE + 1];
        u8 ssid_len;
        int channel;
@@ -452,11 +448,15 @@ struct wl1271 {
        /* currently configured rate set */
        u32 sta_rate_set;
        u32 basic_rate_set;
+       u32 basic_rate;
        u32 rate_set;
 
        /* The current band */
        enum ieee80211_band band;
 
+       /* Beaconing interval (needed for ad-hoc) */
+       u32 beacon_int;
+
        /* Default key (for WEP) */
        u32 default_key;
 
@@ -473,6 +473,9 @@ struct wl1271 {
        /* in dBm */
        int power_level;
 
+       int rssi_thold;
+       int last_rssi_event;
+
        struct wl1271_stats stats;
        struct wl1271_debugfs debugfs;
 
index adaa3f2..2ad086e 100644 (file)
@@ -505,12 +505,17 @@ out:
        return ret;
 }
 
-int wl1271_acx_conn_monit_params(struct wl1271 *wl)
+#define ACX_CONN_MONIT_DISABLE_VALUE  0xffffffff
+
+int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
 {
        struct acx_conn_monit_params *acx;
+       u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE;
+       u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx connection monitor parameters");
+       wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s",
+                    enable ? "enabled" : "disabled");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
        if (!acx) {
@@ -518,8 +523,13 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl)
                goto out;
        }
 
-       acx->synch_fail_thold = cpu_to_le32(wl->conf.conn.synch_fail_thold);
-       acx->bss_lose_timeout = cpu_to_le32(wl->conf.conn.bss_lose_timeout);
+       if (enable) {
+               threshold = wl->conf.conn.synch_fail_thold;
+               timeout = wl->conf.conn.bss_lose_timeout;
+       }
+
+       acx->synch_fail_thold = cpu_to_le32(threshold);
+       acx->bss_lose_timeout = cpu_to_le32(timeout);
 
        ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
                                   acx, sizeof(*acx));
@@ -793,7 +803,7 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
 
        /* configure one basic rate class */
        idx = ACX_TX_BASIC_RATE;
-       acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
+       acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate);
        acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
        acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
        acx->rate_class[idx].aflags = c->aflags;
@@ -1130,3 +1140,129 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
+{
+       struct wl1271_acx_keep_alive_mode *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->enabled = enable;
+
+       ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx keep alive mode failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
+{
+       struct wl1271_acx_keep_alive_config *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx keep alive config");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
+       acx->index = index;
+       acx->tpl_validation = tpl_valid;
+       acx->trigger = ACX_KEEP_ALIVE_NO_TX;
+
+       ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx keep alive config failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
+                               s16 thold, u8 hyst)
+{
+       struct wl1271_acx_rssi_snr_trigger *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx rssi snr trigger");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wl->last_rssi_event = -1;
+
+       acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
+       acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
+       acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
+       if (enable)
+               acx->enable = WL1271_ACX_TRIG_ENABLE;
+       else
+               acx->enable = WL1271_ACX_TRIG_DISABLE;
+
+       acx->index = WL1271_ACX_TRIG_IDX_RSSI;
+       acx->dir = WL1271_ACX_TRIG_DIR_BIDIR;
+       acx->threshold = cpu_to_le16(thold);
+       acx->hysteresis = hyst;
+
+       ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx rssi snr trigger setting failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
+{
+       struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
+       struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->rssi_beacon = c->avg_weight_rssi_beacon;
+       acx->rssi_data = c->avg_weight_rssi_data;
+       acx->snr_beacon = c->avg_weight_snr_beacon;
+       acx->snr_data = c->avg_weight_snr_data;
+
+       ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx rssi snr trigger weights failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 8e5870f..420e7e2 100644 (file)
@@ -915,6 +915,84 @@ struct wl1271_acx_pm_config {
        u8 padding[3];
 } __attribute__ ((packed));
 
+struct wl1271_acx_keep_alive_mode {
+       struct acx_header header;
+
+       u8 enabled;
+       u8 padding[3];
+} __attribute__ ((packed));
+
+enum {
+       ACX_KEEP_ALIVE_NO_TX = 0,
+       ACX_KEEP_ALIVE_PERIOD_ONLY
+};
+
+enum {
+       ACX_KEEP_ALIVE_TPL_INVALID = 0,
+       ACX_KEEP_ALIVE_TPL_VALID
+};
+
+struct wl1271_acx_keep_alive_config {
+       struct acx_header header;
+
+       __le32 period;
+       u8 index;
+       u8 tpl_validation;
+       u8 trigger;
+       u8 padding;
+} __attribute__ ((packed));
+
+enum {
+       WL1271_ACX_TRIG_TYPE_LEVEL = 0,
+       WL1271_ACX_TRIG_TYPE_EDGE,
+};
+
+enum {
+       WL1271_ACX_TRIG_DIR_LOW = 0,
+       WL1271_ACX_TRIG_DIR_HIGH,
+       WL1271_ACX_TRIG_DIR_BIDIR,
+};
+
+enum {
+       WL1271_ACX_TRIG_ENABLE = 1,
+       WL1271_ACX_TRIG_DISABLE,
+};
+
+enum {
+       WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0,
+       WL1271_ACX_TRIG_METRIC_RSSI_DATA,
+       WL1271_ACX_TRIG_METRIC_SNR_BEACON,
+       WL1271_ACX_TRIG_METRIC_SNR_DATA,
+};
+
+enum {
+       WL1271_ACX_TRIG_IDX_RSSI = 0,
+       WL1271_ACX_TRIG_COUNT = 8,
+};
+
+struct wl1271_acx_rssi_snr_trigger {
+       struct acx_header header;
+
+       __le16 threshold;
+       __le16 pacing; /* 0 - 60000 ms */
+       u8 metric;
+       u8 type;
+       u8 dir;
+       u8 hysteresis;
+       u8 index;
+       u8 enable;
+       u8 padding[2];
+};
+
+struct wl1271_acx_rssi_snr_avg_weights {
+       struct acx_header header;
+
+       u8 rssi_beacon;
+       u8 rssi_data;
+       u8 snr_beacon;
+       u8 snr_data;
+};
+
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
        ACX_MEM_CFG                 = 0x0003,
@@ -963,8 +1041,8 @@ enum {
        ACX_FRAG_CFG                = 0x004F,
        ACX_BET_ENABLE              = 0x0050,
        ACX_RSSI_SNR_TRIGGER        = 0x0051,
-       ACX_RSSI_SNR_WEIGHTS        = 0x0051,
-       ACX_KEEP_ALIVE_MODE         = 0x0052,
+       ACX_RSSI_SNR_WEIGHTS        = 0x0052,
+       ACX_KEEP_ALIVE_MODE         = 0x0053,
        ACX_SET_KEEP_ALIVE_CONFIG   = 0x0054,
        ACX_BA_SESSION_RESPONDER_POLICY = 0x0055,
        ACX_BA_SESSION_INITIATOR_POLICY = 0x0056,
@@ -1004,7 +1082,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
 int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
 int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
-int wl1271_acx_conn_monit_params(struct wl1271 *wl);
+int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
 int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_sg_cfg(struct wl1271 *wl);
 int wl1271_acx_cca_threshold(struct wl1271 *wl);
@@ -1031,5 +1109,10 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
                             u8 version);
 int wl1271_acx_pm_config(struct wl1271 *wl);
+int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
+int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
+int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
+                               s16 thold, u8 hyst);
+int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
index 1937859..8087dc1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of wl1271
  *
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
  *
  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
@@ -411,7 +411,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        /* unmask required mbox events  */
        wl->event_mask = BSS_LOSE_EVENT_ID |
                SCAN_COMPLETE_EVENT_ID |
-               PS_REPORT_EVENT_ID;
+               PS_REPORT_EVENT_ID |
+               JOIN_EVENT_COMPLETE_ID |
+               DISCONNECT_EVENT_COMPLETE_ID |
+               RSSI_SNR_TRIGGER_0_EVENT_ID;
 
        ret = wl1271_event_unmask(wl);
        if (ret < 0) {
@@ -452,11 +455,15 @@ int wl1271_boot(struct wl1271 *wl)
 
        if (REF_CLOCK != 0) {
                u16 val;
-               /* Set clock type */
+               /* Set clock type (open drain) */
                val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
                val &= FREF_CLK_TYPE_BITS;
-               val |= CLK_REQ_PRCM;
                wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+
+               /* Set clock pull mode (no pull) */
+               val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
+               val |= NO_PULL;
+               wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
        } else {
                u16 val;
                /* Set clock polarity */
index 412443e..95ecc52 100644 (file)
@@ -53,10 +53,13 @@ struct wl1271_static_data {
 #define OCP_REG_POLARITY     0x0064
 #define OCP_REG_CLK_TYPE     0x0448
 #define OCP_REG_CLK_POLARITY 0x0cb2
+#define OCP_REG_CLK_PULL     0x0cb4
 
-#define CMD_MBOX_ADDRESS 0x407B4
 
-#define POLARITY_LOW BIT(1)
+#define CMD_MBOX_ADDRESS     0x407B4
+
+#define POLARITY_LOW         BIT(1)
+#define NO_PULL              (BIT(14) | BIT(15))
 
 #define FREF_CLK_TYPE_BITS     0xfffffe7f
 #define CLK_REQ_PRCM           0x100
index 92254d0..6b5ba8e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of wl1271
  *
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
@@ -35,6 +35,9 @@
 #include "wl1271_acx.h"
 #include "wl12xx_80211.h"
 #include "wl1271_cmd.h"
+#include "wl1271_event.h"
+
+#define WL1271_CMD_POLL_COUNT       5
 
 /*
  * send command to firmware
@@ -52,6 +55,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
        u32 intr;
        int ret = 0;
        u16 status;
+       u16 poll_count = 0;
 
        cmd = buf;
        cmd->id = cpu_to_le16(id);
@@ -73,7 +77,11 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                        goto out;
                }
 
-               msleep(1);
+               udelay(10);
+               poll_count++;
+               if (poll_count == WL1271_CMD_POLL_COUNT)
+                       wl1271_info("cmd polling took over %d cycles",
+                                   poll_count);
 
                intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
        }
@@ -249,6 +257,35 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
        return ret;
 }
 
+/*
+ * Poll the mailbox event field until any of the bits in the mask is set or a
+ * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
+ */
+static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
+{
+       u32 events_vector, event;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
+
+       do {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+
+               /* read from both event fields */
+               wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
+                           sizeof(events_vector), false);
+               event = events_vector & mask;
+               wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
+                           sizeof(events_vector), false);
+               event |= events_vector & mask;
+       } while (!event);
+
+       return 0;
+}
+
 int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
 {
        static bool do_cal = true;
@@ -281,20 +318,12 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
        join->rx_config_options = cpu_to_le32(wl->rx_config);
        join->rx_filter_options = cpu_to_le32(wl->rx_filter);
        join->bss_type = bss_type;
+       join->basic_rate_set = wl->basic_rate_set;
 
-       if (wl->band == IEEE80211_BAND_2GHZ)
-               join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS   |
-                                                  CONF_HW_BIT_RATE_2MBPS   |
-                                                  CONF_HW_BIT_RATE_5_5MBPS |
-                                                  CONF_HW_BIT_RATE_11MBPS);
-       else {
+       if (wl->band == IEEE80211_BAND_5GHZ)
                join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
-               join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS  |
-                                                  CONF_HW_BIT_RATE_12MBPS |
-                                                  CONF_HW_BIT_RATE_24MBPS);
-       }
 
-       join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
+       join->beacon_interval = cpu_to_le16(wl->beacon_int);
        join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
 
        join->channel = wl->channel;
@@ -319,11 +348,9 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
                goto out_free;
        }
 
-       /*
-        * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
-        * simplify locking we just sleep instead, for now
-        */
-       msleep(10);
+       ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
+       if (ret < 0)
+               wl1271_error("cmd join event completion error");
 
 out_free:
        kfree(join);
@@ -455,7 +482,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
        if (ret < 0) {
                wl1271_error("tx %s cmd for channel %d failed",
                             enable ? "start" : "stop", cmd->channel);
-               return ret;
+               goto out;
        }
 
        wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
@@ -547,17 +574,21 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
        struct wl1271_cmd_trigger_scan_to *trigger = NULL;
        struct wl1271_cmd_scan *params = NULL;
        struct ieee80211_channel *channels;
+       u32 rate;
        int i, j, n_ch, ret;
        u16 scan_options = 0;
        u8 ieee_band;
 
-       if (band == WL1271_SCAN_BAND_2_4_GHZ)
+       if (band == WL1271_SCAN_BAND_2_4_GHZ) {
                ieee_band = IEEE80211_BAND_2GHZ;
-       else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
+               rate = wl->conf.tx.basic_rate;
+       } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
                ieee_band = IEEE80211_BAND_2GHZ;
-       else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
+               rate = wl->conf.tx.basic_rate;
+       } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
                ieee_band = IEEE80211_BAND_5GHZ;
-       else
+               rate = wl->conf.tx.basic_rate_5;
+       } else
                return -EINVAL;
 
        if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
@@ -584,8 +615,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
        params->params.scan_options = cpu_to_le16(scan_options);
 
        params->params.num_probe_requests = probe_requests;
-       /* Let the fw autodetect suitable tx_rate for probes */
-       params->params.tx_rate = 0;
+       params->params.tx_rate = rate;
        params->params.tid_trigger = 0;
        params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
 
@@ -666,11 +696,12 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
 
 out:
        kfree(params);
+       kfree(trigger);
        return ret;
 }
 
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len)
+                           void *buf, size_t buf_len, int index, u32 rates)
 {
        struct wl1271_cmd_template_set *cmd;
        int ret = 0;
@@ -688,9 +719,10 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
 
        cmd->len = cpu_to_le16(buf_len);
        cmd->template_type = template_id;
-       cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
+       cmd->enabled_rates = cpu_to_le32(rates);
        cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
        cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
+       cmd->index = index;
 
        if (buf)
                memcpy(cmd->template_data, buf, buf_len);
@@ -727,7 +759,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
                ptr = skb->data;
        }
 
-       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size);
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
+                                     WL1271_RATE_AUTOMATIC);
 
 out:
        dev_kfree_skb(skb);
@@ -738,6 +771,29 @@ out:
 
 }
 
+int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
+{
+       struct sk_buff *skb = NULL;
+       int ret = -ENOMEM;
+
+       skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
+       if (!skb)
+               goto out;
+
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
+                                     skb->data, skb->len,
+                                     CMD_TEMPL_KLV_IDX_NULL_DATA,
+                                     WL1271_RATE_AUTOMATIC);
+
+out:
+       dev_kfree_skb(skb);
+       if (ret)
+               wl1271_warning("cmd build klv null data failed %d", ret);
+
+       return ret;
+
+}
+
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
 {
        struct sk_buff *skb;
@@ -748,7 +804,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
                goto out;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
-                                     skb->len);
+                                     skb->len, 0, wl->basic_rate);
 
 out:
        dev_kfree_skb(skb);
@@ -773,10 +829,12 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
 
        if (band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             skb->data, skb->len);
+                                             skb->data, skb->len, 0,
+                                             wl->conf.tx.basic_rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             skb->data, skb->len);
+                                             skb->data, skb->len, 0,
+                                             wl->conf.tx.basic_rate_5);
 
 out:
        dev_kfree_skb(skb);
@@ -801,7 +859,8 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)
        template.qos_ctrl = cpu_to_le16(0);
 
        return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
-                                      sizeof(template));
+                                      sizeof(template), 0,
+                                      WL1271_RATE_AUTOMATIC);
 }
 
 int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
@@ -914,6 +973,10 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
                goto out_free;
        }
 
+       ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+       if (ret < 0)
+               wl1271_error("cmd disconnect event completion error");
+
 out_free:
        kfree(cmd);
 
index 6324bbf..00f78b7 100644 (file)
@@ -45,13 +45,14 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
                    const u8 *ie, size_t ie_len, u8 active_scan,
                    u8 high_prio, u8 band, u8 probe_requests);
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len);
+                           void *buf, size_t buf_len, int index, u32 rates);
 int wl1271_cmd_build_null_data(struct wl1271 *wl);
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
 int wl1271_cmd_build_probe_req(struct wl1271 *wl,
                               const u8 *ssid, size_t ssid_len,
                               const u8 *ie, size_t ie_len, u8 band);
 int wl1271_build_qos_null_data(struct wl1271 *wl);
+int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
 int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
 int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
                       u8 key_size, const u8 *key, const u8 *addr,
@@ -101,6 +102,11 @@ enum wl1271_commands {
 
 #define MAX_CMD_PARAMS 572
 
+enum {
+       CMD_TEMPL_KLV_IDX_NULL_DATA = 0,
+       CMD_TEMPL_KLV_IDX_MAX = 4
+};
+
 enum cmd_templ {
        CMD_TEMPL_NULL_DATA = 0,
        CMD_TEMPL_BEACON,
@@ -123,6 +129,7 @@ enum cmd_templ {
 /* unit ms */
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_MAX_SIZE  252
+#define WL1271_EVENT_TIMEOUT       100
 
 struct wl1271_cmd_header {
        __le16 id;
@@ -245,6 +252,8 @@ struct cmd_enabledisable_path {
        u8 padding[3];
 } __attribute__ ((packed));
 
+#define WL1271_RATE_AUTOMATIC  0
+
 struct wl1271_cmd_template_set {
        struct wl1271_cmd_header header;
 
@@ -511,6 +520,8 @@ enum wl1271_disconnect_type {
 };
 
 struct wl1271_cmd_disconnect {
+       struct wl1271_cmd_header header;
+
        __le32 rx_config_options;
        __le32 rx_filter_options;
 
index 7fcfe06..c44307c 100644 (file)
@@ -66,6 +66,32 @@ enum {
 };
 
 enum {
+       CONF_HW_RXTX_RATE_MCS7 = 0,
+       CONF_HW_RXTX_RATE_MCS6,
+       CONF_HW_RXTX_RATE_MCS5,
+       CONF_HW_RXTX_RATE_MCS4,
+       CONF_HW_RXTX_RATE_MCS3,
+       CONF_HW_RXTX_RATE_MCS2,
+       CONF_HW_RXTX_RATE_MCS1,
+       CONF_HW_RXTX_RATE_MCS0,
+       CONF_HW_RXTX_RATE_54,
+       CONF_HW_RXTX_RATE_48,
+       CONF_HW_RXTX_RATE_36,
+       CONF_HW_RXTX_RATE_24,
+       CONF_HW_RXTX_RATE_22,
+       CONF_HW_RXTX_RATE_18,
+       CONF_HW_RXTX_RATE_12,
+       CONF_HW_RXTX_RATE_11,
+       CONF_HW_RXTX_RATE_9,
+       CONF_HW_RXTX_RATE_6,
+       CONF_HW_RXTX_RATE_5_5,
+       CONF_HW_RXTX_RATE_2,
+       CONF_HW_RXTX_RATE_1,
+       CONF_HW_RXTX_RATE_MAX,
+       CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
+};
+
+enum {
        CONF_SG_DISABLE = 0,
        CONF_SG_PROTECTIVE,
        CONF_SG_OPPORTUNISTIC
@@ -648,6 +674,19 @@ struct conf_tx_settings {
         */
        u16 tx_compl_threshold;
 
+       /*
+        * The rate used for control messages and scanning on the 2.4GHz band
+        *
+        * Range: CONF_HW_BIT_RATE_* bit mask
+        */
+       u32 basic_rate;
+
+       /*
+        * The rate used for control messages and scanning on the 5GHz band
+        *
+        * Range: CONF_HW_BIT_RATE_* bit mask
+        */
+       u32 basic_rate_5;
 };
 
 enum {
@@ -717,65 +756,6 @@ enum {
        CONF_TRIG_EVENT_DIR_BIDIR
 };
 
-
-struct conf_sig_trigger {
-       /*
-        * The RSSI / SNR threshold value.
-        *
-        * FIXME: what is the range?
-        */
-       s16 threshold;
-
-       /*
-        * Minimum delay between two trigger events for this trigger in ms.
-        *
-        * Range: 0 - 60000
-        */
-       u16 pacing;
-
-       /*
-        * The measurement data source for this trigger.
-        *
-        * Range: CONF_TRIG_METRIC_*
-        */
-       u8 metric;
-
-       /*
-        * The trigger type of this trigger.
-        *
-        * Range: CONF_TRIG_EVENT_TYPE_*
-        */
-       u8 type;
-
-       /*
-        * The direction of the trigger.
-        *
-        * Range: CONF_TRIG_EVENT_DIR_*
-        */
-       u8 direction;
-
-       /*
-        * Hysteresis range of the trigger around the threshold (in dB)
-        *
-        * Range: u8
-        */
-       u8 hysteresis;
-
-       /*
-        * Index of the trigger rule.
-        *
-        * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1
-        */
-       u8 index;
-
-       /*
-        * Enable / disable this rule (to use for clearing rules.)
-        *
-        * Range: 1 - Enabled, 2 - Not enabled
-        */
-       u8 enable;
-};
-
 struct conf_sig_weights {
 
        /*
@@ -894,12 +874,6 @@ struct conf_conn_settings {
        u8 ps_poll_threshold;
 
        /*
-        * Configuration of signal (rssi/snr) triggers.
-        */
-       u8 sig_trigger_count;
-       struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS];
-
-       /*
         * Configuration of signal average weights.
         */
        struct conf_sig_weights sig_weights;
@@ -929,6 +903,22 @@ struct conf_conn_settings {
         * Range 0 - 255
         */
        u8 psm_entry_retries;
+
+       /*
+        *
+        * Specifies the interval of the connection keep-alive null-func
+        * frame in ms.
+        *
+        * Range: 1000 - 3600000
+        */
+       u32 keep_alive_interval;
+
+       /*
+        * Maximum listen interval supported by the driver in units of beacons.
+        *
+        * Range: u16
+        */
+       u8 max_listen_interval;
 };
 
 enum {
@@ -990,6 +980,43 @@ struct conf_pm_config_settings {
        bool host_fast_wakeup_support;
 };
 
+struct conf_roam_trigger_settings {
+       /*
+        * The minimum interval between two trigger events.
+        *
+        * Range: 0 - 60000 ms
+        */
+       u16 trigger_pacing;
+
+       /*
+        * The weight for rssi/beacon average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_rssi_beacon;
+
+       /*
+        * The weight for rssi/data frame average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_rssi_data;
+
+       /*
+        * The weight for snr/beacon average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_snr_beacon;
+
+       /*
+        * The weight for snr/data frame average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_snr_data;
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
@@ -998,6 +1025,7 @@ struct conf_drv_settings {
        struct conf_init_settings init;
        struct conf_itrim_settings itrim;
        struct conf_pm_config_settings pm_config;
+       struct conf_roam_trigger_settings roam_trigger;
 };
 
 #endif
index 4d35af9..cf37aa6 100644 (file)
 static int wl1271_event_scan_complete(struct wl1271 *wl,
                                      struct event_mailbox *mbox)
 {
-       int size = sizeof(struct wl12xx_probe_req_template);
        wl1271_debug(DEBUG_EVENT, "status: 0x%x",
                     mbox->scheduled_scan_status);
 
        if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
                if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
-                       wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                               NULL, size);
                        /* 2.4 GHz band scanned, scan 5 GHz band, pretend
                         * to the wl1271_cmd_scan function that we are not
                         * scanning as it checks that.
@@ -52,15 +49,6 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
                                                WL1271_SCAN_BAND_5_GHZ,
                                                wl->scan.probe_requests);
                } else {
-                       if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
-                               wl1271_cmd_template_set(wl,
-                                               CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                               NULL, size);
-                       else
-                               wl1271_cmd_template_set(wl,
-                                               CMD_TEMPL_CFG_PROBE_REQ_5,
-                                               NULL, size);
-
                        mutex_unlock(&wl->mutex);
                        ieee80211_scan_completed(wl->hw, false);
                        mutex_lock(&wl->mutex);
@@ -93,16 +81,9 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
                                                 true);
                } else {
-                       wl1271_error("PSM entry failed, giving up.\n");
-                       /* FIXME: this may need to be reconsidered. for now it
-                          is not possible to indicate to the mac80211
-                          afterwards that PSM entry failed. To maximize
-                          functionality (receiving data and remaining
-                          associated) make sure that we are in sync with the
-                          AP in regard of PSM mode. */
-                       ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                                false);
+                       wl1271_info("No ack to nullfunc from AP.");
                        wl->psm_entry_retry = 0;
+                       *beacon_loss = true;
                }
                break;
        case EVENT_ENTER_POWER_SAVE_SUCCESS:
@@ -144,6 +125,24 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
        return ret;
 }
 
+static void wl1271_event_rssi_trigger(struct wl1271 *wl,
+                                     struct event_mailbox *mbox)
+{
+       enum nl80211_cqm_rssi_threshold_event event;
+       s8 metric = mbox->rssi_snr_trigger_metric[0];
+
+       wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
+
+       if (metric <= wl->rssi_thold)
+               event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+       else
+               event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+
+       if (event != wl->last_rssi_event)
+               ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL);
+       wl->last_rssi_event = event;
+}
+
 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 {
        wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -173,10 +172,13 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
         * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
         * filtering) is enabled. Without PSM, the stack will receive all
         * beacons and can detect beacon loss by itself.
+        *
+        * As there's possibility that the driver disables PSM before receiving
+        * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
+        *
         */
-       if (vector & BSS_LOSE_EVENT_ID &&
-           test_bit(WL1271_FLAG_PSM, &wl->flags)) {
-               wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+       if (vector & BSS_LOSE_EVENT_ID) {
+               wl1271_info("Beacon loss detected.");
 
                /* indicate to the stack, that beacons have been lost */
                beacon_loss = true;
@@ -189,17 +191,15 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        return ret;
        }
 
-       if (wl->vif && beacon_loss) {
-               /* Obviously, it's dangerous to release the mutex while
-                  we are holding many of the variables in the wl struct.
-                  That's why it's done last in the function, and care must
-                  be taken that nothing more is done after this function
-                  returns. */
-               mutex_unlock(&wl->mutex);
-               ieee80211_beacon_loss(wl->vif);
-               mutex_lock(&wl->mutex);
+       if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
+               wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
+               if (wl->vif)
+                       wl1271_event_rssi_trigger(wl, mbox);
        }
 
+       if (wl->vif && beacon_loss)
+               ieee80211_connection_loss(wl->vif);
+
        return 0;
 }
 
index 278f920..5837100 100644 (file)
  */
 
 enum {
+       RSSI_SNR_TRIGGER_0_EVENT_ID              = BIT(0),
+       RSSI_SNR_TRIGGER_1_EVENT_ID              = BIT(1),
+       RSSI_SNR_TRIGGER_2_EVENT_ID              = BIT(2),
+       RSSI_SNR_TRIGGER_3_EVENT_ID              = BIT(3),
+       RSSI_SNR_TRIGGER_4_EVENT_ID              = BIT(4),
+       RSSI_SNR_TRIGGER_5_EVENT_ID              = BIT(5),
+       RSSI_SNR_TRIGGER_6_EVENT_ID              = BIT(6),
+       RSSI_SNR_TRIGGER_7_EVENT_ID              = BIT(7),
        MEASUREMENT_START_EVENT_ID               = BIT(8),
        MEASUREMENT_COMPLETE_EVENT_ID            = BIT(9),
        SCAN_COMPLETE_EVENT_ID                   = BIT(10),
index e3806b0..4447af1 100644 (file)
@@ -52,50 +52,65 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
 
 int wl1271_init_templates_config(struct wl1271 *wl)
 {
-       int ret;
+       int ret, i;
 
        /* send empty templates for fw memory reservation */
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
-                                     sizeof(struct wl12xx_probe_req_template));
+                                     sizeof(struct wl12xx_probe_req_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        if (wl1271_11a_enabled()) {
+               size_t size = sizeof(struct wl12xx_probe_req_template);
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                               NULL,
-                               sizeof(struct wl12xx_probe_req_template));
+                                             NULL, size, 0,
+                                             WL1271_RATE_AUTOMATIC);
                if (ret < 0)
                        return ret;
        }
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
-                                     sizeof(struct wl12xx_null_data_template));
+                                     sizeof(struct wl12xx_null_data_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
-                                     sizeof(struct wl12xx_ps_poll_template));
+                                     sizeof(struct wl12xx_ps_poll_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
                                      sizeof
-                                     (struct wl12xx_qos_null_data_template));
+                                     (struct wl12xx_qos_null_data_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
                                      sizeof
-                                     (struct wl12xx_probe_resp_template));
+                                     (struct wl12xx_probe_resp_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
                                      sizeof
-                                     (struct wl12xx_beacon_template));
+                                     (struct wl12xx_beacon_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
+       for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
+               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
+                                             WL1271_CMD_TEMPL_MAX_SIZE, i,
+                                             WL1271_RATE_AUTOMATIC);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -237,7 +252,7 @@ int wl1271_hw_init(struct wl1271 *wl)
                goto out_free_memmap;
 
        /* Initialize connection monitoring thresholds */
-       ret = wl1271_acx_conn_monit_params(wl);
+       ret = wl1271_acx_conn_monit_params(wl, false);
        if (ret < 0)
                goto out_free_memmap;
 
@@ -325,6 +340,24 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
+       /* disable all keep-alive templates */
+       for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
+               ret = wl1271_acx_keep_alive_config(wl, i,
+                                                  ACX_KEEP_ALIVE_TPL_INVALID);
+               if (ret < 0)
+                       goto out_free_memmap;
+       }
+
+       /* disable the keep-alive feature */
+       ret = wl1271_acx_keep_alive_mode(wl, false);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       /* Configure rssi/snr averaging weights */
+       ret = wl1271_acx_rssi_snr_avg_weights(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
        return 0;
 
  out_free_memmap:
index aa970b7..814f300 100644 (file)
@@ -117,8 +117,7 @@ static struct conf_drv_settings default_conf = {
        .tx = {
                .tx_energy_detection         = 0,
                .rc_conf                     = {
-                       .enabled_rates       = CONF_HW_BIT_RATE_1MBPS |
-                                              CONF_HW_BIT_RATE_2MBPS,
+                       .enabled_rates       = 0,
                        .short_retry_limit   = 10,
                        .long_retry_limit    = 10,
                        .aflags              = 0
@@ -215,11 +214,13 @@ static struct conf_drv_settings default_conf = {
                },
                .frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
                .tx_compl_timeout            = 700,
-               .tx_compl_threshold          = 4
+               .tx_compl_threshold          = 4,
+               .basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
+               .basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
        },
        .conn = {
                .wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
-               .listen_interval             = 0,
+               .listen_interval             = 1,
                .bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
                .bcn_filt_ie_count           = 1,
                .bcn_filt_ie = {
@@ -234,38 +235,11 @@ static struct conf_drv_settings default_conf = {
                .broadcast_timeout           = 20000,
                .rx_broadcast_in_ps          = 1,
                .ps_poll_threshold           = 20,
-               .sig_trigger_count           = 2,
-               .sig_trigger = {
-                       [0] = {
-                               .threshold   = -75,
-                               .pacing      = 500,
-                               .metric      = CONF_TRIG_METRIC_RSSI_BEACON,
-                               .type        = CONF_TRIG_EVENT_TYPE_EDGE,
-                               .direction   = CONF_TRIG_EVENT_DIR_LOW,
-                               .hysteresis  = 2,
-                               .index       = 0,
-                               .enable      = 1
-                       },
-                       [1] = {
-                               .threshold   = -75,
-                               .pacing      = 500,
-                               .metric      = CONF_TRIG_METRIC_RSSI_BEACON,
-                               .type        = CONF_TRIG_EVENT_TYPE_EDGE,
-                               .direction   = CONF_TRIG_EVENT_DIR_HIGH,
-                               .hysteresis  = 2,
-                               .index       = 1,
-                               .enable      = 1
-                       }
-               },
-               .sig_weights = {
-                       .rssi_bcn_avg_weight = 10,
-                       .rssi_pkt_avg_weight = 10,
-                       .snr_bcn_avg_weight  = 10,
-                       .snr_pkt_avg_weight  = 10
-               },
                .bet_enable                  = CONF_BET_MODE_ENABLE,
                .bet_max_consecutive         = 10,
-               .psm_entry_retries           = 3
+               .psm_entry_retries           = 3,
+               .keep_alive_interval         = 55000,
+               .max_listen_interval         = 20,
        },
        .init = {
                .radioparam = {
@@ -279,6 +253,14 @@ static struct conf_drv_settings default_conf = {
        .pm_config = {
                .host_clk_settling_time = 5000,
                .host_fast_wakeup_support = false
+       },
+       .roam_trigger = {
+               /* FIXME: due to firmware bug, must use value 1 for now */
+               .trigger_pacing               = 1,
+               .avg_weight_rssi_beacon       = 20,
+               .avg_weight_rssi_data         = 10,
+               .avg_weight_snr_beacon        = 20,
+               .avg_weight_snr_data          = 10
        }
 };
 
@@ -349,7 +331,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
                goto out_free_memmap;
 
        /* Initialize connection monitoring thresholds */
-       ret = wl1271_acx_conn_monit_params(wl);
+       ret = wl1271_acx_conn_monit_params(wl, false);
        if (ret < 0)
                goto out_free_memmap;
 
@@ -959,9 +941,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                wl->bss_type = BSS_TYPE_STA_BSS;
+               wl->set_bss_type = BSS_TYPE_STA_BSS;
                break;
        case NL80211_IFTYPE_ADHOC:
                wl->bss_type = BSS_TYPE_IBSS;
+               wl->set_bss_type = BSS_TYPE_STA_BSS;
                break;
        default:
                ret = -EOPNOTSUPP;
@@ -1066,6 +1050,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
        memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
        wl->ssid_len = 0;
        wl->bss_type = MAX_BSS_TYPE;
+       wl->set_bss_type = MAX_BSS_TYPE;
        wl->band = IEEE80211_BAND_2GHZ;
 
        wl->rx_counter = 0;
@@ -1088,6 +1073,14 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
                wl->tx_blocks_freed[i] = 0;
 
        wl1271_debugfs_reset(wl);
+
+       kfree(wl->fw_status);
+       wl->fw_status = NULL;
+       kfree(wl->tx_res_if);
+       wl->tx_res_if = NULL;
+       kfree(wl->target_mem_map);
+       wl->target_mem_map = NULL;
+
        mutex_unlock(&wl->mutex);
 }
 
@@ -1138,10 +1131,7 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel)
        /* pass through frames from all BSS */
        wl1271_configure_filters(wl, FIF_OTHER_BSS);
 
-       /* the dummy join is performed always with STATION BSS type to allow
-          also ad-hoc mode to listen to the surroundings without sending any
-          beacons yet. */
-       ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
+       ret = wl1271_cmd_join(wl, wl->set_bss_type);
        if (ret < 0)
                goto out;
 
@@ -1171,6 +1161,32 @@ out:
        return ret;
 }
 
+static void wl1271_set_band_rate(struct wl1271 *wl)
+{
+       if (wl->band == IEEE80211_BAND_2GHZ)
+               wl->basic_rate_set = wl->conf.tx.basic_rate;
+       else
+               wl->basic_rate_set = wl->conf.tx.basic_rate_5;
+}
+
+static u32 wl1271_min_rate_get(struct wl1271 *wl)
+{
+       int i;
+       u32 rate = 0;
+
+       if (!wl->basic_rate_set) {
+               WARN_ON(1);
+               wl->basic_rate_set = wl->conf.tx.basic_rate;
+       }
+
+       for (i = 0; !rate; i++) {
+               if ((wl->basic_rate_set >> i) & 0x1)
+                       rate = 1 << i;
+       }
+
+       return rate;
+}
+
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct wl1271 *wl = hw->priv;
@@ -1187,12 +1203,41 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&wl->mutex);
 
-       wl->band = conf->channel->band;
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
 
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
 
+       /* if the channel changes while joined, join again */
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               wl->band = conf->channel->band;
+               wl->channel = channel;
+
+               /*
+                * FIXME: the mac80211 should really provide a fixed rate
+                * to use here. for now, just use the smallest possible rate
+                * for the band as a fixed rate for association frames and
+                * other control messages.
+                */
+               if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+                       wl1271_set_band_rate(wl);
+
+               wl->basic_rate = wl1271_min_rate_get(wl);
+               ret = wl1271_acx_rate_policies(wl);
+               if (ret < 0)
+                       wl1271_warning("rate policy for update channel "
+                                      "failed %d", ret);
+
+               if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+                       ret = wl1271_cmd_join(wl, wl->set_bss_type);
+                       if (ret < 0)
+                               wl1271_warning("cmd join to update channel "
+                                              "failed %d", ret);
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                if (conf->flags & IEEE80211_CONF_IDLE &&
                    test_bit(WL1271_FLAG_JOINED, &wl->flags))
@@ -1201,24 +1246,17 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                        wl1271_join_channel(wl, channel);
 
                if (conf->flags & IEEE80211_CONF_IDLE) {
-                       wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+                       wl->rate_set = wl1271_min_rate_get(wl);
                        wl->sta_rate_set = 0;
                        wl1271_acx_rate_policies(wl);
-               }
+                       wl1271_acx_keep_alive_config(
+                               wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+                               ACX_KEEP_ALIVE_TPL_INVALID);
+                       set_bit(WL1271_FLAG_IDLE, &wl->flags);
+               } else
+                       clear_bit(WL1271_FLAG_IDLE, &wl->flags);
        }
 
-       /* if the channel changes while joined, join again */
-       if (channel != wl->channel &&
-           test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
-               wl->channel = channel;
-               /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
-               ret = wl1271_cmd_join(wl, wl->bss_type);
-               if (ret < 0)
-                       wl1271_warning("cmd join to update channel failed %d",
-                                      ret);
-       } else
-               wl->channel = channel;
-
        if (conf->flags & IEEE80211_CONF_PS &&
            !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
                set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
@@ -1272,6 +1310,11 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
 {
        struct wl1271_filter_params *fp;
        struct netdev_hw_addr *ha;
+       struct wl1271 *wl = hw->priv;
+       int i;
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               return 0;
 
        fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
        if (!fp) {
@@ -1314,15 +1357,16 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&wl->mutex);
 
-       if (wl->state == WL1271_STATE_OFF)
+       *total &= WL1271_SUPPORTED_FILTERS;
+       changed &= WL1271_SUPPORTED_FILTERS;
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
 
-       *total &= WL1271_SUPPORTED_FILTERS;
-       changed &= WL1271_SUPPORTED_FILTERS;
 
        if (*total & FIF_ALLMULTI)
                ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
@@ -1516,10 +1560,13 @@ out:
 static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
        struct wl1271 *wl = hw->priv;
-       int ret;
+       int ret = 0;
 
        mutex_lock(&wl->mutex);
 
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
@@ -1561,6 +1608,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        enum wl1271_cmd_ps_mode mode;
        struct wl1271 *wl = hw->priv;
        bool do_join = false;
+       bool do_keepalive = false;
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1571,20 +1619,29 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       if (wl->bss_type == BSS_TYPE_IBSS) {
-               /* FIXME: This implements rudimentary ad-hoc support -
-                  proper templates are on the wish list and notification
-                  on when they change. This patch will update the templates
-                  on every call to this function. */
+       if ((changed && BSS_CHANGED_BEACON_INT) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
+                       bss_conf->beacon_int);
+
+               wl->beacon_int = bss_conf->beacon_int;
+               do_join = true;
+       }
+
+       if ((changed && BSS_CHANGED_BEACON) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
+
                if (beacon) {
                        struct ieee80211_hdr *hdr;
 
                        wl1271_ssid_set(wl, beacon);
                        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
                                                      beacon->data,
-                                                     beacon->len);
+                                                     beacon->len, 0,
+                                                     wl1271_min_rate_get(wl));
 
                        if (ret < 0) {
                                dev_kfree_skb(beacon);
@@ -1599,7 +1656,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        ret = wl1271_cmd_template_set(wl,
                                                      CMD_TEMPL_PROBE_RESPONSE,
                                                      beacon->data,
-                                                     beacon->len);
+                                                     beacon->len, 0,
+                                                     wl1271_min_rate_get(wl));
                        dev_kfree_skb(beacon);
                        if (ret < 0)
                                goto out_sleep;
@@ -1609,6 +1667,30 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
+                            bss_conf->enable_beacon ? "enabled" : "disabled");
+
+               if (bss_conf->enable_beacon)
+                       wl->set_bss_type = BSS_TYPE_IBSS;
+               else
+                       wl->set_bss_type = BSS_TYPE_STA_BSS;
+               do_join = true;
+       }
+
+       if (changed & BSS_CHANGED_CQM) {
+               bool enable = false;
+               if (bss_conf->cqm_rssi_thold)
+                       enable = true;
+               ret = wl1271_acx_rssi_snr_trigger(wl, enable,
+                                                 bss_conf->cqm_rssi_thold,
+                                                 bss_conf->cqm_rssi_hyst);
+               if (ret < 0)
+                       goto out;
+               wl->rssi_thold = bss_conf->cqm_rssi_thold;
+       }
+
        if ((changed & BSS_CHANGED_BSSID) &&
            /*
             * Now we know the correct bssid, so we send a new join command
@@ -1630,10 +1712,23 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
+                       u32 rates;
                        wl->aid = bss_conf->aid;
                        set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 
                        /*
+                        * use basic rates from AP, and determine lowest rate
+                        * to use with control frames.
+                        */
+                       rates = bss_conf->basic_rates;
+                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
+                                                                        rates);
+                       wl->basic_rate = wl1271_min_rate_get(wl);
+                       ret = wl1271_acx_rate_policies(wl);
+                       if (ret < 0)
+                               goto out_sleep;
+
+                       /*
                         * with wl1271, we don't need to update the
                         * beacon_int and dtim_period, because the firmware
                         * updates it by itself when the first beacon is
@@ -1643,7 +1738,30 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (ret < 0)
                                goto out_sleep;
 
-                       ret = wl1271_acx_aid(wl, wl->aid);
+                       /*
+                        * The SSID is intentionally set to NULL here - the
+                        * firmware will set the probe request with a
+                        * broadcast SSID regardless of what we set in the
+                        * template.
+                        */
+                       ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
+                                                        NULL, 0, wl->band);
+
+                       /* Enable the keep-alive feature */
+                       ret = wl1271_acx_keep_alive_mode(wl, true);
+                       if (ret < 0)
+                               goto out_sleep;
+
+                       /*
+                        * This is awkward. The keep-alive configs must be done
+                        * *after* the join command, because otherwise it will
+                        * not work, but it must only be done *once* because
+                        * otherwise the firmware will start complaining.
+                        */
+                       do_keepalive = true;
+
+                       /* enable the connection monitoring feature */
+                       ret = wl1271_acx_conn_monit_params(wl, true);
                        if (ret < 0)
                                goto out_sleep;
 
@@ -1659,6 +1777,22 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        /* use defaults when not associated */
                        clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
                        wl->aid = 0;
+
+                       /* revert back to minimum rates for the current band */
+                       wl1271_set_band_rate(wl);
+                       wl->basic_rate = wl1271_min_rate_get(wl);
+                       ret = wl1271_acx_rate_policies(wl);
+                       if (ret < 0)
+                               goto out_sleep;
+
+                       /* disable connection monitor features */
+                       ret = wl1271_acx_conn_monit_params(wl, false);
+
+                       /* Disable the keep-alive feature */
+                       ret = wl1271_acx_keep_alive_mode(wl, false);
+
+                       if (ret < 0)
+                               goto out_sleep;
                }
 
        }
@@ -1693,7 +1827,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (do_join) {
-               ret = wl1271_cmd_join(wl, wl->bss_type);
+               ret = wl1271_cmd_join(wl, wl->set_bss_type);
                if (ret < 0) {
                        wl1271_warning("cmd join failed %d", ret);
                        goto out_sleep;
@@ -1701,6 +1835,29 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                set_bit(WL1271_FLAG_JOINED, &wl->flags);
        }
 
+       /*
+        * The JOIN operation shuts down the firmware keep-alive as a side
+        * effect, and the ACX_AID will start the keep-alive as a side effect.
+        * Hence, for non-IBSS, the ACX_AID must always happen *after* the
+        * JOIN operation, and the template config after the ACX_AID.
+        */
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+               ret = wl1271_acx_aid(wl, wl->aid);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
+       if (do_keepalive) {
+               ret = wl1271_cmd_build_klv_null_data(wl);
+               if (ret < 0)
+                       goto out_sleep;
+               ret = wl1271_acx_keep_alive_config(
+                       wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+                       ACX_KEEP_ALIVE_TPL_VALID);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
 out_sleep:
        wl1271_ps_elp_sleep(wl);
 
@@ -1812,6 +1969,36 @@ static struct ieee80211_channel wl1271_channels[] = {
        { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
 };
 
+/* mapping to indexes for wl1271_rates */
+const static u8 wl1271_rate_to_idx_2ghz[] = {
+       /* MCS rates are used only with 11n */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+
+       11,                            /* CONF_HW_RXTX_RATE_54   */
+       10,                            /* CONF_HW_RXTX_RATE_48   */
+       9,                             /* CONF_HW_RXTX_RATE_36   */
+       8,                             /* CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22   */
+
+       7,                             /* CONF_HW_RXTX_RATE_18   */
+       6,                             /* CONF_HW_RXTX_RATE_12   */
+       3,                             /* CONF_HW_RXTX_RATE_11   */
+       5,                             /* CONF_HW_RXTX_RATE_9    */
+       4,                             /* CONF_HW_RXTX_RATE_6    */
+       2,                             /* CONF_HW_RXTX_RATE_5_5  */
+       1,                             /* CONF_HW_RXTX_RATE_2    */
+       0                              /* CONF_HW_RXTX_RATE_1    */
+};
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1271_band_2ghz = {
        .channels = wl1271_channels,
@@ -1894,6 +2081,35 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
        { .hw_value = 165, .center_freq = 5825},
 };
 
+/* mapping to indexes for wl1271_rates_5ghz */
+const static u8 wl1271_rate_to_idx_5ghz[] = {
+       /* MCS rates are used only with 11n */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+
+       7,                             /* CONF_HW_RXTX_RATE_54   */
+       6,                             /* CONF_HW_RXTX_RATE_48   */
+       5,                             /* CONF_HW_RXTX_RATE_36   */
+       4,                             /* CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22   */
+
+       3,                             /* CONF_HW_RXTX_RATE_18   */
+       2,                             /* CONF_HW_RXTX_RATE_12   */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11   */
+       1,                             /* CONF_HW_RXTX_RATE_9    */
+       0,                             /* CONF_HW_RXTX_RATE_6    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5  */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED  /* CONF_HW_RXTX_RATE_1    */
+};
 
 static struct ieee80211_supported_band wl1271_band_5ghz = {
        .channels = wl1271_channels_5ghz,
@@ -1902,6 +2118,11 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
        .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
 };
 
+const static u8 *wl1271_band_rate_to_idx[] = {
+       [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
+       [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
+};
+
 static const struct ieee80211_ops wl1271_ops = {
        .start = wl1271_op_start,
        .stop = wl1271_op_stop,
@@ -1919,6 +2140,27 @@ static const struct ieee80211_ops wl1271_ops = {
        CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
+
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
+{
+       u8 idx;
+
+       BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
+
+       if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
+               wl1271_error("Illegal RX rate from HW: %d", rate);
+               return 0;
+       }
+
+       idx = wl1271_band_rate_to_idx[wl->band][rate];
+       if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
+               wl1271_error("Unsupported RX rate from HW: %d", rate);
+               return 0;
+       }
+
+       return idx;
+}
+
 static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
                                               struct device_attribute *attr,
                                               char *buf)
@@ -2021,13 +2263,16 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
        /* unit us */
        /* FIXME: find a proper value */
        wl->hw->channel_change_time = 10000;
+       wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_BEACON_FILTER |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_SUPPORTS_UAPSD |
-               IEEE80211_HW_HAS_RATE_CONTROL;
+               IEEE80211_HW_HAS_RATE_CONTROL |
+               IEEE80211_HW_CONNECTION_MONITOR |
+               IEEE80211_HW_SUPPORTS_CQM_RSSI;
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
@@ -2038,6 +2283,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
                wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
 
        wl->hw->queues = 4;
+       wl->hw->max_rates = 1;
 
        SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
 
@@ -2053,7 +2299,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        struct platform_device *plat_dev = NULL;
        struct wl1271 *wl;
        int i, ret;
-       static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
@@ -2083,6 +2328,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
+       wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
        wl->default_key = 0;
        wl->rx_counter = 0;
        wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
@@ -2090,6 +2336,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->psm_entry_retry = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
        wl->sta_rate_set = 0;
        wl->band = IEEE80211_BAND_2GHZ;
@@ -2105,13 +2352,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->state = WL1271_STATE_OFF;
        mutex_init(&wl->mutex);
 
-       /*
-        * FIXME: we should use a zero MAC address here, but for now we
-        * generate a random Nokia address.
-        */
-       memcpy(wl->mac_addr, nokia_oui, 3);
-       get_random_bytes(wl->mac_addr + 3, 3);
-
        /* Apply default driver configuration. */
        wl1271_conf_init(wl);
 
@@ -2157,7 +2397,6 @@ int wl1271_free_hw(struct wl1271 *wl)
 
        wl1271_debugfs_exit(wl);
 
-       kfree(wl->target_mem_map);
        vfree(wl->fw);
        wl->fw = NULL;
        kfree(wl->nvs);
index 5a04482..a5e60e0 100644 (file)
@@ -40,7 +40,8 @@ void wl1271_elp_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
 
        if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
-           !test_bit(WL1271_FLAG_PSM, &wl->flags))
+           (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+            !test_bit(WL1271_FLAG_IDLE, &wl->flags)))
                goto out;
 
        wl1271_debug(DEBUG_PSM, "chip to elp");
@@ -56,7 +57,8 @@ out:
 /* Routines to toggle sleep mode while in ELP */
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
-       if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+       if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
+           test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
                cancel_delayed_work(&wl->elp_work);
                ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
                                        msecs_to_jiffies(ELP_ENTRY_DELAY));
index 6f1b732..57f4bfd 100644 (file)
@@ -43,66 +43,6 @@ static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
                RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
 }
 
-/* The values of this table must match the wl1271_rates[] array */
-static u8 wl1271_rx_rate_to_idx[] = {
-       /* MCS rates are used only with 11n */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
-
-       11,                         /* WL1271_RATE_54   */
-       10,                         /* WL1271_RATE_48   */
-       9,                          /* WL1271_RATE_36   */
-       8,                          /* WL1271_RATE_24   */
-
-       /* TI-specific rate */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */
-
-       7,                          /* WL1271_RATE_18   */
-       6,                          /* WL1271_RATE_12   */
-       3,                          /* WL1271_RATE_11   */
-       5,                          /* WL1271_RATE_9    */
-       4,                          /* WL1271_RATE_6    */
-       2,                          /* WL1271_RATE_5_5  */
-       1,                          /* WL1271_RATE_2    */
-       0                           /* WL1271_RATE_1    */
-};
-
-/* The values of this table must match the wl1271_rates[] array */
-static u8 wl1271_5_ghz_rx_rate_to_idx[] = {
-       /* MCS rates are used only with 11n */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
-
-       7,                          /* WL1271_RATE_54   */
-       6,                          /* WL1271_RATE_48   */
-       5,                          /* WL1271_RATE_36   */
-       4,                          /* WL1271_RATE_24   */
-
-       /* TI-specific rate */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */
-
-       3,                          /* WL1271_RATE_18   */
-       2,                          /* WL1271_RATE_12   */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11   */
-       1,                          /* WL1271_RATE_9    */
-       0,                          /* WL1271_RATE_6    */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5  */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2    */
-       WL1271_RX_RATE_UNSUPPORTED  /* WL1271_RATE_1    */
-};
-
 static void wl1271_rx_status(struct wl1271 *wl,
                             struct wl1271_rx_descriptor *desc,
                             struct ieee80211_rx_status *status,
@@ -110,20 +50,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
 {
        memset(status, 0, sizeof(struct ieee80211_rx_status));
 
-       if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
-           WL1271_RX_DESC_BAND_BG) {
-               status->band = IEEE80211_BAND_2GHZ;
-               status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
-       } else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
-                WL1271_RX_DESC_BAND_A) {
-               status->band = IEEE80211_BAND_5GHZ;
-               status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate];
-       } else
-               wl1271_warning("unsupported band 0x%x",
-                              desc->flags & WL1271_RX_DESC_BAND_MASK);
-
-       if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED))
-               wl1271_warning("unsupported rate");
+       status->band = wl->band;
+       status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
 
        /*
         * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
@@ -133,13 +61,6 @@ static void wl1271_rx_status(struct wl1271 *wl,
         */
        status->signal = desc->rssi;
 
-       /*
-        * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
-        * need to divide by two for now, but TI has been discussing about
-        * changing it.  This needs to be rechecked.
-        */
-       status->noise = desc->rssi - (desc->snr >> 1);
-
        status->freq = ieee80211_channel_to_frequency(desc->channel);
 
        if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
index 1ae6d17..b89be47 100644 (file)
@@ -43,7 +43,6 @@
 #define RX_MAX_PACKET_ID 3
 
 #define NUM_RX_PKT_DESC_MOD_MASK   7
-#define WL1271_RX_RATE_UNSUPPORTED 0xFF
 
 #define RX_DESC_VALID_FCS         0x0001
 #define RX_DESC_MATCH_RXADDR1     0x0002
@@ -117,5 +116,6 @@ struct wl1271_rx_descriptor {
 } __attribute__ ((packed));
 
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
 
 #endif
index 3c03de7..d3d6f30 100644 (file)
@@ -117,7 +117,7 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
                else
                        ret = sdio_memcpy_fromio(func, buf, addr, len);
 
-               wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %d bytes",
+               wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
                             addr, len);
                wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
        }
@@ -138,7 +138,7 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
                wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
                             addr, ((u8 *)buf)[0]);
        } else {
-               wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %d bytes",
+               wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
                             addr, len);
                wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
 
@@ -255,7 +255,7 @@ static void __devexit wl1271_remove(struct sdio_func *func)
 }
 
 static struct sdio_driver wl1271_sdio_driver = {
-       .name           = "wl1271",
+       .name           = "wl1271_sdio",
        .id_table       = wl1271_devices,
        .probe          = wl1271_probe,
        .remove         = __devexit_p(wl1271_remove),
index 256e84a..5189b81 100644 (file)
@@ -105,6 +105,7 @@ static void wl1271_spi_reset(struct wl1271 *wl)
        spi_message_add_tail(&t, &m);
 
        spi_sync(wl_to_spi(wl), &m);
+       kfree(cmd);
 
        wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
 }
@@ -159,47 +160,24 @@ static void wl1271_spi_init(struct wl1271 *wl)
        spi_message_add_tail(&t, &m);
 
        spi_sync(wl_to_spi(wl), &m);
+       kfree(cmd);
 
        wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
 }
 
 #define WL1271_BUSY_WORD_TIMEOUT 1000
 
-/* FIXME: Check busy words, removed due to SPI bug */
-#if 0
-static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
+static int wl1271_spi_read_busy(struct wl1271 *wl)
 {
        struct spi_transfer t[1];
        struct spi_message m;
        u32 *busy_buf;
        int num_busy_bytes = 0;
 
-       wl1271_info("spi read BUSY!");
-
-       /*
-        * Look for the non-busy word in the read buffer, and if found,
-        * read in the remaining data into the buffer.
-        */
-       busy_buf = (u32 *)buf;
-       for (; (u32)busy_buf < (u32)buf + len; busy_buf++) {
-               num_busy_bytes += sizeof(u32);
-               if (*busy_buf & 0x1) {
-                       spi_message_init(&m);
-                       memset(t, 0, sizeof(t));
-                       memmove(buf, busy_buf, len - num_busy_bytes);
-                       t[0].rx_buf = buf + (len - num_busy_bytes);
-                       t[0].len = num_busy_bytes;
-                       spi_message_add_tail(&t[0], &m);
-                       spi_sync(wl_to_spi(wl), &m);
-                       return;
-               }
-       }
-
        /*
         * Read further busy words from SPI until a non-busy word is
         * encountered, then read the data itself into the buffer.
         */
-       wl1271_info("spi read BUSY-polling needed!");
 
        num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT;
        busy_buf = wl->buffer_busyword;
@@ -209,28 +187,21 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
                memset(t, 0, sizeof(t));
                t[0].rx_buf = busy_buf;
                t[0].len = sizeof(u32);
+               t[0].cs_change = true;
                spi_message_add_tail(&t[0], &m);
                spi_sync(wl_to_spi(wl), &m);
 
-               if (*busy_buf & 0x1) {
-                       spi_message_init(&m);
-                       memset(t, 0, sizeof(t));
-                       t[0].rx_buf = buf;
-                       t[0].len = len;
-                       spi_message_add_tail(&t[0], &m);
-                       spi_sync(wl_to_spi(wl), &m);
-                       return;
-               }
+               if (*busy_buf & 0x1)
+                       return 0;
        }
 
        /* The SPI bus is unresponsive, the read failed. */
-       memset(buf, 0, len);
        wl1271_error("SPI read busy-word timeout!\n");
+       return -ETIMEDOUT;
 }
-#endif
 
 static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
-                        size_t len, bool fixed)
+                               size_t len, bool fixed)
 {
        struct spi_transfer t[3];
        struct spi_message m;
@@ -253,22 +224,32 @@ static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
 
        t[0].tx_buf = cmd;
        t[0].len = 4;
+       t[0].cs_change = true;
        spi_message_add_tail(&t[0], &m);
 
        /* Busy and non busy words read */
        t[1].rx_buf = busy_buf;
        t[1].len = WL1271_BUSY_WORD_LEN;
+       t[1].cs_change = true;
        spi_message_add_tail(&t[1], &m);
 
-       t[2].rx_buf = buf;
-       t[2].len = len;
-       spi_message_add_tail(&t[2], &m);
-
        spi_sync(wl_to_spi(wl), &m);
 
-       /* FIXME: Check busy words, removed due to SPI bug */
-       /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1))
-          wl1271_spi_read_busy(wl, buf, len); */
+       if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
+           wl1271_spi_read_busy(wl)) {
+               memset(buf, 0, len);
+               return;
+       }
+
+       spi_message_init(&m);
+       memset(t, 0, sizeof(t));
+
+       t[0].rx_buf = buf;
+       t[0].len = len;
+       t[0].cs_change = true;
+       spi_message_add_tail(&t[0], &m);
+
+       spi_sync(wl_to_spi(wl), &m);
 
        wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
        wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
@@ -443,7 +424,7 @@ static int __devexit wl1271_remove(struct spi_device *spi)
 
 static struct spi_driver wl1271_spi_driver = {
        .driver = {
-               .name           = "wl1271",
+               .name           = "wl1271_spi",
                .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
index 6d109df..62db795 100644 (file)
@@ -220,7 +220,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
        return ret;
 }
 
-static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
 {
        struct ieee80211_supported_band *band;
        u32 enabled_rates = 0;
@@ -304,6 +304,8 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        struct ieee80211_tx_info *info;
        struct sk_buff *skb;
        int id = result->id;
+       int rate = -1;
+       u8 retries = 0;
 
        /* check for id legality */
        if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
@@ -314,19 +316,22 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        skb = wl->tx_frames[id];
        info = IEEE80211_SKB_CB(skb);
 
-       /* update packet status */
-       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-               if (result->status == TX_SUCCESS)
+       /* update the TX status info */
+       if (result->status == TX_SUCCESS) {
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                        info->flags |= IEEE80211_TX_STAT_ACK;
-               if (result->status & TX_RETRY_EXCEEDED) {
-                       /* FIXME */
-                       /* info->status.excessive_retries = 1; */
-                       wl->stats.excessive_retries++;
-               }
+               rate = wl1271_rate_to_idx(wl, result->rate_class_index);
+               retries = result->ack_failures;
+       } else if (result->status == TX_RETRY_EXCEEDED) {
+               wl->stats.excessive_retries++;
+               retries = result->ack_failures;
        }
 
-       /* FIXME */
-       /* info->status.retry_count = result->ack_failures; */
+       info->status.rates[0].idx = rate;
+       info->status.rates[0].count = retries;
+       info->status.rates[0].flags = 0;
+       info->status.ack_signal = -1;
+
        wl->stats.retry_count += result->ack_failures;
 
        /* update security sequence number */
@@ -350,8 +355,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
                     result->id, skb, result->ack_failures,
                     result->rate_class_index, result->status);
 
-       /* FIXME: do we need to tell the stack about the used rate? */
-
        /* return the packet to the stack */
        ieee80211_tx_status(wl->hw, skb);
        wl->tx_frames[result->id] = NULL;
@@ -413,31 +416,19 @@ void wl1271_tx_flush(struct wl1271 *wl)
 {
        int i;
        struct sk_buff *skb;
-       struct ieee80211_tx_info *info;
 
        /* TX failure */
 /*     control->flags = 0; FIXME */
 
        while ((skb = skb_dequeue(&wl->tx_queue))) {
-               info = IEEE80211_SKB_CB(skb);
-
                wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
-
-               if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
-                               continue;
-
                ieee80211_tx_status(wl->hw, skb);
        }
 
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                if (wl->tx_frames[i] != NULL) {
                        skb = wl->tx_frames[i];
-                       info = IEEE80211_SKB_CB(skb);
-
-                       if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
-                               continue;
-
-                       ieee80211_tx_status(wl->hw, skb);
                        wl->tx_frames[i] = NULL;
+                       ieee80211_tx_status(wl->hw, skb);
                }
 }
index 5e6c27a..3b8b7ac 100644 (file)
@@ -159,5 +159,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
 void wl1271_tx_work(struct work_struct *work);
 void wl1271_tx_complete(struct wl1271 *wl);
 void wl1271_tx_flush(struct wl1271 *wl);
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
 
 #endif
index 1998495..1252ba1 100644 (file)
@@ -1211,6 +1211,8 @@ enum ieee80211_category {
        WLAN_CATEGORY_SA_QUERY = 8,
        WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
        WLAN_CATEGORY_WMM = 17,
+       WLAN_CATEGORY_MESH_PLINK = 30,          /* Pending ANA approval */
+       WLAN_CATEGORY_MESH_PATH_SEL = 32,       /* Pending ANA approval */
        WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
        WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
 };
@@ -1324,7 +1326,6 @@ enum ieee80211_back_actioncode {
 enum ieee80211_back_parties {
        WLAN_BACK_RECIPIENT = 0,
        WLAN_BACK_INITIATOR = 1,
-       WLAN_BACK_TIMER = 2,
 };
 
 /* SA Query action */
index 0ebaef5..329a8fa 100644 (file)
@@ -94,6 +94,8 @@
 
 #define  SDIO_BUS_WIDTH_1BIT   0x00
 #define  SDIO_BUS_WIDTH_4BIT   0x02
+#define  SDIO_BUS_ECSI         0x20    /* Enable continuous SPI interrupt */
+#define  SDIO_BUS_SCSI         0x40    /* Support continuous SPI interrupt */
 
 #define  SDIO_BUS_ASYNC_INT    0x20
 
index daf6a34..2ea3ede 100644 (file)
@@ -703,6 +703,12 @@ enum nl80211_commands {
  * @NL80211_ATTR_CQM: connection quality monitor configuration in a
  *     nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
  *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ *     is requesting a local authentication/association state change without
+ *     invoking actual management frame exchange. This can be used with
+ *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ *     NL80211_CMD_DISASSOCIATE.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -856,6 +862,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_CQM,
 
+       NL80211_ATTR_LOCAL_STATE_CHANGE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index 868cfd3..37cebd3 100644 (file)
@@ -704,6 +704,10 @@ struct cfg80211_crypto_settings {
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
  * @key: WEP key for shared key authentication
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Authentication frame is to be transmitted and authentication state is
+ *     to be changed without having to wait for a response from the peer STA
+ *     (AP).
  */
 struct cfg80211_auth_request {
        struct cfg80211_bss *bss;
@@ -712,6 +716,7 @@ struct cfg80211_auth_request {
        enum nl80211_auth_type auth_type;
        const u8 *key;
        u8 key_len, key_idx;
+       bool local_state_change;
 };
 
 /**
@@ -744,12 +749,15 @@ struct cfg80211_assoc_request {
  * @ie: Extra IEs to add to Deauthentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @reason_code: The reason code for the deauthentication
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Deauthentication frame is to be transmitted.
  */
 struct cfg80211_deauth_request {
        struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
        u16 reason_code;
+       bool local_state_change;
 };
 
 /**
@@ -762,12 +770,15 @@ struct cfg80211_deauth_request {
  * @ie: Extra IEs to add to Disassociation frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @reason_code: The reason code for the disassociation
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Disassociation frame is to be transmitted.
  */
 struct cfg80211_disassoc_request {
        struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
        u16 reason_code;
+       bool local_state_change;
 };
 
 /**
index b2b98f3..3afdb21 100644 (file)
@@ -323,7 +323,7 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
 struct iw_handler_def {
 
        /* Array of handlers for standard ioctls
-        * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT]
+        * We will call dev->wireless_handlers->standard[ioctl - SIOCIWFIRST]
         */
        const iw_handler *      standard;
        /* Number of handlers defined (more precisely, index of the
index 20823d0..344e5bf 100644 (file)
@@ -587,11 +587,15 @@ struct ieee80211_rx_status {
  *     may turn the device off as much as possible. Typically, this flag will
  *     be set when an interface is set UP but not associated or scanning, but
  *     it can also be unset in that case when monitor interfaces are active.
+ * @IEEE80211_CONF_QOS: Enable 802.11e QoS also know as WMM (Wireless
+ *      Multimedia). On some drivers (iwlwifi is one of know) we have
+ *      to enable/disable QoS explicitly.
  */
 enum ieee80211_conf_flags {
        IEEE80211_CONF_MONITOR          = (1<<0),
        IEEE80211_CONF_PS               = (1<<1),
        IEEE80211_CONF_IDLE             = (1<<2),
+       IEEE80211_CONF_QOS              = (1<<3),
 };
 
 
@@ -616,6 +620,7 @@ enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_CHANNEL           = BIT(6),
        IEEE80211_CONF_CHANGE_RETRY_LIMITS      = BIT(7),
        IEEE80211_CONF_CHANGE_IDLE              = BIT(8),
+       IEEE80211_CONF_CHANGE_QOS               = BIT(9),
 };
 
 /**
@@ -1822,7 +1827,10 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
  * ieee80211_rx - receive frame
  *
  * Use this function to hand received frames to mac80211. The receive
- * buffer in @skb must start with an IEEE 802.11 header.
+ * buffer in @skb must start with an IEEE 802.11 header. In case of a
+ * paged @skb is used, the driver is recommended to put the ieee80211
+ * header of the frame on the linear part of the @skb to avoid memory
+ * allocation and/or memcpy by the stack.
  *
  * This function may not be called in IRQ context. Calls to this function
  * for a single hardware must be synchronized against each other. Calls to
index 334c359..8a91f6c 100644 (file)
@@ -221,8 +221,8 @@ config MAC80211_DRIVER_API_TRACER
        depends on EVENT_TRACING
        help
          Say Y here to make mac80211 register with the ftrace
-         framework for the driver API -- you can see which
-         driver methods it is calling then by looking at the
-         trace.
+         framework for the driver API -- you can then see which
+         driver methods it is calling and which API functions
+         drivers are calling by looking at the trace.
 
-         If unsure, say N.
+         If unsure, say Y.
index f9516a2..9598fdb 100644 (file)
@@ -23,19 +23,20 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason)
 {
        struct ieee80211_local *local = sta->local;
+       struct tid_ampdu_rx *tid_rx;
        int i;
 
-       /* check if TID is in operational state */
        spin_lock_bh(&sta->lock);
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) {
+
+       /* check if TID is in operational state */
+       if (!sta->ampdu_mlme.tid_active_rx[tid]) {
                spin_unlock_bh(&sta->lock);
                return;
        }
 
-       sta->ampdu_mlme.tid_state_rx[tid] =
-               HT_AGG_STATE_REQ_STOP_BA_MSK |
-               (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-       spin_unlock_bh(&sta->lock);
+       sta->ampdu_mlme.tid_active_rx[tid] = false;
+
+       tid_rx = sta->ampdu_mlme.tid_rx[tid];
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
@@ -47,61 +48,35 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                printk(KERN_DEBUG "HW problem - can not stop rx "
                                "aggregation for tid %d\n", tid);
 
-       /* shutdown timer has not expired */
-       if (initiator != WLAN_BACK_TIMER)
-               del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
        /* check if this is a self generated aggregation halt */
-       if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+       if (initiator == WLAN_BACK_RECIPIENT)
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, 0, reason);
 
        /* free the reordering buffer */
-       for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
-               if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
+       for (i = 0; i < tid_rx->buf_size; i++) {
+               if (tid_rx->reorder_buf[i]) {
                        /* release the reordered frames */
-                       dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
-                       sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
-                       sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
+                       dev_kfree_skb(tid_rx->reorder_buf[i]);
+                       tid_rx->stored_mpdu_num--;
+                       tid_rx->reorder_buf[i] = NULL;
                }
        }
 
-       spin_lock_bh(&sta->lock);
        /* free resources */
-       kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
-       kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time);
+       kfree(tid_rx->reorder_buf);
+       kfree(tid_rx->reorder_time);
+       sta->ampdu_mlme.tid_rx[tid] = NULL;
 
-       if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
-               kfree(sta->ampdu_mlme.tid_rx[tid]);
-               sta->ampdu_mlme.tid_rx[tid] = NULL;
-       }
-
-       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
        spin_unlock_bh(&sta->lock);
-}
-
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
-                                       u16 initiator, u16 reason)
-{
-       struct sta_info *sta;
-
-       rcu_read_lock();
-
-       sta = sta_info_get(sdata, ra);
-       if (!sta) {
-               rcu_read_unlock();
-               return;
-       }
-
-       __ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
 
-       rcu_read_unlock();
+       del_timer_sync(&tid_rx->session_timer);
+       kfree(tid_rx);
 }
 
 /*
  * After accepting the AddBA Request we activated a timer,
  * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
  */
 static void sta_rx_agg_session_timer_expired(unsigned long data)
 {
@@ -117,9 +92,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
 #endif
-       ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                                        (u16)*ptid, WLAN_BACK_TIMER,
-                                        WLAN_REASON_QSTA_TIMEOUT);
+       __ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT,
+                                      WLAN_REASON_QSTA_TIMEOUT);
 }
 
 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
@@ -194,7 +168,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
        status = WLAN_STATUS_REQUEST_DECLINED;
 
-       if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
+       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying ADDBA request\n");
@@ -232,7 +206,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        /* examine state machine */
        spin_lock_bh(&sta->lock);
 
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
+       if (sta->ampdu_mlme.tid_active_rx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -294,7 +268,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        }
 
        /* change state and send addba resp */
-       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
+       sta->ampdu_mlme.tid_active_rx[tid] = true;
        tid_agg_rx->dialog_token = dialog_token;
        tid_agg_rx->ssn = start_seq_num;
        tid_agg_rx->head_seq_num = start_seq_num;
index 96d2534..608063f 100644 (file)
@@ -215,6 +215,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
        int ret = 0;
        u16 start_seq_num;
 
+       trace_api_start_tx_ba_session(pubsta, tid);
+
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
 
@@ -246,7 +248,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
                return -EINVAL;
        }
 
-       if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
+       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying BA session request\n");
@@ -415,7 +417,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
                                         struct sta_info *sta, u16 tid)
 {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+       printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
 #endif
 
        spin_lock(&local->ampdu_lock);
@@ -441,6 +443,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        struct sta_info *sta;
        u8 *state;
 
+       trace_api_start_tx_ba_cb(sdata, ra, tid);
+
        if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
@@ -542,6 +546,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
 
+       trace_api_stop_tx_ba_session(pubsta, tid, initiator);
+
        if (!local->ops->ampdu_action)
                return -EINVAL;
 
@@ -559,6 +565,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
        struct sta_info *sta;
        u8 *state;
 
+       trace_api_stop_tx_ba_cb(sdata, ra, tid);
+
        if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
@@ -675,7 +683,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
        del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+       printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
index c41aaba..7dd7cda 100644 (file)
@@ -1137,6 +1137,10 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+
        return 0;
 }
 
@@ -1412,9 +1416,6 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
        struct ieee80211_vif *vif = &sdata->vif;
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
-       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI))
-               return -EOPNOTSUPP;
-
        if (rssi_thold == bss_conf->cqm_rssi_thold &&
            rssi_hyst == bss_conf->cqm_rssi_hyst)
                return 0;
@@ -1422,6 +1423,12 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
        bss_conf->cqm_rssi_thold = rssi_thold;
        bss_conf->cqm_rssi_hyst = rssi_hyst;
 
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return -EOPNOTSUPP;
+               return 0;
+       }
+
        /* tell the driver upon association, unless already associated */
        if (sdata->u.mgd.associated)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
index 83d4289..20b2998 100644 (file)
@@ -100,6 +100,14 @@ static ssize_t ieee80211_if_fmt_##name(                                    \
        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 }
 
+#define IEEE80211_IF_FMT_DEC_DIV_16(name, field)                       \
+static ssize_t ieee80211_if_fmt_##name(                                        \
+       const struct ieee80211_sub_if_data *sdata,                      \
+       char *buf, int buflen)                                          \
+{                                                                      \
+       return scnprintf(buf, buflen, "%d\n", sdata->field / 16);       \
+}
+
 #define __IEEE80211_IF_FILE(name, _write)                              \
 static ssize_t ieee80211_if_read_##name(struct file *file,             \
                                        char __user *userbuf,           \
@@ -140,6 +148,8 @@ IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
+IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
+IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
 
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
                              enum ieee80211_smps_mode smps_mode)
@@ -276,6 +286,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 
        DEBUGFS_ADD(bssid);
        DEBUGFS_ADD(aid);
+       DEBUGFS_ADD(last_beacon);
+       DEBUGFS_ADD(ave_beacon);
        DEBUGFS_ADD_MODE(smps, 0600);
 }
 
index 23e7200..6bc9b07 100644 (file)
@@ -119,7 +119,7 @@ STA_OPS(last_seq_ctrl);
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
-       char buf[64 + STA_TID_NUM * 40], *p = buf;
+       char buf[71 + STA_TID_NUM * 40], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
 
@@ -127,16 +127,16 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
                        sta->ampdu_mlme.dialog_token_allocator + 1);
        p += scnprintf(p, sizeof(buf) + buf - p,
-                      "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
+                      "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
        for (i = 0; i < STA_TID_NUM; i++) {
                p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-                               sta->ampdu_mlme.tid_state_rx[i]);
+                               sta->ampdu_mlme.tid_active_rx[i]);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_active_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
-                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_active_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->ssn : 0);
 
                p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
@@ -176,7 +176,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
        if (htc->ht_supported) {
                p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap);
 
-               PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP");
+               PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDPC");
                PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
                PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20");
 
index 41baf73..e209cb8 100644 (file)
@@ -32,6 +32,10 @@ static inline void trace_ ## name(proto) {}
 #define VIF_PR_FMT     " vif:%s(%d)"
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type
 
+/*
+ * Tracing for driver callbacks.
+ */
+
 TRACE_EVENT(drv_start,
        TP_PROTO(struct ieee80211_local *local, int ret),
 
@@ -766,6 +770,277 @@ TRACE_EVENT(drv_flush,
                LOCAL_PR_ARG, __entry->drop
        )
 );
+
+/*
+ * Tracing for API calls that drivers call.
+ */
+
+TRACE_EVENT(api_start_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+       TP_ARGS(sta, tid),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d",
+               STA_PR_ARG, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_start_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator),
+
+       TP_ARGS(sta, tid, initiator),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+               __field(u16, initiator)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+               __entry->initiator = initiator;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d initiator:%d",
+               STA_PR_ARG, __entry->tid, __entry->initiator
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_restart_hw,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT,
+               LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_beacon_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_connection_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_cqm_rssi_notify,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                enum nl80211_cqm_rssi_threshold_event rssi_event),
+
+       TP_ARGS(sdata, rssi_event),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(u32, rssi_event)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " event:%d",
+               VIF_PR_ARG, __entry->rssi_event
+       )
+);
+
+TRACE_EVENT(api_scan_completed,
+       TP_PROTO(struct ieee80211_local *local, bool aborted),
+
+       TP_ARGS(local, aborted),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, aborted)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->aborted = aborted;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " aborted:%d",
+               LOCAL_PR_ARG, __entry->aborted
+       )
+);
+
+TRACE_EVENT(api_sta_block_awake,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta, bool block),
+
+       TP_ARGS(local, sta, block),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(bool, block)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->block = block;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " block:%d",
+               LOCAL_PR_ARG, STA_PR_FMT, __entry->block
+       )
+);
+
+/*
+ * Tracing for internal functions
+ * (which may also be called in response to driver calls)
+ */
+
+TRACE_EVENT(wake_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
+
+TRACE_EVENT(stop_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
index bb677a7..2ab106a 100644 (file)
@@ -175,8 +175,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (initiator == WLAN_BACK_INITIATOR)
-               ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
-                                                WLAN_BACK_INITIATOR, 0);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
        else { /* WLAN_BACK_RECIPIENT */
                spin_lock_bh(&sta->lock);
                if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
index 7fdacf9..c9712f3 100644 (file)
@@ -317,6 +317,7 @@ enum ieee80211_sta_flags {
        IEEE80211_STA_MFP_ENABLED       = BIT(6),
        IEEE80211_STA_UAPSD_ENABLED     = BIT(7),
        IEEE80211_STA_NULLFUNC_ACKED    = BIT(8),
+       IEEE80211_STA_RESET_SIGNAL_AVE  = BIT(9),
 };
 
 struct ieee80211_if_managed {
@@ -359,6 +360,24 @@ struct ieee80211_if_managed {
        int wmm_last_param_set;
 
        u8 use_4addr;
+
+       /* Signal strength from the last Beacon frame in the current BSS. */
+       int last_beacon_signal;
+
+       /*
+        * Weighted average of the signal strength from Beacon frames in the
+        * current BSS. This is in units of 1/16 of the signal unit to maintain
+        * accuracy and to speed up calculations, i.e., the value need to be
+        * divided by 16 to get the actual value.
+        */
+       int ave_beacon_signal;
+
+       /*
+        * Last Beacon frame signal strength average (ave_beacon_signal / 16)
+        * that triggered a cqm event. 0 indicates that no event has been
+        * generated for the current association.
+        */
+       int last_cqm_event_signal;
 };
 
 enum ieee80211_ibss_request {
@@ -1078,8 +1097,6 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_smps_mode smps, const u8 *da,
                               const u8 *bssid);
 
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
-                               u16 tid, u16 initiator, u16 reason);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason);
 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
index 50c1b1a..011ee85 100644 (file)
@@ -309,6 +309,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
+       trace_api_restart_hw(local);
+
        /* use this reason, __ieee80211_resume will unblock it */
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
index 859ee5f..7e93524 100644 (file)
@@ -601,10 +601,10 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
                                          struct ieee80211_rx_status *rx_status)
 {
        switch (mgmt->u.action.category) {
-       case MESH_PLINK_CATEGORY:
+       case WLAN_CATEGORY_MESH_PLINK:
                mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
                break;
-       case MESH_PATH_SEL_CATEGORY:
+       case WLAN_CATEGORY_MESH_PATH_SEL:
                mesh_rx_path_sel_frame(sdata, mgmt, len);
                break;
        }
index 85562c5..c88087f 100644 (file)
@@ -209,8 +209,6 @@ struct mesh_rmc {
 #define MESH_MAX_MPATHS                1024
 
 /* Pending ANA approval */
-#define MESH_PLINK_CATEGORY    30
-#define MESH_PATH_SEL_CATEGORY 32
 #define MESH_PATH_SEL_ACTION   0
 
 /* PERR reason codes */
index fefc45c..d89ed7f 100644 (file)
@@ -132,7 +132,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID == SA */
        memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-       mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+       mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
 
        switch (action) {
@@ -225,7 +225,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
        memcpy(mgmt->da, ra, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
-       mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+       mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
        ie_len = 15;
        pos = skb_put(skb, 2 + ie_len);
index 7b7080e..3cd5f7b 100644 (file)
@@ -172,7 +172,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
-       mgmt->u.action.category = MESH_PLINK_CATEGORY;
+       mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK;
        mgmt->u.action.u.plink_action.action_code = action;
 
        if (action == PLINK_CLOSE)
index 71ff42a..35d8502 100644 (file)
  */
 #define IEEE80211_PROBE_WAIT           (HZ / 2)
 
+/*
+ * Weight given to the latest Beacon frame when calculating average signal
+ * strength for Beacon frames received in the current BSS. This must be
+ * between 1 and 15.
+ */
+#define IEEE80211_SIGNAL_AVE_WEIGHT    3
+
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
@@ -204,7 +211,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                                           const u8 *bssid, u16 stype, u16 reason,
-                                          void *cookie)
+                                          void *cookie, bool send_frame)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -241,7 +248,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                        cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
        if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-       ieee80211_tx_skb(sdata, skb);
+
+       if (send_frame)
+               ieee80211_tx_skb(sdata, skb);
+       else
+               kfree_skb(skb);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -590,6 +601,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        int count;
        u8 *pos, uapsd_queues = 0;
 
+       if (!local->ops->conf_tx)
+               return;
+
        if (local->hw.queues < 4)
                return;
 
@@ -664,11 +678,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                       params.aifs, params.cw_min, params.cw_max, params.txop,
                       params.uapsd);
 #endif
-               if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
+               if (drv_conf_tx(local, queue, &params))
                        printk(KERN_DEBUG "%s: failed to set TX queue "
                               "parameters for queue %d\n",
                               wiphy_name(local->hw.wiphy), queue);
        }
+
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
 }
 
 static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -729,6 +747,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        sdata->u.mgd.associated = cbss;
        memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
 
+       sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
+
        /* just to be sure */
        sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                                IEEE80211_STA_BEACON_POLL);
@@ -770,7 +790,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        netif_carrier_on(sdata->dev);
 }
 
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+                                  bool remove_sta)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -843,7 +864,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
        changed |= BSS_CHANGED_BSSID;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       sta_info_destroy_addr(sdata, bssid);
+       if (remove_sta)
+               sta_info_destroy_addr(sdata, bssid);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -956,7 +978,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
 
        printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(local);
        mutex_unlock(&ifmgd->mtx);
        /*
@@ -966,7 +988,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
        ieee80211_send_deauth_disassoc(sdata, bssid,
                                       IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                      NULL);
+                                      NULL, true);
 }
 
 void ieee80211_beacon_connection_loss_work(struct work_struct *work)
@@ -986,6 +1008,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_beacon_loss(sdata);
+
        WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -996,6 +1020,8 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_connection_loss(sdata);
+
        WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -1022,7 +1048,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
                        sdata->name, bssid, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
 
        return RX_MGMT_CFG80211_DEAUTH;
@@ -1052,7 +1078,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
                        sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
        return RX_MGMT_CFG80211_DISASSOC;
 }
@@ -1344,6 +1370,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
@@ -1379,6 +1406,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
+       /* Track average RSSI from the Beacon frames of the current AP */
+       ifmgd->last_beacon_signal = rx_status->signal;
+       if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
+               ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
+               ifmgd->ave_beacon_signal = rx_status->signal;
+               ifmgd->last_cqm_event_signal = 0;
+       } else {
+               ifmgd->ave_beacon_signal =
+                       (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
+                        (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
+                        ifmgd->ave_beacon_signal) / 16;
+       }
+       if (bss_conf->cqm_rssi_thold &&
+           !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               int sig = ifmgd->ave_beacon_signal / 16;
+               int last_event = ifmgd->last_cqm_event_signal;
+               int thold = bss_conf->cqm_rssi_thold;
+               int hyst = bss_conf->cqm_rssi_hyst;
+               if (sig < thold &&
+                   (last_event == 0 || sig < last_event - hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+                               GFP_KERNEL);
+               } else if (sig > thold &&
+                          (last_event == 0 || sig > last_event + hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+                               GFP_KERNEL);
+               }
+       }
+
        if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
@@ -1664,7 +1726,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        printk(KERN_DEBUG "No probe response from AP %pM"
                                " after %dms, disconnecting.\n",
                                bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
-                       ieee80211_set_disassoc(sdata);
+                       ieee80211_set_disassoc(sdata, true);
                        ieee80211_recalc_idle(local);
                        mutex_unlock(&ifmgd->mtx);
                        /*
@@ -1674,7 +1736,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        ieee80211_send_deauth_disassoc(sdata, bssid,
                                        IEEE80211_STYPE_DEAUTH,
                                        WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                       NULL);
+                                       NULL, true);
                        mutex_lock(&ifmgd->mtx);
                }
        }
@@ -1858,6 +1920,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_work *wk;
        u16 auth_alg;
 
+       if (req->local_state_change)
+               return 0; /* no need to update mac80211 state */
+
        switch (req->auth_type) {
        case NL80211_AUTHTYPE_OPEN_SYSTEM:
                auth_alg = WLAN_AUTH_OPEN;
@@ -1966,7 +2031,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
 
                /* Trying to reassociate - clear previous association state */
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
        }
        mutex_unlock(&ifmgd->mtx);
 
@@ -2070,7 +2135,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->associated == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
                mutex_unlock(&ifmgd->mtx);
        } else {
                bool not_auth_yet = false;
@@ -2113,9 +2178,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
               sdata->name, bssid, req->reason_code);
 
-       ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH, req->reason_code,
-                       cookie);
+       ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
+                                      req->reason_code, cookie,
+                                      !req->local_state_change);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2127,6 +2192,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                           void *cookie)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 bssid[ETH_ALEN];
 
        mutex_lock(&ifmgd->mtx);
 
@@ -2144,13 +2210,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
               sdata->name, req->bss->bssid, req->reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       memcpy(bssid, req->bss->bssid, ETH_ALEN);
+       ieee80211_set_disassoc(sdata, false);
 
        mutex_unlock(&ifmgd->mtx);
 
        ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
                        IEEE80211_STYPE_DISASSOC, req->reason_code,
-                       cookie);
+                       cookie, !req->local_state_change);
+       sta_info_destroy_addr(sdata, bssid);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2198,6 +2266,8 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
+       trace_api_cqm_rssi_notify(sdata, rssi_event);
+
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
index 0e64484..75202b2 100644 (file)
@@ -46,7 +46,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                list_for_each_entry_rcu(sta, &local->sta_list, list) {
-                       set_sta_flags(sta, WLAN_STA_SUSPEND);
+                       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
                        ieee80211_sta_tear_down_BA_sessions(sta);
                }
        }
index e0c944f..72efbd8 100644 (file)
@@ -39,7 +39,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
 {
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
-                       skb_trim(skb, skb->len - FCS_LEN);
+                       __pskb_trim(skb, skb->len - FCS_LEN);
                else {
                        /* driver bug */
                        WARN_ON(1);
@@ -228,6 +228,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
+       /* make sure hdr->frame_control is on the linear part */
+       if (!pskb_may_pull(origskb, 2)) {
+               dev_kfree_skb(origskb);
+               return NULL;
+       }
+
        if (!local->monitors) {
                if (should_drop_frame(origskb, present_fcs_len)) {
                        dev_kfree_skb(origskb);
@@ -485,7 +491,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        mgmt = (struct ieee80211_mgmt *)hdr;
-                       if (mgmt->u.action.category != MESH_PLINK_CATEGORY)
+                       if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -715,14 +721,16 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
 
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
-               goto dont_reorder;
+       spin_lock(&sta->lock);
+
+       if (!sta->ampdu_mlme.tid_active_rx[tid])
+               goto dont_reorder_unlock;
 
        tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
 
        /* qos null data frames are excluded */
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-               goto dont_reorder;
+               goto dont_reorder_unlock;
 
        /* new, potentially un-ordered, ampdu frame - process it */
 
@@ -734,15 +742,20 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        /* if this mpdu is fragmented - terminate rx aggregation session */
        sc = le16_to_cpu(hdr->seq_ctrl);
        if (sc & IEEE80211_SCTL_FRAG) {
-               ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+               spin_unlock(&sta->lock);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+                                              WLAN_REASON_QSTA_REQUIRE_SETUP);
                dev_kfree_skb(skb);
                return;
        }
 
-       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
+       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) {
+               spin_unlock(&sta->lock);
                return;
+       }
 
+ dont_reorder_unlock:
+       spin_unlock(&sta->lock);
  dont_reorder:
        __skb_queue_tail(frames, skb);
 }
@@ -889,6 +902,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                        rx->key = key;
                return RX_CONTINUE;
        } else {
+               u8 keyid;
                /*
                 * The device doesn't give us the IV so we won't be
                 * able to look up the key. That's ok though, we
@@ -911,7 +925,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * no need to call ieee80211_wep_get_keyidx,
                 * it verifies a bunch of things we've done already
                 */
-               keyidx = rx->skb->data[hdrlen + 3] >> 6;
+               skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
+               keyidx = keyid >> 6;
 
                rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
 
@@ -932,6 +947,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
        }
 
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
+
        /* Check for weak IVs if possible */
        if (rx->sta && rx->key->conf.alg == ALG_WEP &&
            ieee80211_is_data(hdr->frame_control) &&
@@ -1232,6 +1252,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        }
        I802_DEBUG_INC(rx->local->rx_handlers_fragments);
 
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
        seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
        if (frag == 0) {
@@ -1397,21 +1420,24 @@ static int
 ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
        __le16 fc = hdr->frame_control;
-       int res;
 
-       res = ieee80211_drop_unencrypted(rx, fc);
-       if (unlikely(res))
-               return res;
+       /*
+        * Pass through unencrypted frames if the hardware has
+        * decrypted them already.
+        */
+       if (status->flag & RX_FLAG_DECRYPTED)
+               return 0;
 
        if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
-               if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
+               if (unlikely(!ieee80211_has_protected(fc) &&
+                            ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
                             rx->key))
                        return -EACCES;
                /* BIP does not use Protected field, so need to check MMIE */
                if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
-                            ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
-                            rx->key))
+                            ieee80211_get_mmie_keyidx(rx->skb) < 0))
                        return -EACCES;
                /*
                 * When using MFP, Action frames are not allowed prior to
@@ -1589,6 +1615,9 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
+       if (skb_linearize(skb))
+               return RX_DROP_UNUSABLE;
+
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
                                 rx->local->hw.extra_tx_headroom);
@@ -1787,10 +1816,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
        if (ieee80211_is_back_req(bar->frame_control)) {
                if (!rx->sta)
                        return RX_DROP_MONITOR;
+               spin_lock(&rx->sta->lock);
                tid = le16_to_cpu(bar->control) >> 12;
-               if (rx->sta->ampdu_mlme.tid_state_rx[tid]
-                                       != HT_AGG_STATE_OPERATIONAL)
+               if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
+                       spin_unlock(&rx->sta->lock);
                        return RX_DROP_MONITOR;
+               }
                tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
                start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
@@ -1804,6 +1835,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
                                                 frames);
                kfree_skb(skb);
+               spin_unlock(&rx->sta->lock);
                return RX_QUEUED;
        }
 
@@ -1965,8 +1997,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        goto handled;
                }
                break;
-       case MESH_PLINK_CATEGORY:
-       case MESH_PATH_SEL_CATEGORY:
+       case WLAN_CATEGORY_MESH_PLINK:
+       case WLAN_CATEGORY_MESH_PATH_SEL:
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
                break;
@@ -2363,29 +2395,42 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr;
+       __le16 fc;
        struct ieee80211_rx_data rx;
        int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        struct sta_info *sta, *tmp;
        bool found_sta = false;
+       int err = 0;
 
-       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
        rx.local = local;
 
-       if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
+       if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
                local->dot11ReceivedFragmentCount++;
 
        if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
                     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
                rx.flags |= IEEE80211_RX_IN_SCAN;
 
+       if (ieee80211_is_mgmt(fc))
+               err = skb_linearize(skb);
+       else
+               err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
+
+       if (err) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *)skb->data;
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       if (ieee80211_is_data(hdr->frame_control)) {
+       if (ieee80211_is_data(fc)) {
                for_each_sta_info(local, hdr->addr2, sta, tmp) {
                        rx.sta = sta;
                        found_sta = true;
index 1ce4ce8..e1a3def 100644 (file)
@@ -248,6 +248,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        struct ieee80211_local *local = hw_to_local(hw);
        bool was_hw_scan;
 
+       trace_api_scan_completed(local, aborted);
+
        mutex_lock(&local->scan_mtx);
 
        /*
index fb12cec..ff0eb94 100644 (file)
@@ -250,9 +250,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                 * enable session_timer's data differentiation. refer to
                 * sta_rx_agg_session_timer_expired for useage */
                sta->timer_to_tid[i] = i;
-               /* rx */
-               sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
-               sta->ampdu_mlme.tid_rx[i] = NULL;
                /* tx */
                sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
                sta->ampdu_mlme.tid_tx[i] = NULL;
@@ -619,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        struct ieee80211_sub_if_data *sdata;
        struct sk_buff *skb;
        unsigned long flags;
-       int ret, i;
+       int ret;
 
        might_sleep();
 
@@ -629,6 +626,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        local = sta->local;
        sdata = sta->sdata;
 
+       /*
+        * Before removing the station from the driver and
+        * rate control, it might still start new aggregation
+        * sessions -- block that to make sure the tear-down
+        * will be sufficient.
+        */
+       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+       ieee80211_sta_tear_down_BA_sessions(sta);
+
        spin_lock_irqsave(&local->sta_lock, flags);
        ret = sta_info_hash_del(local, sta);
        /* this might still be the pending list ... which is fine */
@@ -645,9 +651,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                 * may mean it is removed from hardware which requires that
                 * the key->sta pointer is still valid, so flush the key todo
                 * list here.
-                *
-                * ieee80211_key_todo() will synchronize_rcu() so after this
-                * nothing can reference this sta struct any more.
                 */
                ieee80211_key_todo();
 
@@ -679,11 +682,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                sdata = sta->sdata;
        }
 
+       /*
+        * At this point, after we wait for an RCU grace period,
+        * neither mac80211 nor the driver can reference this
+        * sta struct any more except by still existing timers
+        * associated with this station that we clean up below.
+        */
+       synchronize_rcu();
+
 #ifdef CONFIG_MAC80211_MESH
-       if (ieee80211_vif_is_mesh(&sdata->vif)) {
+       if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_accept_plinks_update(sdata);
-               del_timer(&sta->plink_timer);
-       }
 #endif
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -710,50 +719,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
                dev_kfree_skb_any(skb);
 
-       for (i = 0; i <  STA_TID_NUM; i++) {
-               struct tid_ampdu_rx *tid_rx;
-               struct tid_ampdu_tx *tid_tx;
-
-               spin_lock_bh(&sta->lock);
-               tid_rx = sta->ampdu_mlme.tid_rx[i];
-               /* Make sure timer won't free the tid_rx struct, see below */
-               if (tid_rx)
-                       tid_rx->shutdown = true;
-
-               spin_unlock_bh(&sta->lock);
-
-               /*
-                * Outside spinlock - shutdown is true now so that the timer
-                * won't free tid_rx, we have to do that now. Can't let the
-                * timer do it because we have to sync the timer outside the
-                * lock that it takes itself.
-                */
-               if (tid_rx) {
-                       del_timer_sync(&tid_rx->session_timer);
-                       kfree(tid_rx);
-               }
-
-               /*
-                * No need to do such complications for TX agg sessions, the
-                * path leading to freeing the tid_tx struct goes via a call
-                * from the driver, and thus needs to look up the sta struct
-                * again, which cannot be found when we get here. Hence, we
-                * just need to delete the timer and free the aggregation
-                * info; we won't be telling the peer about it then but that
-                * doesn't matter if we're not talking to it again anyway.
-                */
-               tid_tx = sta->ampdu_mlme.tid_tx[i];
-               if (tid_tx) {
-                       del_timer_sync(&tid_tx->addba_resp_timer);
-                       /*
-                        * STA removed while aggregation session being
-                        * started? Bit odd, but purge frames anyway.
-                        */
-                       skb_queue_purge(&tid_tx->pending);
-                       kfree(tid_tx);
-               }
-       }
-
        __sta_info_free(local, sta);
 
        return 0;
@@ -992,6 +957,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 {
        struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
+       trace_api_sta_block_awake(sta->local, pubsta, block);
+
        if (block)
                set_sta_flags(sta, WLAN_STA_PS_DRIVER);
        else
index 2b63590..48a5e80 100644 (file)
@@ -35,8 +35,8 @@
  *     IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
  *     frame to this station is transmitted.
  * @WLAN_STA_MFP: Management frame protection is used with this STA.
- * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle.
- *     Used to deny ADDBA requests (both TX and RX).
+ * @WLAN_STA_BLOCK_BA: Used to deny ADDBA requests (both TX and RX)
+ *     during suspend/resume and station removal.
  * @WLAN_STA_PS_DRIVER: driver requires keeping this station in
  *     power-save mode logically to flush frames that might still
  *     be in the queues
@@ -57,7 +57,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_WDS            = 1<<7,
        WLAN_STA_CLEAR_PS_FILT  = 1<<9,
        WLAN_STA_MFP            = 1<<10,
-       WLAN_STA_SUSPEND        = 1<<11,
+       WLAN_STA_BLOCK_BA       = 1<<11,
        WLAN_STA_PS_DRIVER      = 1<<12,
        WLAN_STA_PSPOLL         = 1<<13,
        WLAN_STA_DISASSOC       = 1<<14,
@@ -106,7 +106,6 @@ struct tid_ampdu_tx {
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
- * @shutdown: this session is being shut down due to STA removal
  */
 struct tid_ampdu_rx {
        struct sk_buff **reorder_buf;
@@ -118,7 +117,6 @@ struct tid_ampdu_rx {
        u16 buf_size;
        u16 timeout;
        u8 dialog_token;
-       bool shutdown;
 };
 
 /**
@@ -156,7 +154,7 @@ enum plink_state {
  */
 struct sta_ampdu_mlme {
        /* rx */
-       u8 tid_state_rx[STA_TID_NUM];
+       bool tid_active_rx[STA_TID_NUM];
        struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
        /* tx */
        u8 tid_state_tx[STA_TID_NUM];
index db25fa9..2cb7726 100644 (file)
@@ -513,6 +513,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
+                is_multicast_ether_addr(hdr->addr1) &&
+                ieee80211_is_robust_mgmt_frame(hdr) &&
                 (key = rcu_dereference(tx->sdata->default_mgmt_key)))
                tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
@@ -1142,13 +1144,12 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
-               unsigned long flags;
                struct tid_ampdu_tx *tid_tx;
 
                qc = ieee80211_get_qos_ctl(hdr);
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
 
-               spin_lock_irqsave(&tx->sta->lock, flags);
+               spin_lock(&tx->sta->lock);
                /*
                 * XXX: This spinlock could be fairly expensive, but see the
                 *      comment in agg-tx.c:ieee80211_agg_tx_operational().
@@ -1173,7 +1174,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        __skb_queue_tail(&tid_tx->pending, skb);
                }
-               spin_unlock_irqrestore(&tx->sta->lock, flags);
+               spin_unlock(&tx->sta->lock);
 
                if (unlikely(queued))
                        return TX_QUEUED;
index 53af570..2b75b4f 100644 (file)
@@ -270,6 +270,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
 
+       trace_wake_queue(local, queue, reason);
+
        if (WARN_ON(queue >= hw->queues))
                return;
 
@@ -312,6 +314,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
 
+       trace_stop_queue(local, queue, reason);
+
        if (WARN_ON(queue >= hw->queues))
                return;
 
@@ -796,6 +800,11 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                drv_conf_tx(local, queue, &qparam);
        }
+
+       /* after reinitialize QoS TX queues setting to default,
+        * disable QoS at all */
+       local->hw.conf.flags &= ~IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
 }
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
@@ -1135,7 +1144,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                list_for_each_entry_rcu(sta, &local->sta_list, list) {
-                       clear_sta_flags(sta, WLAN_STA_SUSPEND);
+                       clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
                }
        }
 
index 15e1ba9..bdb1d05 100644 (file)
@@ -920,11 +920,16 @@ static void ieee80211_work_work(struct work_struct *work)
                run_again(local, jiffies + HZ/2);
        }
 
-       if (list_empty(&local->work_list) && local->scan_req)
+       mutex_lock(&local->scan_mtx);
+
+       if (list_empty(&local->work_list) && local->scan_req &&
+           !local->scanning)
                ieee80211_queue_delayed_work(&local->hw,
                                             &local->scan_work,
                                             round_jiffies_relative(0));
 
+       mutex_unlock(&local->scan_mtx);
+
        mutex_unlock(&local->work_mtx);
 
        ieee80211_recalc_idle(local);
index d52da91..b2234b4 100644 (file)
@@ -293,13 +293,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx);
+                        const u8 *key, int key_len, int key_idx,
+                        bool local_state_change);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx);
+                      const u8 *key, int key_len, int key_idx,
+                      bool local_state_change);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
@@ -315,13 +317,16 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                        struct cfg80211_crypto_settings *crypt);
 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason);
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change);
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                         struct net_device *dev, const u8 *bssid,
-                        const u8 *ie, int ie_len, u16 reason);
+                        const u8 *ie, int ie_len, u16 reason,
+                        bool local_state_change);
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason);
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change);
 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
index 4bb734a..48ead6f 100644 (file)
@@ -378,7 +378,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx)
+                        const u8 *key, int key_len, int key_idx,
+                        bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
@@ -408,6 +409,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
 
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        req.auth_type = auth_type;
@@ -434,12 +436,18 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                goto out;
        }
 
-       wdev->authtry_bsses[slot] = bss;
+       if (local_state_change)
+               wdev->auth_bsses[slot] = bss;
+       else
+               wdev->authtry_bsses[slot] = bss;
        cfg80211_hold_bss(bss);
 
        err = rdev->ops->auth(&rdev->wiphy, dev, &req);
        if (err) {
-               wdev->authtry_bsses[slot] = NULL;
+               if (local_state_change)
+                       wdev->auth_bsses[slot] = NULL;
+               else
+                       wdev->authtry_bsses[slot] = NULL;
                cfg80211_unhold_bss(bss);
        }
 
@@ -454,14 +462,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx)
+                      const u8 *key, int key_len, int key_idx,
+                      bool local_state_change)
 {
        int err;
 
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                   ssid, ssid_len, ie, ie_len,
-                                  key, key_len, key_idx);
+                                  key, key_len, key_idx, local_state_change);
        wdev_unlock(dev->ieee80211_ptr);
 
        return err;
@@ -555,7 +564,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 
 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason)
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_deauth_request req;
@@ -565,6 +575,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        if (wdev->current_bss &&
@@ -591,13 +602,15 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                         struct net_device *dev, const u8 *bssid,
-                        const u8 *ie, int ie_len, u16 reason)
+                        const u8 *ie, int ie_len, u16 reason,
+                        bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        wdev_lock(wdev);
-       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
+       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
+                                    local_state_change);
        wdev_unlock(wdev);
 
        return err;
@@ -605,7 +618,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                                    struct net_device *dev, const u8 *bssid,
-                                   const u8 *ie, int ie_len, u16 reason)
+                                   const u8 *ie, int ie_len, u16 reason,
+                                   bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_disassoc_request req;
@@ -620,6 +634,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
@@ -632,13 +647,15 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason)
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        wdev_lock(wdev);
-       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
+       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
+                                      local_state_change);
        wdev_unlock(wdev);
 
        return err;
index 596bf18..356a84a 100644 (file)
@@ -151,6 +151,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
        [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
        [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
+       [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
 };
 
 /* policy for the attributes */
@@ -2097,7 +2098,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
                goto out_rtnl;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
                err = -EINVAL;
                goto out;
        }
@@ -3393,6 +3395,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        int err, ssid_len, ie_len = 0;
        enum nl80211_auth_type auth_type;
        struct key_parse key;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3471,9 +3474,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
        err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                 ssid, ssid_len, ie, ie_len,
-                                key.p.key, key.p.key_len, key.idx);
+                                key.p.key, key.p.key_len, key.idx,
+                                local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -3650,6 +3656,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
        const u8 *ie = NULL, *bssid;
        int err, ie_len = 0;
        u16 reason_code;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3695,7 +3702,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code);
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
+       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
+                                  local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -3712,6 +3722,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
        const u8 *ie = NULL, *bssid;
        int err, ie_len = 0;
        u16 reason_code;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3757,7 +3768,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code);
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
+       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
+                                    local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
index 422da20..8f0d97d 100644 (file)
@@ -2356,10 +2356,10 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                                        rdev->country_ie_alpha2[1]);
                        } else
                                printk(KERN_INFO "cfg80211: Current regulatory "
-                                       "domain intersected: \n");
+                                       "domain intersected:\n");
                } else
-                               printk(KERN_INFO "cfg80211: Current regulatory "
-                                       "domain intersected: \n");
+                       printk(KERN_INFO "cfg80211: Current regulatory "
+                               "domain intersected:\n");
        } else if (is_world_regdom(rd->alpha2))
                printk(KERN_INFO "cfg80211: World regulatory "
                        "domain updated:\n");
index f4dfd5f..c273577 100644 (file)
@@ -171,7 +171,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            params->ssid, params->ssid_len,
                                            NULL, 0,
                                            params->key, params->key_len,
-                                           params->key_idx);
+                                           params->key_idx, false);
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -186,12 +186,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                if (err)
                        __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                               NULL, 0,
-                                              WLAN_REASON_DEAUTH_LEAVING);
+                                              WLAN_REASON_DEAUTH_LEAVING,
+                                              false);
                return err;
        case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
                __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                       NULL, 0,
-                                      WLAN_REASON_DEAUTH_LEAVING);
+                                      WLAN_REASON_DEAUTH_LEAVING, false);
                /* return an error so that we call __cfg80211_connect_result() */
                return -EINVAL;
        default:
@@ -676,7 +677,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                                continue;
                        bssid = wdev->auth_bsses[i]->pub.bssid;
                        ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
-                                               WLAN_REASON_DEAUTH_LEAVING);
+                                               WLAN_REASON_DEAUTH_LEAVING,
+                                               false);
                        WARN(ret, "deauth failed: %d\n", ret);
                }
        }
@@ -935,7 +937,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                /* wdev->conn->params.bssid must be set if > SCANNING */
                err = __cfg80211_mlme_deauth(rdev, dev,
                                             wdev->conn->params.bssid,
-                                            NULL, 0, reason);
+                                            NULL, 0, reason, false);
                if (err)
                        return err;
        } else {
@@ -991,7 +993,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
 
        memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
        if (__cfg80211_mlme_deauth(rdev, dev, bssid,
-                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
+                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
+                                  false)) {
                /* whatever -- assume gone anyway */
                cfg80211_unhold_bss(wdev->auth_bsses[idx]);
                cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
index d3574a4..3416373 100644 (file)
@@ -331,11 +331,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
                        struct ieee80211s_hdr *meshdr =
                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                       /* make sure meshdr->flags is on the linear part */
+                       if (!pskb_may_pull(skb, hdrlen + 1))
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
-                               memcpy(dst, meshdr->eaddr1, ETH_ALEN);
-                               memcpy(src, meshdr->eaddr2, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr1),
+                                       dst, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr2),
+                                       src, ETH_ALEN);
                        }
+                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
                }
                break;
        case cpu_to_le16(IEEE80211_FCTL_FROMDS):
@@ -347,9 +354,14 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
                        struct ieee80211s_hdr *meshdr =
                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                       /* make sure meshdr->flags is on the linear part */
+                       if (!pskb_may_pull(skb, hdrlen + 1))
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A4)
-                               memcpy(src, meshdr->eaddr1, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr1),
+                                       src, ETH_ALEN);
+                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
                }
                break;
        case cpu_to_le16(0):
@@ -358,7 +370,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                break;
        }
 
-       if (unlikely(skb->len - hdrlen < 8))
+       if (!pskb_may_pull(skb, hdrlen + 8))
                return -1;
 
        payload = skb->data + hdrlen;