Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Thu, 4 Feb 2010 16:58:14 +0000 (08:58 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Feb 2010 16:58:14 +0000 (08:58 -0800)
125 files changed:
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ps3_defconfig
drivers/net/Kconfig
drivers/net/ps3_gelic_wireless.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/led.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/debug.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_common.h
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-fh.h
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-led.c
drivers/net/wireless/iwlwifi/iwl-3945-led.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
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-hw.h
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-led.c
drivers/net/wireless/iwlwifi/iwl-agn-led.h
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-calib.h
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-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-helpers.h
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-led.h
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-power.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-spectrum.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-spectrum.h
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/assoc.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54pci.h
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_main.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/rate.h
net/mac80211/rc80211_pid_algo.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/status.c
net/mac80211/tkip.c
net/mac80211/tx.c
net/mac80211/wep.c
net/mac80211/work.c
net/mac80211/wpa.c
net/wireless/core.c
net/wireless/core.h
net/wireless/lib80211_crypt_ccmp.c
net/wireless/lib80211_crypt_tkip.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/reg.h
net/wireless/scan.c
net/wireless/sme.c
net/wireless/sysfs.c
net/wireless/util.c
net/wireless/wext-compat.c

index 7b3804a6e363e10806b0a5fac0c72bc77c77cefc..80e80caed2da9ba6ec0d65b8f92f4f710234e3ab 100644 (file)
@@ -1000,7 +1000,6 @@ CONFIG_TIGON3=y
 CONFIG_SPIDER_NET=m
 CONFIG_GELIC_NET=m
 CONFIG_GELIC_WIRELESS=y
-# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 # CONFIG_ATL1E is not set
index 7de127e4ceeffbf36f4ae9e718d9b9896c733198..32f7058bb1738d87f42b4108e6312e247c9143bb 100644 (file)
@@ -593,7 +593,6 @@ CONFIG_MII=m
 CONFIG_NETDEV_1000=y
 CONFIG_GELIC_NET=y
 CONFIG_GELIC_WIRELESS=y
-# CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE is not set
 # CONFIG_NETDEV_10000 is not set
 
 #
index 411e207031109b36a40abcf5ad77ad41d21b13af..ef662e15c3d3b84aafa7b927fc0cf49a78dd1b05 100644 (file)
@@ -2368,20 +2368,6 @@ config GELIC_WIRELESS
          the driver automatically distinguishes the models, you can
          safely enable this option even if you have a wireless-less model.
 
-config GELIC_WIRELESS_OLD_PSK_INTERFACE
-       bool "PS3 Wireless private PSK interface (OBSOLETE)"
-       depends on GELIC_WIRELESS
-       select WEXT_PRIV
-       help
-          This option retains the obsolete private interface to pass
-          the PSK from user space programs to the driver.  The PSK
-          stands for 'Pre Shared Key' and is used for WPA[2]-PSK
-          (WPA-Personal) environment.
-          If WPA[2]-PSK is used and you need to use old programs that
-          support only this old interface, say Y.  Otherwise N.
-
-          If unsure, say N.
-
 config FSL_PQ_MDIO
        tristate "Freescale PQ MDIO"
        depends on FSL_SOC
index 227b141c4fbd3549bd0664bdb5288defa0657473..2663b2fdc0bb0170b6054188e02defdfb74241f1 100644 (file)
@@ -1389,113 +1389,6 @@ static int gelic_wl_get_mode(struct net_device *netdev,
        return 0;
 }
 
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
-/* SIOCIWFIRSTPRIV */
-static int hex2bin(u8 *str, u8 *bin, unsigned int len)
-{
-       unsigned int i;
-       static unsigned char *hex = "0123456789ABCDEF";
-       unsigned char *p, *q;
-       u8 tmp;
-
-       if (len != WPA_PSK_LEN * 2)
-               return -EINVAL;
-
-       for (i = 0; i < WPA_PSK_LEN * 2; i += 2) {
-               p = strchr(hex, toupper(str[i]));
-               q = strchr(hex, toupper(str[i + 1]));
-               if (!p || !q) {
-                       pr_info("%s: unconvertible PSK digit=%d\n",
-                               __func__, i);
-                       return -EINVAL;
-               }
-               tmp = ((p - hex) << 4) + (q - hex);
-               *bin++ = tmp;
-       }
-       return 0;
-};
-
-static int gelic_wl_priv_set_psk(struct net_device *net_dev,
-                                struct iw_request_info *info,
-                                union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
-       unsigned int len;
-       unsigned long irqflag;
-       int ret = 0;
-
-       pr_debug("%s:<- len=%d\n", __func__, data->data.length);
-       len = data->data.length - 1;
-       if (len <= 2)
-               return -EINVAL;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       if (extra[0] == '"' && extra[len - 1] == '"') {
-               pr_debug("%s: passphrase mode\n", __func__);
-               /* pass phrase */
-               if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) {
-                       pr_info("%s: passphrase too long\n", __func__);
-                       ret = -E2BIG;
-                       goto out;
-               }
-               memset(wl->psk, 0, sizeof(wl->psk));
-               wl->psk_len = len - 2;
-               memcpy(wl->psk, &(extra[1]), wl->psk_len);
-               wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE;
-       } else {
-               ret = hex2bin(extra, wl->psk, len);
-               if (ret)
-                       goto out;
-               wl->psk_len = WPA_PSK_LEN;
-               wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
-       }
-       set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
-out:
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s:->\n", __func__);
-       return ret;
-}
-
-static int gelic_wl_priv_get_psk(struct net_device *net_dev,
-                                struct iw_request_info *info,
-                                union iwreq_data *data, char *extra)
-{
-       struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev));
-       char *p;
-       unsigned long irqflag;
-       unsigned int i;
-
-       pr_debug("%s:<-\n", __func__);
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       spin_lock_irqsave(&wl->lock, irqflag);
-       p = extra;
-       if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) {
-               if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) {
-                       for (i = 0; i < wl->psk_len; i++) {
-                               sprintf(p, "%02xu", wl->psk[i]);
-                               p += 2;
-                       }
-                       *p = '\0';
-                       data->data.length = wl->psk_len * 2;
-               } else {
-                       *p++ = '"';
-                       memcpy(p, wl->psk, wl->psk_len);
-                       p += wl->psk_len;
-                       *p++ = '"';
-                       *p = '\0';
-                       data->data.length = wl->psk_len + 2;
-               }
-       } else
-               /* no psk set */
-               data->data.length = 0;
-       spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s:-> %d\n", __func__, data->data.length);
-       return 0;
-}
-#endif
-
 /* SIOCGIWNICKN */
 static int gelic_wl_get_nick(struct net_device *net_dev,
                                  struct iw_request_info *info,
@@ -1571,8 +1464,10 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
        init_completion(&wl->scan_done);
        /*
         * If we have already a bss list, don't try to get new
+        * unless we are doing an ESSID scan
         */
-       if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
+       if ((!essid_len && !always_scan)
+           && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) {
                pr_debug("%s: already has the list\n", __func__);
                complete(&wl->scan_done);
                goto out;
@@ -1673,7 +1568,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
                }
        }
 
-       /* put them in the newtork_list */
+       /* put them in the network_list */
        for (i = 0, scan_info_size = 0, scan_info = buf;
             scan_info_size < data_len;
             i++, scan_info_size += be16_to_cpu(scan_info->size),
@@ -2009,7 +1904,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
        /* PSK type */
        wpa->psk_type = cpu_to_be16(wl->psk_type);
 #ifdef DEBUG
-       pr_debug("%s: sec=%s psktype=%s\nn", __func__,
+       pr_debug("%s: sec=%s psktype=%s\n", __func__,
                 wpasecstr(wpa->security),
                 (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
                 "BIN" : "passphrase");
@@ -2019,9 +1914,9 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
         * the debug log because this dumps your precious
         * passphrase/key.
         */
-       pr_debug("%s: psk=%s\n",
+       pr_debug("%s: psk=%s\n", __func__,
                 (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ?
-                (char *)"N/A" : (char *)wpa->psk);
+                "N/A" : wpa->psk);
 #endif
 #endif
        /* issue wpa setup */
@@ -2406,40 +2301,10 @@ static const iw_handler gelic_wl_wext_handler[] =
        IW_IOCTL(SIOCGIWNICKN)          = gelic_wl_get_nick,
 };
 
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
-static struct iw_priv_args gelic_wl_private_args[] =
-{
-       {
-               .cmd = GELIC_WL_PRIV_SET_PSK,
-               .set_args = IW_PRIV_TYPE_CHAR |
-               (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
-               .name = "set_psk"
-       },
-       {
-               .cmd = GELIC_WL_PRIV_GET_PSK,
-               .get_args = IW_PRIV_TYPE_CHAR |
-               (GELIC_WL_EURUS_PSK_MAX_LEN + 2),
-               .name = "get_psk"
-       }
-};
-
-static const iw_handler gelic_wl_private_handler[] =
-{
-       gelic_wl_priv_set_psk,
-       gelic_wl_priv_get_psk,
-};
-#endif
-
 static const struct iw_handler_def gelic_wl_wext_handler_def = {
        .num_standard           = ARRAY_SIZE(gelic_wl_wext_handler),
        .standard               = gelic_wl_wext_handler,
        .get_wireless_stats     = gelic_wl_get_wireless_stats,
-#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
-       .num_private            = ARRAY_SIZE(gelic_wl_private_handler),
-       .num_private_args       = ARRAY_SIZE(gelic_wl_private_args),
-       .private                = gelic_wl_private_handler,
-       .private_args           = gelic_wl_private_args,
-#endif
 };
 
 static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
index 37e4ab737f2ad6913246c30b19839aabd1dae371..ef6b78da370f809490a9ae0b418f1794348be1c9 100644 (file)
@@ -5254,11 +5254,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
        WepKeyRid wkr;
        int rc;
 
-       if (keylen == 0) {
-               airo_print_err(ai->dev->name, "%s: key length to set was zero",
-                              __func__);
-               return -1;
-       }
+       WARN_ON(keylen == 0);
 
        memset(&wkr, 0, sizeof(wkr));
        wkr.len = cpu_to_le16(sizeof(wkr));
@@ -6405,11 +6401,7 @@ static int airo_set_encode(struct net_device *dev,
                if (dwrq->length > MIN_KEY_SIZE)
                        key.len = MAX_KEY_SIZE;
                else
-                       if (dwrq->length > 0)
-                               key.len = MIN_KEY_SIZE;
-                       else
-                               /* Disable the key */
-                               key.len = 0;
+                       key.len = MIN_KEY_SIZE;
                /* Check if the key is not marked as invalid */
                if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
                        /* Cleanup */
@@ -6590,12 +6582,22 @@ static int airo_set_encodeext(struct net_device *dev,
                default:
                        return -EINVAL;
                }
-               /* Send the key to the card */
-               rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
-               if (rc < 0) {
-                       airo_print_err(local->dev->name, "failed to set WEP key"
-                                      " at index %d: %d.", idx, rc);
-                       return rc;
+               if (key.len == 0) {
+                       rc = set_wep_tx_idx(local, idx, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name,
+                                              "failed to set WEP transmit index to %d: %d.",
+                                              idx, rc);
+                               return rc;
+                       }
+               } else {
+                       rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name,
+                                              "failed to set WEP key at index %d: %d.",
+                                              idx, rc);
+                               return rc;
+                       }
                }
        }
 
index 9e05648356feb32971370298b5bb8c9b10b1bcd3..71fc960814f0e26c77aed4278158addd011c6e58 100644 (file)
@@ -74,7 +74,6 @@ struct ath_common;
 
 struct ath_bus_ops {
        void            (*read_cachesize)(struct ath_common *common, int *csz);
-       void            (*cleanup)(struct ath_common *common);
        bool            (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
        void            (*bt_coex_prep)(struct ath_common *common);
 };
index 66bcb506a1123e7f25e82ef7fa7d46a1b48f8aed..ad4d446f02646d6d1714c17b3c28e8620a19938b 100644 (file)
@@ -535,7 +535,7 @@ struct ath5k_txq_info {
        u32     tqi_cbr_period; /* Constant bit rate period */
        u32     tqi_cbr_overflow_limit;
        u32     tqi_burst_time;
-       u32     tqi_ready_time; /* Not used */
+       u32     tqi_ready_time; /* Time queue waits after an event */
 };
 
 /*
index 5577bcc80eac04ed1443e3c221eaadd6edbd5491..edb6c90e376f87b75023f2102fce451dd07c7bc9 100644 (file)
@@ -1516,7 +1516,8 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
 
        ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
        if (ret)
-               return ret;
+               goto err;
+
        if (sc->opmode == NL80211_IFTYPE_AP ||
                sc->opmode == NL80211_IFTYPE_MESH_POINT) {
                /*
@@ -1543,10 +1544,25 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
        if (ret) {
                ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
                        "hardware queue!\n", __func__);
-               return ret;
+               goto err;
        }
+       ret = ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */
+       if (ret)
+               goto err;
 
-       return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */;
+       /* reconfigure cabq with ready time to 80% of beacon_interval */
+       ret = ath5k_hw_get_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi);
+       if (ret)
+               goto err;
+
+       qi.tqi_ready_time = (sc->bintval * 80) / 100;
+       ret = ath5k_hw_set_tx_queueprops(ah, AR5K_TX_QUEUE_ID_CAB, &qi);
+       if (ret)
+               goto err;
+
+       ret = ath5k_hw_reset_tx_queue(ah, AR5K_TX_QUEUE_ID_CAB);
+err:
+       return ret;
 }
 
 static void
index 60f547503d75a2eb7edc3bf4f42495f4a74b10a4..67aa52e9bf9404a581c7084d12f058f21df13bbc 100644 (file)
@@ -77,6 +77,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
        { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137a), ATH_LED(3, 1) },
        /* HP Compaq C700 (nitrousnrg@gmail.com) */
        { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
+       /* LiteOn AR5BXB63 (magooz@salug.it) */
+       { ATH_SDEVICE(PCI_VENDOR_ID_ATHEROS, 0x3067), ATH_LED(3, 0) },
        /* IBM-specific AR5212 (all others) */
        { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
        /* Dell Vostro A860 (shahar@shahar-or.co.il) */
index abe36c0d139c72f4e60dde1d006423b82185570b..9122a8556f45c3e02a6e2e215f16702458f14147 100644 (file)
@@ -408,12 +408,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                        break;
 
                case AR5K_TX_QUEUE_CAB:
+                       /* XXX: use BCN_SENT_GT, if we can figure out how */
                        AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-                               AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
+                               AR5K_QCU_MISC_FRSHED_DBA_GT |
                                AR5K_QCU_MISC_CBREXP_DIS |
                                AR5K_QCU_MISC_CBREXP_BCN_DIS);
 
-                       ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+                       ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
                                (AR5K_TUNE_SW_BEACON_RESP -
                                AR5K_TUNE_DMA_BEACON_RESP) -
                                AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
index 6690923fd78cee4700adc05c647856e29b167d93..a35a7db0fc4cfeae7b47c72dcb73132ec5f30f06 100644 (file)
@@ -1374,8 +1374,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         * Set clocks to 32KHz operation and use an
         * external 32KHz crystal when sleeping if one
         * exists */
-       if (ah->ah_version == AR5K_AR5212)
-                       ath5k_hw_set_sleep_clock(ah, true);
+       if (ah->ah_version == AR5K_AR5212 &&
+           ah->ah_op_mode != NL80211_IFTYPE_AP)
+               ath5k_hw_set_sleep_clock(ah, true);
 
        /*
         * Disable beacons and reset the register
index 9e62a569e816bf59ba7307647149701faf0354c5..ca4994f1315153b4ef2a9aae256846bbb4f6cf91 100644 (file)
@@ -27,12 +27,6 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
        *csz = L1_CACHE_BYTES >> 2;
 }
 
-static void ath_ahb_cleanup(struct ath_common *common)
-{
-       struct ath_softc *sc = (struct ath_softc *)common->priv;
-       iounmap(sc->mem);
-}
-
 static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 {
        struct ath_softc *sc = (struct ath_softc *)common->priv;
@@ -54,8 +48,6 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 
 static struct ath_bus_ops ath_ahb_bus_ops  = {
        .read_cachesize = ath_ahb_read_cachesize,
-       .cleanup = ath_ahb_cleanup,
-
        .eeprom_read = ath_ahb_eeprom_read,
 };
 
@@ -164,12 +156,12 @@ static int ath_ahb_remove(struct platform_device *pdev)
        if (hw) {
                struct ath_wiphy *aphy = hw->priv;
                struct ath_softc *sc = aphy->sc;
-               struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+               void __iomem *mem = sc->mem;
 
                ath9k_deinit_device(sc);
                free_irq(sc->irq, sc);
                ieee80211_free_hw(sc->hw);
-               ath_bus_cleanup(common);
+               iounmap(mem);
                platform_set_drvdata(pdev, NULL);
        }
 
index bf3d4c4bfa522788691aab1c63991aaba9cf310d..0ea340fd071c9fa24f6b7de0275d388a9e2cac40 100644 (file)
@@ -364,6 +364,7 @@ struct ath_btcoex {
        int bt_stomp_type; /* Types of BT stomping */
        u32 btcoex_no_stomp; /* in usec */
        u32 btcoex_period; /* in usec */
+       u32 btscan_no_stomp; /* in usec */
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
 };
 
@@ -429,6 +430,7 @@ void ath_deinit_leds(struct ath_softc *sc);
 #define SC_OP_SCANNING               BIT(10)
 #define SC_OP_TSF_RESET              BIT(11)
 #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
+#define SC_OP_BT_SCAN               BIT(13)
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -478,6 +480,7 @@ struct ath_softc {
        u8 nbcnvifs;
        u16 nvifs;
        bool ps_enabled;
+       bool ps_idle;
        unsigned long ps_usecount;
        enum ath9k_int imask;
 
@@ -535,11 +538,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
        common->bus_ops->read_cachesize(common, csz);
 }
 
-static inline void ath_bus_cleanup(struct ath_common *common)
-{
-       common->bus_ops->cleanup(common);
-}
-
 extern struct ieee80211_ops ath9k_ops;
 extern int modparam_nohwcrypt;
 
index 1ba31a73317c9f3d3e3d32b8406a407c14ea0c47..1ee5a15ccbb1a8c714692e52ddd81542e0b84411 100644 (file)
 
 #define ATH_BTCOEX_DEF_BT_PERIOD  45
 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55
+#define ATH_BTCOEX_BTSCAN_DUTY_CYCLE 90
 #define ATH_BTCOEX_BMISS_THRESH   50
 
 #define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */
 #define ATH_BT_CNT_THRESHOLD          3
+#define ATH_BT_CNT_SCAN_THRESHOLD      15
 
 enum ath_btcoex_scheme {
        ATH_BTCOEX_CFG_NONE,
index 9489b6b25b5fc97ab3bc3d0ba146aeecced088fd..42d2a506845a43ea929b0d8159bb12b44bcb5e17 100644 (file)
@@ -75,17 +75,24 @@ static const struct file_operations fops_debug = {
 
 #endif
 
+#define DMA_BUF_LEN 1024
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
        struct ath_hw *ah = sc->sc_ah;
-       char buf[1024];
+       char *buf;
+       int retval;
        unsigned int len = 0;
        u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
        int i, qcuOffset = 0, dcuOffset = 0;
        u32 *qcuBase = &val[0], *dcuBase = &val[4];
 
+       buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
+       if (!buf)
+               return 0;
+
        ath9k_ps_wakeup(sc);
 
        REG_WRITE_D(ah, AR_MACMISC,
@@ -93,20 +100,20 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                   (AR_MACMISC_MISC_OBS_BUS_1 <<
                    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                        "Raw DMA Debug values:\n");
 
        for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
                if (i % 4 == 0)
-                       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+                       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
 
                val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
-               len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
+               len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
                                i, val[i]);
        }
 
-       len += snprintf(buf + len, sizeof(buf) - len, "\n\n");
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                        "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
 
        for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
@@ -120,7 +127,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                        dcuBase++;
                }
 
-               len += snprintf(buf + len, sizeof(buf) - len,
+               len += snprintf(buf + len, DMA_BUF_LEN - len,
                        "%2d          %2x      %1x     %2x           %2x\n",
                        i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
                        (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
@@ -128,35 +135,37 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                        (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
        }
 
-       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
 
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
                (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "qcu_complete state: %2x    dcu_complete state:     %2x\n",
                (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
                (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
                (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
                (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
-       len += snprintf(buf + len, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
 
-       len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
+       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, sizeof(buf) - len,
+       len += snprintf(buf + len, DMA_BUF_LEN - len,
                        "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
 
        ath9k_ps_restore(sc);
 
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return retval;
 }
 
 static const struct file_operations fops_dma = {
index e204bd25ff65eec5b7904d9846969e39a1467939..deab8beb068010a7a7ec3de2ddd404d64ddce32a 100644 (file)
@@ -230,12 +230,17 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
 
        if (time_after(jiffies, btcoex->bt_priority_time +
                        msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-               if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+               sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
+               /* Detect if colocated bt started scanning */
+               if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
+                       ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+                                 "BT scan detected");
+                       sc->sc_flags |= (SC_OP_BT_SCAN |
+                                        SC_OP_BT_PRIORITY_DETECTED);
+               } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
                        ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
                                  "BT priority traffic detected");
                        sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
-               } else {
-                       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
                }
 
                btcoex->bt_priority_cnt = 0;
@@ -316,12 +321,17 @@ static void ath_btcoex_period_timer(unsigned long data)
        struct ath_softc *sc = (struct ath_softc *) data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
+       u32 timer_period;
+       bool is_btscan;
 
        ath_detect_bt_priority(sc);
 
+       is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
+
        spin_lock_bh(&btcoex->btcoex_lock);
 
-       ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
+       ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+                             btcoex->bt_stomp_type);
 
        spin_unlock_bh(&btcoex->btcoex_lock);
 
@@ -329,11 +339,12 @@ static void ath_btcoex_period_timer(unsigned long data)
                if (btcoex->hw_timer_enabled)
                        ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
 
+               timer_period = is_btscan ? btcoex->btscan_no_stomp :
+                                          btcoex->btcoex_no_stomp;
                ath9k_gen_timer_start(ah,
                                      btcoex->no_stomp_timer,
                                      (ath9k_hw_gettsf32(ah) +
-                                      btcoex->btcoex_no_stomp),
-                                      btcoex->btcoex_no_stomp * 10);
+                                      timer_period), timer_period * 10);
                btcoex->hw_timer_enabled = true;
        }
 
@@ -350,13 +361,14 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        struct ath_softc *sc = (struct ath_softc *)arg;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
+       bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
                  "no stomp timer running \n");
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
-       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
                ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
                ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
@@ -371,6 +383,8 @@ int ath_init_btcoex_timer(struct ath_softc *sc)
        btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
        btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
                btcoex->btcoex_period / 100;
+       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+                                  btcoex->btcoex_period / 100;
 
        setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
                        (unsigned long) sc);
@@ -405,7 +419,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc)
 
        btcoex->bt_priority_cnt = 0;
        btcoex->bt_priority_time = jiffies;
-       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+       sc->sc_flags &= ~(SC_OP_BT_PRIORITY_DETECTED | SC_OP_BT_SCAN);
 
        mod_timer(&btcoex->period_timer, jiffies);
 }
index 1a27f39c1adc8e776c3e3cfcb853aca580052288..f15fee76a4e24272efc3b04d5c16e6707641dc36 100644 (file)
@@ -334,7 +334,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        ah->config.pcie_clock_req = 0;
        ah->config.pcie_waen = 0;
        ah->config.analog_shiftreg = 1;
-       ah->config.ht_enable = 1;
        ah->config.ofdm_trig_low = 200;
        ah->config.ofdm_trig_high = 500;
        ah->config.cck_trig_high = 200;
@@ -346,6 +345,11 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
                ah->config.spurchans[i][1] = AR_NO_SPUR;
        }
 
+       if (ah->hw_version.devid != AR2427_DEVID_PCIE)
+               ah->config.ht_enable = 1;
+       else
+               ah->config.ht_enable = 0;
+
        ah->config.rx_intr_mitigation = true;
 
        /*
@@ -542,6 +546,7 @@ static bool ath9k_hw_devid_supported(u16 devid)
        case AR5416_DEVID_AR9287_PCI:
        case AR5416_DEVID_AR9287_PCIE:
        case AR9271_USB:
+       case AR2427_DEVID_PCIE:
                return true;
        default:
                break;
index ab1f1981d857a2a697375f17bad6527ca4ed64c6..dbbf7ca5f97d8a5b7ca60f6e3d193a7435f08d7d 100644 (file)
@@ -40,6 +40,7 @@
 #define AR9280_DEVID_PCI       0x0029
 #define AR9280_DEVID_PCIE      0x002a
 #define AR9285_DEVID_PCIE      0x002b
+#define AR2427_DEVID_PCIE      0x002c
 
 #define AR5416_AR9100_DEVID    0x000b
 
index 5f78d7a5ff226fe5d1085b22d266bd76f333d1fa..4b5e54848683be97b4e56ee3fa4d9cf47788a024 100644 (file)
@@ -620,11 +620,13 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_AMPDU_AGGREGATION |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_PS_NULLFUNC_STACK |
                IEEE80211_HW_SPECTRUM_MGMT;
 
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+                hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+
        if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
@@ -640,8 +642,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->max_rates = 4;
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
-       /* Hardware supports 10 but we use 4 */
-       hw->max_rate_tries = 4;
+       hw->max_rate_tries = 10;
        hw->sta_data_size = sizeof(struct ath_node);
        hw->vif_data_size = sizeof(struct ath_vif);
 
index 6aaca0026da8355714ba3c2ed1d4b7f52b497f3d..6796d5cdc293611c0fdd063cdeb7641dede2227e 100644 (file)
@@ -143,8 +143,10 @@ void ath9k_ps_restore(struct ath_softc *sc)
        if (--sc->ps_usecount != 0)
                goto unlock;
 
-       if (sc->ps_enabled &&
-           !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+       if (sc->ps_idle)
+               ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+       else if (sc->ps_enabled &&
+                !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
                              PS_WAIT_FOR_CAB |
                              PS_WAIT_FOR_PSPOLL_DATA |
                              PS_WAIT_FOR_TX_ACK)))
@@ -204,7 +206,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
        r = ath9k_hw_reset(ah, hchan, fastcc);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
-                         "Unable to reset channel (%u Mhz) "
+                         "Unable to reset channel (%u MHz), "
                          "reset status %d\n",
                          channel->center_freq, r);
                spin_unlock_bh(&sc->sc_resetlock);
@@ -867,7 +869,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
        r = ath9k_hw_reset(ah, ah->curchan, false);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
-                         "Unable to reset channel %u (%uMhz) ",
+                         "Unable to reset channel (%u MHz), "
                          "reset status %d\n",
                          channel->center_freq, r);
        }
@@ -922,7 +924,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
        r = ath9k_hw_reset(ah, ah->curchan, false);
        if (r) {
                ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
-                         "Unable to reset channel %u (%uMhz) "
+                         "Unable to reset channel (%u MHz), "
                          "reset status %d\n",
                          channel->center_freq, r);
        }
@@ -1528,6 +1530,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                spin_unlock_bh(&sc->wiphy_lock);
 
                if (enable_radio) {
+                       sc->ps_idle = false;
                        ath_radio_enable(sc, hw);
                        ath_print(common, ATH_DBG_CONFIG,
                                  "not-idle: enabling radio\n");
@@ -1624,8 +1627,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        }
 
 skip_chan_change:
-       if (changed & IEEE80211_CONF_CHANGE_POWER)
+       if (changed & IEEE80211_CONF_CHANGE_POWER) {
                sc->config.txpowlimit = 2 * conf->power_level;
+               ath_update_txpow(sc);
+       }
 
        spin_lock_bh(&sc->wiphy_lock);
        disable_radio = ath9k_all_wiphys_idle(sc);
@@ -1633,6 +1638,7 @@ skip_chan_change:
 
        if (disable_radio) {
                ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
+               sc->ps_idle = true;
                ath_radio_disable(sc, hw);
        }
 
index fe2c3a644a6ed01583c0f5c1116f5f4a5111dbda..9441c6718a3098a760c0c0d1a13819b3fe8524aa 100644 (file)
@@ -25,6 +25,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
        { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+       { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
        { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
        { 0 }
@@ -49,16 +50,6 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
                *csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
 }
 
-static void ath_pci_cleanup(struct ath_common *common)
-{
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-       struct pci_dev *pdev = to_pci_dev(sc->dev);
-
-       pci_iounmap(pdev, sc->mem);
-       pci_disable_device(pdev);
-       pci_release_region(pdev, 0);
-}
-
 static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 {
        struct ath_hw *ah = (struct ath_hw *) common->ah;
@@ -98,7 +89,6 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
 
 static const struct ath_bus_ops ath_pci_bus_ops = {
        .read_cachesize = ath_pci_read_cachesize,
-       .cleanup = ath_pci_cleanup,
        .eeprom_read = ath_pci_eeprom_read,
        .bt_coex_prep = ath_pci_bt_coex_prep,
 };
@@ -245,12 +235,15 @@ static void ath_pci_remove(struct pci_dev *pdev)
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       void __iomem *mem = sc->mem;
 
        ath9k_deinit_device(sc);
        free_irq(sc->irq, sc);
        ieee80211_free_hw(sc->hw);
-       ath_bus_cleanup(common);
+
+       pci_iounmap(pdev, mem);
+       pci_disable_device(pdev);
+       pci_release_region(pdev, 0);
 }
 
 #ifdef CONFIG_PM
index 70fdb9d8db82579193b8ed7e393ef9cc0a30cd7a..11968843c7735c646e3e488a40f9eba0d4f6beea 100644 (file)
@@ -678,13 +678,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
         * For Multi Rate Retry we use a different number of
         * retry attempt counts. This ends up looking like this:
         *
-        * MRR[0] = 2
-        * MRR[1] = 2
-        * MRR[2] = 2
-        * MRR[3] = 4
+        * MRR[0] = 4
+        * MRR[1] = 4
+        * MRR[2] = 4
+        * MRR[3] = 8
         *
         */
-       try_per_rate = sc->hw->max_rate_tries;
+       try_per_rate = 4;
 
        rate_table = sc->cur_rate_table;
        rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
@@ -714,7 +714,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        for ( ; i < 4; i++) {
                /* Use twice the number of tries for the last MRR segment. */
                if (i + 1 == 4)
-                       try_per_rate = 4;
+                       try_per_rate = 8;
 
                ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
                /* All other rates in the series have RTS enabled */
index 40b5d05edcce8ab274ad216d90aed3800b78e67f..1ca42e5148c81ba72935899a931125b1a60b2d1a 100644 (file)
@@ -429,7 +429,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
                sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
                ath_print(common, ATH_DBG_PS,
                          "Going back to sleep after having received "
-                         "PS-Poll data (0x%x)\n",
+                         "PS-Poll data (0x%lx)\n",
                        sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                        PS_WAIT_FOR_CAB |
                                        PS_WAIT_FOR_PSPOLL_DATA |
index 8e653fb937a10e6c305cccea20be864293219296..72cfa8ebd9ae193677cc6c77c985ffab9b6c354a 100644 (file)
@@ -1547,9 +1547,9 @@ enum {
 
 #define AR_BT_COEX_WEIGHT          0x8174
 #define AR_BT_COEX_WGHT                   0xff55
-#define AR_STOMP_ALL_WLAN_WGHT    0xffcc
-#define AR_STOMP_LOW_WLAN_WGHT    0xaaa8
-#define AR_STOMP_NONE_WLAN_WGHT           0xaa00
+#define AR_STOMP_ALL_WLAN_WGHT    0xfcfc
+#define AR_STOMP_LOW_WLAN_WGHT    0xa8a8
+#define AR_STOMP_NONE_WLAN_WGHT           0x0000
 #define AR_BTCOEX_BT_WGHT          0x0000ffff
 #define AR_BTCOEX_BT_WGHT_S        0
 #define AR_BTCOEX_WL_WGHT          0xffff0000
index a821bb687b3bdb72d45d533d123a5708e3c8ca7b..3c790a4f38f77988b2bfdbd09ddca89ea9f2740f 100644 (file)
@@ -1498,26 +1498,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
                ctsrate |= rate->hw_value_short;
 
-       /*
-        * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
-        * Check the first rate in the series to decide whether RTS/CTS
-        * or CTS-to-self has to be used.
-        */
-       if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
-               flags = ATH9K_TXDESC_CTSENA;
-       else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               flags = ATH9K_TXDESC_RTSENA;
-
-       /* FIXME: Handle aggregation protection */
-       if (sc->config.ath_aggr_prot &&
-           (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
-               flags = ATH9K_TXDESC_RTSENA;
-       }
-
-       /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
-       if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
-               flags &= ~(ATH9K_TXDESC_RTSENA);
-
        for (i = 0; i < 4; i++) {
                bool is_40, is_sgi, is_sp;
                int phy;
@@ -1529,8 +1509,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                series[i].Tries = rates[i].count;
                series[i].ChSel = common->tx_chainmask;
 
-               if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
+                   (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
                        series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+                       flags |= ATH9K_TXDESC_RTSENA;
+               } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+                       flags |= ATH9K_TXDESC_CTSENA;
+               }
+
                if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                        series[i].RateFlags |= ATH9K_RATESERIES_2040;
                if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
@@ -1568,6 +1555,14 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                        phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
        }
 
+       /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+       if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
+               flags &= ~ATH9K_TXDESC_RTSENA;
+
+       /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
+       if (flags & ATH9K_TXDESC_RTSENA)
+               flags &= ~ATH9K_TXDESC_CTSENA;
+
        /* set dur_update_en for l-sig computation except for PS-Poll frames */
        ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
                                     bf->bf_lastbf->bf_desc,
@@ -1862,7 +1857,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_print(common, ATH_DBG_PS,
                          "Going back to sleep after having "
-                         "received TX status (0x%x)\n",
+                         "received TX status (0x%lx)\n",
                        sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                        PS_WAIT_FOR_CAB |
                                        PS_WAIT_FOR_PSPOLL_DATA |
index d6b685a06c5edb9cc33853a163d186fc083f2528..8263633c003c050c1640a6994c8a33743cd1ba43 100644 (file)
@@ -65,11 +65,11 @@ enum ATH_DEBUG {
 #define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
 
 #ifdef CONFIG_ATH_DEBUG
-void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...);
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
+       __attribute__ ((format (printf, 3, 4)));
 #else
-static inline void ath_print(struct ath_common *common,
-                            int dbg_mask,
-                            const char *fmt, ...)
+static inline void __attribute__ ((format (printf, 3, 4)))
+ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
 {
 }
 #endif /* CONFIG_ATH_DEBUG */
index 9c5c7c9ad530212b0c0446e813390cd45b8e920a..316a913860d7833a3754bef53d6f044189a02c27 100644 (file)
@@ -844,8 +844,10 @@ static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
 }
 
 static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
-                       struct ieee80211_key_conf *keyconf, const u8 *addr,
-                       u32 iv32, u16 *phase1key)
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_key_conf *keyconf,
+                                  struct ieee80211_sta *sta,
+                                  u32 iv32, u16 *phase1key)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -854,19 +856,19 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
        if (B43_WARN_ON(!modparam_hwtkip))
                return;
 
-       mutex_lock(&wl->mutex);
-
+       /* This is only called from the RX path through mac80211, where
+        * our mutex is already locked. */
+       B43_WARN_ON(!mutex_is_locked(&wl->mutex));
        dev = wl->current_dev;
-       if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
-               goto out_unlock;
+       B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED);
 
        keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
 
        rx_tkip_phase1_write(dev, index, iv32, phase1key);
-       keymac_write(dev, index, addr);
-
-out_unlock:
-       mutex_unlock(&wl->mutex);
+       /* only pairwise TKIP keys are supported right now */
+       if (WARN_ON(!sta))
+               return;
+       keymac_write(dev, index, sta->addr);
 }
 
 static void do_key_write(struct b43_wldev *dev,
@@ -3571,6 +3573,12 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        dev = wl->current_dev;
        phy = &dev->phy;
 
+       if (conf_is_ht(conf))
+               phy->is_40mhz =
+                       (conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf));
+       else
+               phy->is_40mhz = false;
+
        b43_mac_suspend(dev);
 
        if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
index 75b26e175e8fc9028da8084fac5eebb9bca3f92b..8f7d7eff2d803a79649e4a340f15a6d806089adb 100644 (file)
@@ -421,3 +421,48 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
 {
        b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
 }
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */
+struct b43_c32 b43_cordic(int theta)
+{
+       u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
+                     58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
+                     229, 115, 57, 29, };
+       u8 i;
+       s32 tmp;
+       s8 signx = 1;
+       u32 angle = 0;
+       struct b43_c32 ret = { .i = 39797, .q = 0, };
+
+       while (theta > (180 << 16))
+               theta -= (360 << 16);
+       while (theta < -(180 << 16))
+               theta += (360 << 16);
+
+       if (theta > (90 << 16)) {
+               theta -= (180 << 16);
+               signx = -1;
+       } else if (theta < -(90 << 16)) {
+               theta += (180 << 16);
+               signx = -1;
+       }
+
+       for (i = 0; i <= 17; i++) {
+               if (theta > angle) {
+                       tmp = ret.i - (ret.q >> i);
+                       ret.q += ret.i >> i;
+                       ret.i = tmp;
+                       angle += arctg[i];
+               } else {
+                       tmp = ret.i + (ret.q >> i);
+                       ret.q -= ret.i >> i;
+                       ret.i = tmp;
+                       angle -= arctg[i];
+               }
+       }
+
+       ret.i *= signx;
+       ret.q *= signx;
+
+       return ret;
+}
index 9edd4e8e0c857658a04dd6068375fe956e75874d..bd480b481bfc387da47d8744e2174e3f5da7111f 100644 (file)
@@ -5,6 +5,12 @@
 
 struct b43_wldev;
 
+/* Complex number using 2 32-bit signed integers */
+struct b43_c32 { s32 i, q; };
+
+#define CORDIC_CONVERT(value)  (((value) >= 0) ? \
+                                ((((value) >> 15) + 1) >> 1) : \
+                                -((((-(value)) >> 15) + 1) >> 1))
 
 /* PHY register routing bits */
 #define B43_PHYROUTE                   0x0C00 /* PHY register routing bits mask */
@@ -212,6 +218,9 @@ struct b43_phy {
        bool supports_2ghz;
        bool supports_5ghz;
 
+       /* HT info */
+       bool is_40mhz;
+
        /* GMODE bit enabled? */
        bool gmode;
 
@@ -418,5 +427,6 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
  */
 void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
 
+struct b43_c32 b43_cordic(int theta);
 
 #endif /* LINUX_B43_PHY_COMMON_H_ */
index b58d6cf26580a90c79d0b84c11b9148192d241be..185219e0a55243deed19cb3a6d50c0640d5ccb32 100644 (file)
@@ -1767,47 +1767,6 @@ out:
        return ret;
 }
 
-/* Complex number using 2 32-bit signed integers */
-typedef struct {s32 i, q;} lpphy_c32;
-
-static lpphy_c32 lpphy_cordic(int theta)
-{
-       u32 arctg[] = { 2949120, 1740967, 919879, 466945, 234379, 117304,
-                     58666, 29335, 14668, 7334, 3667, 1833, 917, 458,
-                     229, 115, 57, 29, };
-       int i, tmp, signx = 1, angle = 0;
-       lpphy_c32 ret = { .i = 39797, .q = 0, };
-
-       theta = clamp_t(int, theta, -180, 180);
-
-       if (theta > 90) {
-               theta -= 180;
-               signx = -1;
-       } else if (theta < -90) {
-               theta += 180;
-               signx = -1;
-       }
-
-       for (i = 0; i <= 17; i++) {
-               if (theta > angle) {
-                       tmp = ret.i - (ret.q >> i);
-                       ret.q += ret.i >> i;
-                       ret.i = tmp;
-                       angle += arctg[i];
-               } else {
-                       tmp = ret.i + (ret.q >> i);
-                       ret.q -= ret.i >> i;
-                       ret.i = tmp;
-                       angle -= arctg[i];
-               }
-       }
-
-       ret.i *= signx;
-       ret.q *= signx;
-
-       return ret;
-}
-
 static void lpphy_run_samples(struct b43_wldev *dev, u16 samples, u16 loops,
                              u16 wait)
 {
@@ -1825,8 +1784,9 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
        u16 buf[64];
-       int i, samples = 0, angle = 0, rotation = (9 * freq) / 500;
-       lpphy_c32 sample;
+       int i, samples = 0, angle = 0;
+       int rotation = (((36 * freq) / 20) << 16) / 100;
+       struct b43_c32 sample;
 
        lpphy->tx_tone_freq = freq;
 
@@ -1842,10 +1802,10 @@ static void lpphy_start_tx_tone(struct b43_wldev *dev, s32 freq, u16 max)
        }
 
        for (i = 0; i < samples; i++) {
-               sample = lpphy_cordic(angle);
+               sample = b43_cordic(angle);
                angle += rotation;
-               buf[i] = ((sample.i * max) & 0xFF) << 8;
-               buf[i] |= (sample.q * max) & 0xFF;
+               buf[i] = CORDIC_CONVERT((sample.i * max) & 0xFF) << 8;
+               buf[i] |= CORDIC_CONVERT((sample.q * max) & 0xFF);
        }
 
        b43_lptab_write_bulk(dev, B43_LPTAB16(5, 0), samples, buf);
index 4a817e3da163c73b79d8194c8c6f4293c348ed0c..6392da25efed06197b3ff86d32143290a17a861c 100644 (file)
@@ -55,6 +55,20 @@ struct nphy_iq_est {
        u32 q1_pwr;
 };
 
+enum b43_nphy_rf_sequence {
+       B43_RFSEQ_RX2TX,
+       B43_RFSEQ_TX2RX,
+       B43_RFSEQ_RESET2RX,
+       B43_RFSEQ_UPDATE_GAINH,
+       B43_RFSEQ_UPDATE_GAINL,
+       B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
+                                       u8 *events, u8 *delays, u8 length);
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+                                      enum b43_nphy_rf_sequence seq);
+
 void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
 {//TODO
 }
@@ -234,110 +248,6 @@ static void b43_nphy_tables_init(struct b43_wldev *dev)
                b43_nphy_rev3plus_tables_init(dev);
 }
 
-static void b43_nphy_workarounds(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       unsigned int i;
-
-       b43_phy_set(dev, B43_NPHY_IQFLIP,
-                   B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
-       if (1 /* FIXME band is 2.4GHz */) {
-               b43_phy_set(dev, B43_NPHY_CLASSCTL,
-                           B43_NPHY_CLASSCTL_CCKEN);
-       } else {
-               b43_phy_mask(dev, B43_NPHY_CLASSCTL,
-                            ~B43_NPHY_CLASSCTL_CCKEN);
-       }
-       b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
-       b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
-
-       /* Fixup some tables */
-       b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
-
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
-       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
-
-       //TODO set RF sequence
-
-       /* Set narrowband clip threshold */
-       b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
-       b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
-
-       /* Set wideband clip 2 threshold */
-       b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
-                       ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
-                       21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
-       b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
-                       ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
-                       21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
-
-       /* Set Clip 2 detect */
-       b43_phy_set(dev, B43_NPHY_C1_CGAINI,
-                   B43_NPHY_C1_CGAINI_CL2DETECT);
-       b43_phy_set(dev, B43_NPHY_C2_CGAINI,
-                   B43_NPHY_C2_CGAINI_CL2DETECT);
-
-       if (0 /*FIXME*/) {
-               /* Set dwell lengths */
-               b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
-               b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
-               b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
-               b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
-
-               /* Set gain backoff */
-               b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
-                               ~B43_NPHY_C1_CGAINI_GAINBKOFF,
-                               1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
-               b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
-                               ~B43_NPHY_C2_CGAINI_GAINBKOFF,
-                               1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
-
-               /* Set HPVGA2 index */
-               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
-                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
-                               6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
-               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
-                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
-                               6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
-
-               //FIXME verify that the specs really mean to use autoinc here.
-               for (i = 0; i < 3; i++)
-                       b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
-       }
-
-       /* Set minimum gain value */
-       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
-                       ~B43_NPHY_C1_MINGAIN,
-                       23 << B43_NPHY_C1_MINGAIN_SHIFT);
-       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
-                       ~B43_NPHY_C2_MINGAIN,
-                       23 << B43_NPHY_C2_MINGAIN_SHIFT);
-
-       if (phy->rev < 2) {
-               b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
-                            ~B43_NPHY_SCRAM_SIGCTL_SCM);
-       }
-
-       /* Set phase track alpha and beta */
-       b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
-       b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
-       b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
-       b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
 static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
 {
@@ -421,7 +331,49 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev)
        udelay(1);
        b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
        b43_nphy_bmac_clock_fgc(dev, 0);
-       /* TODO: N PHY Force RF Seq with argument 2 */
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
+static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble)
+{
+       u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG);
+
+       mimocfg |= B43_NPHY_MIMOCFG_AUTO;
+       if (preamble == 1)
+               mimocfg |= B43_NPHY_MIMOCFG_GFMIX;
+       else
+               mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX;
+
+       b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
+static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       bool override = false;
+       u16 chain = 0x33;
+
+       if (nphy->txrx_chain == 0) {
+               chain = 0x11;
+               override = true;
+       } else if (nphy->txrx_chain == 1) {
+               chain = 0x22;
+               override = true;
+       }
+
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+                       ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
+                       chain);
+
+       if (override)
+               b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+                               B43_NPHY_RFSEQMODE_CAOVER);
+       else
+               b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+                               ~B43_NPHY_RFSEQMODE_CAOVER);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
@@ -480,6 +432,88 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
+static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core)
+{
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+       b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]);
+       if (core == 0) {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
+       } else {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
+       }
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]);
+       b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]);
+       b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
+       b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */
+static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
+{
+       u8 rxval, txval;
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+       regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
+       if (core == 0) {
+               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+       } else {
+               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+       }
+       regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+       regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+       regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
+       regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+       regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1);
+       regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
+       regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
+       regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
+
+       b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
+       b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, (u16)~B43_NPHY_RFSEQCA_RXDIS,
+                       ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
+                       ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
+                       (core << B43_NPHY_RFSEQCA_RXEN_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS,
+                       (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT));
+
+       if (core == 0) {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007);
+       } else {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007);
+       }
+
+       /* TODO: Call N PHY RF Ctrl Intc Override with 2, 0, 3 as arguments */
+       /* TODO: Call N PHY RF Intc Override with 8, 0, 3, 0 as arguments */
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+
+       if (core == 0) {
+               rxval = 1;
+               txval = 8;
+       } else {
+               rxval = 4;
+               txval = 2;
+       }
+
+       /* TODO: Call N PHY RF Ctrl Intc Override with 1, rxval, (core + 1) */
+       /* TODO: Call N PHY RF Ctrl Intc Override with 1, txval, (2 - core) */
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
 static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
 {
@@ -653,6 +687,386 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
+static void b43_nphy_stop_playback(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 tmp;
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
+       if (tmp & 0x1)
+               b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
+       else if (tmp & 0x2)
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, (u16)~0x8000);
+
+       b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
+
+       if (nphy->bb_mult_save & 0x80000000) {
+               tmp = nphy->bb_mult_save & 0xFFFF;
+               b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+               nphy->bb_mult_save = 0;
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
+static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i, j;
+       u8 code;
+
+       /* TODO: for PHY >= 3
+       s8 *lna1_gain, *lna2_gain;
+       u8 *gain_db, *gain_bits;
+       u16 *rfseq_init;
+       u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
+       u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
+       */
+
+       u8 rfseq_events[3] = { 6, 8, 7 };
+       u8 rfseq_delays[3] = { 10, 30, 1 };
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               /* Set Clip 2 detect */
+               b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+                               B43_NPHY_C1_CGAINI_CL2DETECT);
+               b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+                               B43_NPHY_C2_CGAINI_CL2DETECT);
+
+               /* Set narrowband clip threshold */
+               b43_phy_set(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
+               b43_phy_set(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
+
+               if (!dev->phy.is_40mhz) {
+                       /* Set dwell lengths */
+                       b43_phy_set(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
+                       b43_phy_set(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
+                       b43_phy_set(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
+                       b43_phy_set(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
+               }
+
+               /* Set wideband clip 2 threshold */
+               b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+                               ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+                               21);
+               b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+                               ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+                               21);
+
+               if (!dev->phy.is_40mhz) {
+                       b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+                               ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+                               ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
+                               ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
+                       b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
+                               ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
+               }
+
+               b43_phy_set(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+
+               if (nphy->gain_boost) {
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
+                           dev->phy.is_40mhz)
+                               code = 4;
+                       else
+                               code = 5;
+               } else {
+                       code = dev->phy.is_40mhz ? 6 : 7;
+               }
+
+               /* Set HPVGA2 index */
+               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
+                               code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
+                               code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x7C));
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x7C));
+
+               /* TODO: b43_nphy_adjust_lna_gain_table(dev); */
+
+               if (nphy->elna_gain_config) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x74));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (code << 8 | 0x74));
+               }
+
+               if (dev->phy.rev == 2) {
+                       for (i = 0; i < 4; i++) {
+                               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                                               (0x0400 * i) + 0x0020);
+                               for (j = 0; j < 21; j++)
+                                       b43_phy_write(dev,
+                                               B43_NPHY_TABLE_DATALO, 3 * j);
+                       }
+
+                       b43_nphy_set_rf_sequence(dev, 5,
+                                       rfseq_events, rfseq_delays, 3);
+                       b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
+                               (u16)~B43_NPHY_OVER_DGAIN_CCKDGECV,
+                               0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
+
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                               b43_phy_maskset(dev, B43_PHY_N(0xC5D),
+                                               0xFF80, 4);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->dev->bus;
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
+
+       u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 };
+       u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 };
+
+       u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
+       u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               b43_nphy_classifier(dev, 1, 0);
+       else
+               b43_nphy_classifier(dev, 1, 1);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       b43_phy_set(dev, B43_NPHY_IQFLIP,
+                   B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
+                   nphy->band5g_pwrgain) {
+                       b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
+                       b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8);
+               } else {
+                       b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+                       b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8);
+               }
+
+               /* TODO: convert to b43_ntab_write? */
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2000);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2010);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x000A);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2002);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2012);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0xCDAA);
+
+               if (dev->phy.rev < 2) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2008);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2018);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0000);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2007);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2017);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x7AAB);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2006);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x2016);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0800);
+               }
+
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+               if (bus->sprom.boardflags2_lo & 0x100 &&
+                   bus->boardinfo.type == 0x8B) {
+                       delays1[0] = 0x1;
+                       delays1[5] = 0x14;
+               }
+               b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
+               b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
+
+               b43_nphy_gain_crtl_workarounds(dev);
+
+               if (dev->phy.rev < 2) {
+                       if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
+                               ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+               } else if (dev->phy.rev == 2) {
+                       b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
+                       b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
+               }
+
+               if (dev->phy.rev < 2)
+                       b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+                                       ~B43_NPHY_SCRAM_SIGCTL_SCM);
+
+               /* Set phase track alpha and beta */
+               b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+               b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+               b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+               b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+
+               b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+                               (u16)~B43_NPHY_PIL_DW_64QAM);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+
+               if (dev->phy.rev == 2)
+                       b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
+                                       B43_NPHY_FINERX2_CGC_DECGC);
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
+static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
+                                       bool test)
+{
+       int i;
+       u16 bw, len, rot, angle;
+       struct b43_c32 *samples;
+
+
+       bw = (dev->phy.is_40mhz) ? 40 : 20;
+       len = bw << 3;
+
+       if (test) {
+               if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
+                       bw = 82;
+               else
+                       bw = 80;
+
+               if (dev->phy.is_40mhz)
+                       bw <<= 1;
+
+               len = bw << 1;
+       }
+
+       samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL);
+       rot = (((freq * 36) / bw) << 16) / 100;
+       angle = 0;
+
+       for (i = 0; i < len; i++) {
+               samples[i] = b43_cordic(angle);
+               angle += rot;
+               samples[i].q = CORDIC_CONVERT(samples[i].q * max);
+               samples[i].i = CORDIC_CONVERT(samples[i].i * max);
+       }
+
+       /* TODO: Call N PHY Load Sample Table with buffer, len as arguments */
+       kfree(samples);
+       return len;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
+static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+                                       u16 wait, bool iqmode, bool dac_test)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i;
+       u16 seq_mode;
+       u32 tmp;
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
+
+       if ((nphy->bb_mult_save & 0x80000000) == 0) {
+               tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
+               nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
+       }
+
+       if (!dev->phy.is_40mhz)
+               tmp = 0x6464;
+       else
+               tmp = 0x4747;
+       b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
+
+       b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
+
+       if (loops != 0xFFFF)
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
+       else
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
+
+       b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
+
+       seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
+
+       b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
+       if (iqmode) {
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+               b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
+       } else {
+               if (dac_test)
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
+               else
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
+       }
+       for (i = 0; i < 100; i++) {
+               if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
+                       i = 0;
+                       break;
+               }
+               udelay(10);
+       }
+       if (i)
+               b43err(dev->wl, "run samples timeout\n");
+
+       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+}
+
+/*
+ * Transmits a known value for LO calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
+ */
+static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
+                               bool iqmode, bool dac_test)
+{
+       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
+       if (samp == 0)
+               return -1;
+       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
+       return 0;
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
 static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
 {
@@ -666,8 +1080,7 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
        if (nphy->hang_avoid)
                b43_nphy_stay_in_carrier_search(dev, true);
 
-       /* TODO: Read an N PHY Table with ID 15, length 7, offset 80,
-               width 16, and data pointer buffer */
+       b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
 
        for (i = 0; i < 2; i++) {
                tmp = ((buffer[i * 2] & 0x3FF) << 10) |
@@ -720,15 +1133,32 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
                b43_nphy_stay_in_carrier_search(dev, false);
 }
 
-enum b43_nphy_rf_sequence {
-       B43_RFSEQ_RX2TX,
-       B43_RFSEQ_TX2RX,
-       B43_RFSEQ_RESET2RX,
-       B43_RFSEQ_UPDATE_GAINH,
-       B43_RFSEQ_UPDATE_GAINL,
-       B43_RFSEQ_UPDATE_GAINU,
-};
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
+static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
+                                       u8 *events, u8 *delays, u8 length)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i;
+       u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F;
+       u16 offset1 = cmd << 4;
+       u16 offset2 = offset1 + 0x80;
 
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
+
+       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events);
+       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays);
+
+       for (i = length; i < 16; i++) {
+               b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end);
+               b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1);
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
 static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
                                       enum b43_nphy_rf_sequence seq)
 {
@@ -741,6 +1171,7 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
                [B43_RFSEQ_UPDATE_GAINU]        = B43_NPHY_RFSEQTR_UPGU,
        };
        int i;
+       u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
 
        B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
 
@@ -754,8 +1185,83 @@ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
        }
        b43err(dev->wl, "RF sequence status timeout\n");
 ok:
-       b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
-                    ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
+static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
+                                               u16 value, u8 core, bool off)
+{
+       int i;
+       u8 index = fls(field);
+       u8 addr, en_addr, val_addr;
+       /* we expect only one bit set */
+       B43_WARN_ON(field & (~(1 << (index - 1))));
+
+       if (dev->phy.rev >= 3) {
+               const struct nphy_rf_control_override_rev3 *rf_ctrl;
+               for (i = 0; i < 2; i++) {
+                       if (index == 0 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
+
+                       rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
+                       en_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
+                       val_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
+
+                       if (off) {
+                               b43_phy_mask(dev, en_addr, ~(field));
+                               b43_phy_mask(dev, val_addr,
+                                               ~(rf_ctrl->val_mask));
+                       } else {
+                               if (core == 0 || ((1 << core) & i) != 0) {
+                                       b43_phy_set(dev, en_addr, field);
+                                       b43_phy_maskset(dev, val_addr,
+                                               ~(rf_ctrl->val_mask),
+                                               (value << rf_ctrl->val_shift));
+                               }
+                       }
+               }
+       } else {
+               const struct nphy_rf_control_override_rev2 *rf_ctrl;
+               if (off) {
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
+                       value = 0;
+               } else {
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
+               }
+
+               for (i = 0; i < 2; i++) {
+                       if (index <= 1 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
+
+                       if (index == 2 || index == 10 ||
+                           (index >= 13 && index <= 15)) {
+                               core = 1;
+                       }
+
+                       rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
+                       addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->addr0 : rf_ctrl->addr1);
+
+                       if ((core & (1 << i)) != 0)
+                               b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
+                                               (value << rf_ctrl->shift));
+
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
+                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                                       B43_NPHY_RFCTL_CMD_START);
+                       udelay(1);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
+               }
+       }
 }
 
 static void b43_nphy_bphy_init(struct b43_wldev *dev)
@@ -837,66 +1343,151 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
 }
 
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
-static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
 {
        u16 val;
 
-       if (dev->phy.rev >= 3) {
-               /* TODO */
-       } else {
-               if (type < 3)
-                       val = 0;
-               else if (type == 6)
-                       val = 1;
-               else if (type == 3)
-                       val = 2;
-               else
-                       val = 3;
+       if (type < 3)
+               val = 0;
+       else if (type == 6)
+               val = 1;
+       else if (type == 3)
+               val = 2;
+       else
+               val = 3;
 
-               val = (val << 12) | (val << 14);
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
+       val = (val << 12) | (val << 14);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
 
+       if (type < 3) {
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
+                               (type + 1) << 4);
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
+                               (type + 1) << 4);
+       }
+
+       /* TODO use some definitions */
+       if (code == 0) {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
+               if (type < 3) {
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0);
+                       udelay(20);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+               }
+       } else {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
+                               0x3000);
                if (type < 3) {
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
-                                       (type + 1) << 4);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
-                                       (type + 1) << 4);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                       0xFEC7, 0x0180);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                       0xEFDC, (code << 1 | 0x1021));
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1);
+                       udelay(20);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
                }
+       }
+}
+
+static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i;
+       u16 reg, val;
+
+       if (code == 0) {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF);
+               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF);
+               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF);
+               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
+               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
+       } else {
+               for (i = 0; i < 2; i++) {
+                       if ((code == 1 && i == 1) || (code == 2 && !i))
+                               continue;
+
+                       reg = (i == 0) ?
+                               B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
+                       b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
 
-               /* TODO use some definitions */
-               if (code == 0) {
-                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
-                       if (type < 3) {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFEC7, 0);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xEFDC, 0);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFFFE, 0);
-                               udelay(20);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE, 0);
-                       }
-               } else {
-                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
-                                       0x3000);
                        if (type < 3) {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFEC7, 0x0180);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xEFDC, (code << 1 | 0x1021));
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                               0xFFFE, 0x0001);
-                               udelay(20);
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE, 0);
+                               reg = (i == 0) ?
+                                       B43_NPHY_AFECTL_C1 :
+                                       B43_NPHY_AFECTL_C2;
+                               b43_phy_maskset(dev, reg, 0xFCFF, 0);
+
+                               reg = (i == 0) ?
+                                       B43_NPHY_RFCTL_LUT_TRSW_UP1 :
+                                       B43_NPHY_RFCTL_LUT_TRSW_UP2;
+                               b43_phy_maskset(dev, reg, 0xFFC3, 0);
+
+                               if (type == 0)
+                                       val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
+                               else if (type == 1)
+                                       val = 16;
+                               else
+                                       val = 32;
+                               b43_phy_set(dev, reg, val);
+
+                               reg = (i == 0) ?
+                                       B43_NPHY_TXF_40CO_B1S0 :
+                                       B43_NPHY_TXF_40CO_B32S1;
+                               b43_phy_set(dev, reg, 0x0020);
+                       } else {
+                               if (type == 6)
+                                       val = 0x0100;
+                               else if (type == 3)
+                                       val = 0x0200;
+                               else
+                                       val = 0x0300;
+
+                               reg = (i == 0) ?
+                                       B43_NPHY_AFECTL_C1 :
+                                       B43_NPHY_AFECTL_C2;
+
+                               b43_phy_maskset(dev, reg, 0xFCFF, val);
+                               b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
+
+                               if (type != 3 && type != 6) {
+                                       enum ieee80211_band band =
+                                               b43_current_band(dev->wl);
+
+                                       if ((nphy->ipa2g_on &&
+                                               band == IEEE80211_BAND_2GHZ) ||
+                                               (nphy->ipa5g_on &&
+                                               band == IEEE80211_BAND_5GHZ))
+                                               val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
+                                       else
+                                               val = 0x11;
+                                       reg = (i == 0) ? 0x2000 : 0x3000;
+                                       reg |= B2055_PADDRV;
+                                       b43_radio_write16(dev, reg, val);
+
+                                       reg = (i == 0) ?
+                                               B43_NPHY_AFECTL_OVER1 :
+                                               B43_NPHY_AFECTL_OVER;
+                                       b43_phy_set(dev, reg, 0x0200);
+                               }
                        }
                }
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
+static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+       if (dev->phy.rev >= 3)
+               b43_nphy_rev3_rssi_select(dev, code, type);
+       else
+               b43_nphy_rev2_rssi_select(dev, code, type);
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
 static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
 {
@@ -1239,9 +1830,60 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
        u16 *save = nphy->tx_rx_cal_radio_saveregs;
+       u16 tmp;
+       u8 offset, i;
 
        if (dev->phy.rev >= 3) {
-               /* TODO */
+           for (i = 0; i < 2; i++) {
+               tmp = (i == 0) ? 0x2000 : 0x3000;
+               offset = i * 11;
+
+               save[offset + 0] = b43_radio_read16(dev, B2055_CAL_RVARCTL);
+               save[offset + 1] = b43_radio_read16(dev, B2055_CAL_LPOCTL);
+               save[offset + 2] = b43_radio_read16(dev, B2055_CAL_TS);
+               save[offset + 3] = b43_radio_read16(dev, B2055_CAL_RCCALRTS);
+               save[offset + 4] = b43_radio_read16(dev, B2055_CAL_RCALRTS);
+               save[offset + 5] = b43_radio_read16(dev, B2055_PADDRV);
+               save[offset + 6] = b43_radio_read16(dev, B2055_XOCTL1);
+               save[offset + 7] = b43_radio_read16(dev, B2055_XOCTL2);
+               save[offset + 8] = b43_radio_read16(dev, B2055_XOREGUL);
+               save[offset + 9] = b43_radio_read16(dev, B2055_XOMISC);
+               save[offset + 10] = b43_radio_read16(dev, B2055_PLL_LFC1);
+
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                       b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x0A);
+                       b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+                       b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
+                       b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
+                       b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
+                       if (nphy->ipa5g_on) {
+                               b43_radio_write16(dev, tmp | B2055_PADDRV, 4);
+                               b43_radio_write16(dev, tmp | B2055_XOCTL1, 1);
+                       } else {
+                               b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
+                               b43_radio_write16(dev, tmp | B2055_XOCTL1, 0x2F);
+                       }
+                       b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+               } else {
+                       b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x06);
+                       b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+                       b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
+                       b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
+                       b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
+                       b43_radio_write16(dev, tmp | B2055_XOCTL1, 0);
+                       if (nphy->ipa2g_on) {
+                               b43_radio_write16(dev, tmp | B2055_PADDRV, 6);
+                               b43_radio_write16(dev, tmp | B2055_XOCTL2,
+                                       (dev->phy.rev < 5) ? 0x11 : 0x01);
+                       } else {
+                               b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
+                               b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+                       }
+               }
+               b43_radio_write16(dev, tmp | B2055_XOREGUL, 0);
+               b43_radio_write16(dev, tmp | B2055_XOMISC, 0);
+               b43_radio_write16(dev, tmp | B2055_PLL_LFC1, 0);
+           }
        } else {
                save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1);
                b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29);
@@ -1330,16 +1972,51 @@ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
        for (i = 0; i < 18; i++) {
                scale = (ladder_lo[i].percent * tmp) / 100;
                entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env;
-               /* TODO: Write an N PHY Table with ID 15, length 1,
-                       offset i, width 16, and data entry */
+               b43_ntab_write(dev, B43_NTAB16(15, i), entry);
 
                scale = (ladder_iq[i].percent * tmp) / 100;
                entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env;
-               /* TODO: Write an N PHY Table with ID 15, length 1,
-                       offset i + 32, width 16, and data entry */
+               b43_ntab_write(dev, B43_NTAB16(15, i + 32), entry);
        }
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */
+static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+       int i;
+       for (i = 0; i < 15; i++)
+               b43_phy_write(dev, B43_PHY_N(0x2C5 + i),
+                               tbl_tx_filter_coef_rev4[2][i]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */
+static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev)
+{
+       int i, j;
+       /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */
+       u16 offset[] = { 0x186, 0x195, 0x2C5 };
+
+       for (i = 0; i < 3; i++)
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[i] + j),
+                                       tbl_tx_filter_coef_rev4[i][j]);
+
+       if (dev->phy.is_40mhz) {
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[3][j]);
+       } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[5][j]);
+       }
+
+       if (dev->phy.channel == 14)
+               for (j = 0; j < 15; j++)
+                       b43_phy_write(dev, B43_PHY_N(offset[0] + j),
+                                       tbl_tx_filter_coef_rev4[6][j]);
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
 static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
 {
@@ -1354,8 +2031,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
 
                if (nphy->hang_avoid)
                        b43_nphy_stay_in_carrier_search(dev, true);
-               /* TODO: Read an N PHY Table with ID 7, length 2,
-                       offset 0x110, width 16, and curr_gain */
+               b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, curr_gain);
                if (nphy->hang_avoid)
                        b43_nphy_stay_in_carrier_search(dev, false);
 
@@ -1423,6 +2099,101 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
        return target;
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */
+static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev)
+{
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+
+       if (dev->phy.rev >= 3) {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[0]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[3]);
+               b43_phy_write(dev, B43_NPHY_BBCFG, regs[4]);
+               b43_ntab_write(dev, B43_NTAB16(8, 3), regs[5]);
+               b43_ntab_write(dev, B43_NTAB16(8, 19), regs[6]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[7]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[8]);
+               b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
+               b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+               b43_nphy_reset_cca(dev);
+       } else {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, regs[0]);
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
+               b43_ntab_write(dev, B43_NTAB16(8, 2), regs[3]);
+               b43_ntab_write(dev, B43_NTAB16(8, 18), regs[4]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[5]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[6]);
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */
+static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
+{
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+       u16 tmp;
+
+       regs[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+       regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+       if (dev->phy.rev >= 3) {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0xF0FF, 0x0A00);
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0xF0FF, 0x0A00);
+
+               tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+               regs[2] = tmp;
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, tmp | 0x0600);
+
+               tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               regs[3] = tmp;
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x0600);
+
+               regs[4] = b43_phy_read(dev, B43_NPHY_BBCFG);
+               b43_phy_mask(dev, B43_NPHY_BBCFG, (u16)~B43_NPHY_BBCFG_RSTRX);
+
+               tmp = b43_ntab_read(dev, B43_NTAB16(8, 3));
+               regs[5] = tmp;
+               b43_ntab_write(dev, B43_NTAB16(8, 3), 0);
+
+               tmp = b43_ntab_read(dev, B43_NTAB16(8, 19));
+               regs[6] = tmp;
+               b43_ntab_write(dev, B43_NTAB16(8, 19), 0);
+               regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+               regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+
+               /* TODO: Call N PHY RF Ctrl Intc Override with 2, 1, 3 */
+               /* TODO: Call N PHY RF Ctrl Intc Override with 1, 2, 1 */
+               /* TODO: Call N PHY RF Ctrl Intc Override with 1, 8, 2 */
+
+               regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
+               regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
+               b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
+               b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+       } else {
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, 0xA000);
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, 0xA000);
+               tmp = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               regs[2] = tmp;
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp | 0x3000);
+               tmp = b43_ntab_read(dev, B43_NTAB16(8, 2));
+               regs[3] = tmp;
+               tmp |= 0x2000;
+               b43_ntab_write(dev, B43_NTAB16(8, 2), tmp);
+               tmp = b43_ntab_read(dev, B43_NTAB16(8, 18));
+               regs[4] = tmp;
+               tmp |= 0x2000;
+               b43_ntab_write(dev, B43_NTAB16(8, 18), tmp);
+               regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+               regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+                       tmp = 0x0180;
+               else
+                       tmp = 0x0120;
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
+       }
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */
 static void b43_nphy_restore_cal(struct b43_wldev *dev)
 {
@@ -1448,8 +2219,7 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev)
                loft = &nphy->cal_cache.txcal_coeffs_5G[5];
        }
 
-       /* TODO: Write an N PHY table with ID 15, length 4, offset 80,
-               width 16, and data from table */
+       b43_ntab_write_bulk(dev, B43_NTAB16(15, 80), 4, table);
 
        for (i = 0; i < 4; i++) {
                if (dev->phy.rev >= 3)
@@ -1458,12 +2228,9 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev)
                        coef[i] = 0;
        }
 
-       /* TODO: Write an N PHY table with ID 15, length 4, offset 88,
-               width 16, and data from coef */
-       /* TODO: Write an N PHY table with ID 15, length 2, offset 85,
-               width 16 and data from loft */
-       /* TODO: Write an N PHY table with ID 15, length 2, offset 93,
-               width 16 and data from loft */
+       b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4, coef);
+       b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2, loft);
+       b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2, loft);
 
        if (dev->phy.rev < 2)
                b43_nphy_tx_iq_workaround(dev);
@@ -1524,39 +2291,47 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                nphy->hang_avoid = 0;
        }
 
-       /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data pointer save */
+       b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
 
        for (i = 0; i < 2; i++) {
                b43_nphy_iq_cal_gain_params(dev, i, target, &params[i]);
                gain[i] = params[i].cal_gain;
        }
-       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data pointer gain */
+
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain);
 
        b43_nphy_tx_cal_radio_setup(dev);
-       /* TODO: Call N PHY TX Cal PHY Setup */
+       b43_nphy_tx_cal_phy_setup(dev);
 
        phy6or5x = dev->phy.rev >= 6 ||
                (dev->phy.rev == 5 && nphy->ipa2g_on &&
                b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ);
        if (phy6or5x) {
-               /* TODO */
+               if (dev->phy.is_40mhz) {
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
+                                       tbl_tx_iqlo_cal_loft_ladder_40);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18,
+                                       tbl_tx_iqlo_cal_iqimb_ladder_40);
+               } else {
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 0), 18,
+                                       tbl_tx_iqlo_cal_loft_ladder_20);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 32), 18,
+                                       tbl_tx_iqlo_cal_iqimb_ladder_20);
+               }
        }
 
        b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
 
-       if (1 /* FIXME: the band width is 20 MHz */)
+       if (!dev->phy.is_40mhz)
                freq = 2500;
        else
                freq = 5000;
 
        if (nphy->mphase_cal_phase_id > 2)
-               ;/* TODO: Call N PHY Run Samples with (band width * 8),
-                       0xFFFF, 0, 1, 0 as arguments */
+               b43_nphy_run_samples(dev, (dev->phy.is_40mhz ? 40 : 20) * 8,
+                                       0xFFFF, 0, true, false);
        else
-               ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments
-                       and save result as error */
+               error = b43_nphy_tx_tone(dev, freq, 250, true, false);
 
        if (error == 0) {
                if (nphy->mphase_cal_phase_id > 2) {
@@ -1582,8 +2357,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        }
                }
 
-               /* TODO: Write an N PHY Table with ID 15, length from above,
-                       offset 64, width 16, and the data pointer from above */
+               b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length, table);
 
                if (full) {
                        if (dev->phy.rev >= 3)
@@ -1631,14 +2405,12 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp);
 
                        if (type == 1 || type == 3 || type == 4) {
-                               /* TODO: Read an N PHY Table with ID 15,
-                                       length 1, offset 69 + core,
-                                       width 16, and data pointer buffer */
+                               buffer[0] = b43_ntab_read(dev,
+                                               B43_NTAB16(15, 69 + core));
                                diq_start = buffer[0];
                                buffer[0] = 0;
-                               /* TODO: Write an N PHY Table with ID 15,
-                                       length 1, offset 69 + core, width 16,
-                                       and data of 0 */
+                               b43_ntab_write(dev, B43_NTAB16(15, 69 + core),
+                                               0);
                        }
 
                        b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd);
@@ -1649,12 +2421,10 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                                udelay(10);
                        }
 
-                       /* TODO: Read an N PHY Table with ID 15,
-                               length table_length, offset 96, width 16,
-                               and data pointer buffer */
-                       /* TODO: Write an N PHY Table with ID 15,
-                               length table_length, offset 64, width 16,
-                               and data pointer buffer */
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+                                               buffer);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 64), length,
+                                               buffer);
 
                        if (type == 1 || type == 3 || type == 4)
                                buffer[0] = diq_start;
@@ -1666,30 +2436,27 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                last = (dev->phy.rev < 3) ? 6 : 7;
 
                if (!mphase || nphy->mphase_cal_phase_id == last) {
-                       /* TODO: Write an N PHY Table with ID 15, length 4,
-                               offset 96, width 16, and data pointer buffer */
-                       /* TODO: Read an N PHY Table with ID 15, length 4,
-                               offset 80, width 16, and data pointer buffer */
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 96), 4, buffer);
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 4, buffer);
                        if (dev->phy.rev < 3) {
                                buffer[0] = 0;
                                buffer[1] = 0;
                                buffer[2] = 0;
                                buffer[3] = 0;
                        }
-                       /* TODO: Write an N PHY Table with ID 15, length 4,
-                               offset 88, width 16, and data pointer buffer */
-                       /* TODO: Read an N PHY Table with ID 15, length 2,
-                               offset 101, width 16, and data pointer buffer*/
-                       /* TODO: Write an N PHY Table with ID 15, length 2,
-                               offset 85, width 16, and data pointer buffer */
-                       /* TODO: Write an N PHY Table with ID 15, length 2,
-                               offset 93, width 16, and data pointer buffer */
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
+                                               buffer);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2,
+                                               buffer);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
+                                               buffer);
+                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 93), 2,
+                                               buffer);
                        length = 11;
                        if (dev->phy.rev < 3)
                                length -= 2;
-                       /* TODO: Read an N PHY Table with ID 15, length length,
-                               offset 96, width 16, and data pointer
-                               nphy->txiqlocal_bestc */
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+                                               nphy->txiqlocal_bestc);
                        nphy->txiqlocal_coeffsvalid = true;
                        /* TODO: Set nphy->txiqlocal_chanspec to
                                the current channel */
@@ -1697,18 +2464,16 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        length = 11;
                        if (dev->phy.rev < 3)
                                length -= 2;
-                       /* TODO: Read an N PHY Table with ID 5, length length,
-                               offset 96, width 16, and data pointer
-                               nphy->mphase_txcal_bestcoeffs */
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
+                                               nphy->mphase_txcal_bestcoeffs);
                }
 
-               /* TODO: Call N PHY Stop Playback */
+               b43_nphy_stop_playback(dev);
                b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0);
        }
 
-       /* TODO: Call N PHY TX Cal PHY Cleanup */
-       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data from save */
+       b43_nphy_tx_cal_phy_cleanup(dev);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
 
        if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last))
                b43_nphy_tx_iq_workaround(dev);
@@ -1739,7 +2504,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
        u16 lna[3] = { 3, 3, 1 };
        u16 hpf1[3] = { 7, 2, 0 };
        u16 hpf2[3] = { 2, 0, 0 };
-       u32 power[3];
+       u32 power[3] = { };
        u16 gain_save[2];
        u16 cal_gain[2];
        struct nphy_iqcal_params cal_params[2];
@@ -1752,14 +2517,12 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
 
        if (dev->phy.rev < 2)
                ;/* TODO: Call N PHY Reapply TX Cal Coeffs */
-       /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data gain_save */
+       b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
        for (i = 0; i < 2; i++) {
                b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]);
                cal_gain[i] = cal_params[i].cal_gain;
        }
-       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data from cal_gain */
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, cal_gain);
 
        for (i = 0; i < 2; i++) {
                if (i == 0) {
@@ -1846,19 +2609,19 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
 
                        tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
                                        (cur_lna << 2));
-                       /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0],
-                               3, 0 as arguments */
-                       /* TODO: Call N PHY Force RF Seq with 2 as argument */
-                       /* TODO: Call N PHT Stop Playback */
+                       b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3,
+                                                                       false);
+                       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+                       b43_nphy_stop_playback(dev);
 
                        if (playtone) {
-                               /* TODO: Call N PHY TX Tone with 4000,
-                                       (nphy_rxcalparams & 0xffff), 0, 0
-                                       as arguments and save result as ret */
+                               ret = b43_nphy_tx_tone(dev, 4000,
+                                               (nphy->rxcalparams & 0xFFFF),
+                                               false, false);
                                playtone = false;
                        } else {
-                               /* TODO: Call N PHY Run Samples with 160,
-                                       0xFFFF, 0, 0, 0 as arguments */
+                               b43_nphy_run_samples(dev, 160, 0xFFFF, 0,
+                                                       false, false);
                        }
 
                        if (ret == 0) {
@@ -1876,7 +2639,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
                                } else {
                                        b43_nphy_calc_rx_iq_comp(dev, 1 << i);
                                }
-                               /* TODO: Call N PHY Stop Playback */
+                               b43_nphy_stop_playback(dev);
                        }
 
                        if (ret != 0)
@@ -1895,10 +2658,9 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
                        break;
        }
 
-       /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/
-       /* TODO: Call N PHY Force RF Seq with 2 as argument */
-       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
-               width 16, and data from gain_save */
+       b43_nphy_rf_control_override(dev, 0x400, 0, 3, true);
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
 
        b43_nphy_stay_in_carrier_search(dev, 0);
 
@@ -1990,8 +2752,8 @@ int b43_phy_initn(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
        b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
 
-       /* TODO MIMO-Config */
-       /* TODO Update TX/RX chain */
+       b43_nphy_update_mimo_config(dev, nphy->preamble_override);
+       b43_nphy_update_txrx_chain(dev);
 
        if (phy->rev < 2) {
                b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
@@ -2007,9 +2769,9 @@ int b43_phy_initn(struct b43_wldev *dev)
                b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
                b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
                                nphy->papd_epsilon_offset[1] << 7);
-               /* TODO N PHY IPA Set TX Dig Filters */
+               b43_nphy_int_pa_set_tx_dig_filters(dev);
        } else if (phy->rev >= 5) {
-               /* TODO N PHY Ext PA Set TX Dig Filters */
+               b43_nphy_ext_pa_set_tx_dig_filters(dev);
        }
 
        b43_nphy_workarounds(dev);
@@ -2040,8 +2802,10 @@ int b43_phy_initn(struct b43_wldev *dev)
        if (phy->rev >= 3) {
                /* TODO */
        } else {
-               /* TODO Write an N PHY table with ID 26, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */
-               /* TODO Write an N PHY table with ID 27, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */
+               b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128,
+                                       b43_ntab_tx_gain_rev0_1_2);
+               b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128,
+                                       b43_ntab_tx_gain_rev0_1_2);
        }
 
        if (nphy->phyrxchain != 3)
index 4572866756fc9f6b0f899356c28877659edd2ee7..ae82f0fc2096671710373e9c3a903c492ea53477 100644 (file)
@@ -973,6 +973,12 @@ struct b43_phy_n {
        bool hang_avoid;
        bool mute;
        u16 papd_epsilon_offset[2];
+       s32 preamble_override;
+       u32 bb_mult_save;
+
+       bool gain_boost;
+       bool elna_gain_config;
+       bool band5g_pwrgain;
 
        u8 mphase_cal_phase_id;
        u16 mphase_txcal_cmdidx;
@@ -985,6 +991,7 @@ struct b43_phy_n {
        bool txiqlocal_coeffsvalid;
        struct b43_phy_n_txpwrindex txpwrindex[2];
 
+       u8 txrx_chain;
        u16 tx_rx_cal_phy_saveregs[11];
        u16 tx_rx_cal_radio_saveregs[22];
 
index 7dff853ab9624f988e10316d8d64153b1d0cba2e..a00d509150f77082f741fa18ff6c7f3e4d0bc1d4 100644 (file)
@@ -2883,6 +2883,67 @@ const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
        0x9084, 0x9267, 0x9056, 0x9234
 };
 
+const s16 tbl_tx_filter_coef_rev4[7][15] = {
+       {  -377,   137,  -407,   208, -1527,
+           956,    93,   186,    93,   230,
+           -44,   230,    20,  -191,   201 },
+       {   -77,    20,   -98,    49,   -93,
+            60,    56,   111,    56,    26,
+            -5,    26,    34,   -32,    34 },
+       {  -360,   164,  -376,   164, -1533,
+           576,   308,  -314,   308,   121,
+           -73,   121,    91,   124,    91 },
+       {  -295,   200,  -363,   142, -1391,
+           826,   151,   301,   151,   151,
+           301,   151,   602,  -752,   602 },
+       {   -92,    58,   -96,    49,  -104,
+            44,    17,    35,    17,    12,
+            25,    12,    13,    27,    13 },
+       {  -375,   136,  -399,   209, -1479,
+           949,   130,   260,   130,   230,
+           -44,   230,   201,  -191,   201 },
+       { 0xed9,  0xc8, 0xe95,  0x8e, 0xa91,
+         0x33a,  0x97, 0x12d,  0x97,  0x97,
+         0x12d,  0x97, 0x25a, 0xd10, 0x25a }
+};
+
+/* addr0,  addr1,  bmask,  shift */
+const struct nphy_rf_control_override_rev2 tbl_rf_control_override_rev2[] = {
+       { 0x78, 0x78, 0x0038,  3 }, /* for field == 0x0002 (fls == 2) */
+       { 0x7A, 0x7D, 0x0001,  0 }, /* for field == 0x0004 (fls == 3) */
+       { 0x7A, 0x7D, 0x0002,  1 }, /* for field == 0x0008 (fls == 4) */
+       { 0x7A, 0x7D, 0x0004,  2 }, /* for field == 0x0010 (fls == 5) */
+       { 0x7A, 0x7D, 0x0030,  4 }, /* for field == 0x0020 (fls == 6) */
+       { 0x7A, 0x7D, 0x00C0,  6 }, /* for field == 0x0040 (fls == 7) */
+       { 0x7A, 0x7D, 0x0100,  8 }, /* for field == 0x0080 (fls == 8) */
+       { 0x7A, 0x7D, 0x0200,  9 }, /* for field == 0x0100 (fls == 9) */
+       { 0x78, 0x78, 0x0004,  2 }, /* for field == 0x0200 (fls == 10) */
+       { 0x7B, 0x7E, 0x01FF,  0 }, /* for field == 0x0400 (fls == 11) */
+       { 0x7C, 0x7F, 0x01FF,  0 }, /* for field == 0x0800 (fls == 12) */
+       { 0x78, 0x78, 0x0100,  8 }, /* for field == 0x1000 (fls == 13) */
+       { 0x78, 0x78, 0x0200,  9 }, /* for field == 0x2000 (fls == 14) */
+       { 0x78, 0x78, 0xF000, 12 }  /* for field == 0x4000 (fls == 15) */
+};
+
+/* val_mask, val_shift, en_addr0, val_addr0, en_addr1, val_addr1 */
+const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
+       { 0x8000, 15, 0xE5, 0xF9, 0xE6, 0xFB }, /* field == 0x0001 (fls 1) */
+       { 0x0001,  0, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0002 (fls 2) */
+       { 0x0002,  1, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0004 (fls 3) */
+       { 0x0004,  2, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0008 (fls 4) */
+       { 0x0016,  4, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0010 (fls 5) */
+       { 0x0020,  5, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0020 (fls 6) */
+       { 0x0040,  6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0040 (fls 7) */
+       { 0x0080,  6, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0080 (fls 8) */
+       { 0x0100,  7, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0100 (fls 9) */
+       { 0x0007,  0, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0200 (fls 10) */
+       { 0x0070,  4, 0xE7, 0xF8, 0xEC, 0xFA }, /* field == 0x0400 (fls 11) */
+       { 0xE000, 13, 0xE7, 0x7A, 0xEC, 0x7D }, /* field == 0x0800 (fls 12) */
+       { 0xFFFF,  0, 0xE7, 0x7B, 0xEC, 0x7E }, /* field == 0x1000 (fls 13) */
+       { 0xFFFF,  0, 0xE7, 0x7C, 0xEC, 0x7F }, /* field == 0x2000 (fls 14) */
+       { 0x00C0,  6, 0xE7, 0xF9, 0xEC, 0xFB }  /* field == 0x4000 (fls 15) */
+};
+
 static inline void assert_ntab_array_sizes(void)
 {
 #undef check
@@ -2919,6 +2980,72 @@ static inline void assert_ntab_array_sizes(void)
 #undef check
 }
 
+u32 b43_ntab_read(struct b43_wldev *dev, u32 offset)
+{
+       u32 type, value;
+
+       type = offset & B43_NTAB_TYPEMASK;
+       offset &= ~B43_NTAB_TYPEMASK;
+       B43_WARN_ON(offset > 0xFFFF);
+
+       switch (type) {
+       case B43_NTAB_8BIT:
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF;
+               break;
+       case B43_NTAB_16BIT:
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               value = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+               break;
+       case B43_NTAB_32BIT:
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+               value = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI);
+               value <<= 16;
+               value |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+               break;
+       default:
+               B43_WARN_ON(1);
+               value = 0;
+       }
+
+       return value;
+}
+
+void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset,
+                        unsigned int nr_elements, void *_data)
+{
+       u32 type;
+       u8 *data = _data;
+       unsigned int i;
+
+       type = offset & B43_NTAB_TYPEMASK;
+       offset &= ~B43_NTAB_TYPEMASK;
+       B43_WARN_ON(offset > 0xFFFF);
+
+       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+
+       for (i = 0; i < nr_elements; i++) {
+               switch (type) {
+               case B43_NTAB_8BIT:
+                       *data = b43_phy_read(dev, B43_NPHY_TABLE_DATALO) & 0xFF;
+                       data++;
+                       break;
+               case B43_NTAB_16BIT:
+                       *((u16 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+                       data += 2;
+                       break;
+               case B43_NTAB_32BIT:
+                       *((u32 *)data) = b43_phy_read(dev, B43_NPHY_TABLE_DATAHI);
+                       *((u32 *)data) <<= 16;
+                       *((u32 *)data) |= b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+                       data += 4;
+                       break;
+               default:
+                       B43_WARN_ON(1);
+               }
+       }
+}
+
 void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
 {
        u32 type;
@@ -2952,6 +3079,46 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
        assert_ntab_array_sizes();
 }
 
+void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
+                         unsigned int nr_elements, const void *_data)
+{
+       u32 type, value;
+       const u8 *data = _data;
+       unsigned int i;
+
+       type = offset & B43_NTAB_TYPEMASK;
+       offset &= ~B43_NTAB_TYPEMASK;
+       B43_WARN_ON(offset > 0xFFFF);
+
+       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+
+       for (i = 0; i < nr_elements; i++) {
+               switch (type) {
+               case B43_NTAB_8BIT:
+                       value = *data;
+                       data++;
+                       B43_WARN_ON(value & ~0xFF);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+                       break;
+               case B43_NTAB_16BIT:
+                       value = *((u16 *)data);
+                       data += 2;
+                       B43_WARN_ON(value & ~0xFFFF);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+                       break;
+               case B43_NTAB_32BIT:
+                       value = *((u32 *)data);
+                       data += 4;
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16);
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       value & 0xFFFF);
+                       break;
+               default:
+                       B43_WARN_ON(1);
+               }
+       }
+}
+
 #define ntab_upload(dev, offset, data) do { \
                unsigned int i;                                         \
                for (i = 0; i < (offset##_SIZE); i++)                   \
index 51636d02f8b131b3bb42b58b00c3d032bbf5df8a..9c1c6ecd36725f9475f3d781ea46472b7f02a7e6 100644 (file)
@@ -51,6 +51,22 @@ struct nphy_txiqcal_ladder {
        u8 g_env;
 };
 
+struct nphy_rf_control_override_rev2 {
+       u8 addr0;
+       u8 addr1;
+       u16 bmask;
+       u8 shift;
+};
+
+struct nphy_rf_control_override_rev3 {
+       u16 val_mask;
+       u8 val_shift;
+       u8 en_addr0;
+       u8 val_addr0;
+       u8 en_addr1;
+       u8 val_addr1;
+};
+
 /* Upload the default register value table.
  * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
  * table is uploaded. If "ignore_uploadflag" is true, we upload any value
@@ -142,7 +158,12 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
 #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL              10
 #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3         12
 
+u32 b43_ntab_read(struct b43_wldev *dev, u32 offset);
+void b43_ntab_read_bulk(struct b43_wldev *dev, u32 offset,
+                        unsigned int nr_elements, void *_data);
 void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
+                         unsigned int nr_elements, const void *_data);
 
 void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev);
 void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev);
@@ -172,5 +193,11 @@ extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[];
 extern const u16 tbl_tx_iqlo_cal_cmds_recal[];
 extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[];
 extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[];
+extern const s16 tbl_tx_filter_coef_rev4[7][15];
+
+extern const struct nphy_rf_control_override_rev2
+       tbl_rf_control_override_rev2[];
+extern const struct nphy_rf_control_override_rev3
+       tbl_rf_control_override_rev3[];
 
 #endif /* B43_TABLES_NPHY_H_ */
index b16b06c2031f991e2e93386fcf634fb5070e5736..dc8ed15276667f1abb3ce7b311789a592d2c7ee3 100644 (file)
@@ -1,14 +1,8 @@
 config IWLWIFI
        tristate "Intel Wireless Wifi"
-       depends on PCI && MAC80211 && EXPERIMENTAL
+       depends on PCI && MAC80211
        select FW_LOADER
 
-config IWLWIFI_SPECTRUM_MEASUREMENT
-       bool "Enable Spectrum Measurement in iwlagn driver"
-       depends on IWLWIFI
-       ---help---
-         This option will enable spectrum measurement for the iwlagn driver.
-
 config IWLWIFI_DEBUG
        bool "Enable full debugging output in iwlagn and iwl3945 drivers"
        depends on IWLWIFI
@@ -120,9 +114,3 @@ config IWL3945
          inserted in and removed from the running kernel whenever you want),
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
          module will be called iwl3945.
-
-config IWL3945_SPECTRUM_MEASUREMENT
-       bool "Enable Spectrum Measurement in iwl3945 driver"
-       depends on IWL3945
-       ---help---
-         This option will enable spectrum measurement for the iwl3945 driver.
index 7f82044af24213155c8a42867c6bdd8fe8952302..4e378faee6505f710d69c6309e24c9cf66a7c36a 100644 (file)
@@ -3,7 +3,6 @@ iwlcore-objs            := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
 iwlcore-objs           += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
 iwlcore-objs           += iwl-scan.o iwl-led.o
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
-iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
 iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
 
 CFLAGS_iwl-devtrace.o := -I$(src)
@@ -20,3 +19,5 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
 # 3945
 obj-$(CONFIG_IWL3945)  += iwl3945.o
 iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index 0db1fda94a6574805c786b455c03c6bdbfc6efba..9d1820676f3026f75550ad4620b22dea8b6b9072 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008-2009 Intel Corporation. All rights reserved.
+ * 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
@@ -89,8 +89,78 @@ static void iwl1000_nic_config(struct iwl_priv *priv)
                                ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
 }
 
+static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
+       .min_nrg_cck = 95,
+       .max_nrg_cck = 0, /* not used, set to 0 */
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 120,
+       .auto_corr_min_ofdm_mrc_x1 = 240,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       .auto_corr_max_ofdm_x1 = 155,
+       .auto_corr_max_ofdm_mrc_x1 = 290,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .auto_corr_max_cck_mrc = 400,
+       .nrg_th_cck = 95,
+       .nrg_th_ofdm = 95,
+
+       .barker_corr_th_min = 190,
+       .barker_corr_th_min_mrc = 390,
+       .nrg_th_cca = 62,
+};
+
+static 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->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
+
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+       priv->hw_params.scd_bc_tbls_size =
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwl5000_scd_bc_tbl);
+       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+
+       priv->hw_params.max_bsm_size = 0;
+       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
+                                       BIT(IEEE80211_BAND_5GHZ);
+       priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
+
+       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+       /* Set initial sensitivity parameters */
+       /* Set initial calibration set */
+       priv->hw_params.sens = &iwl1000_sensitivity;
+       priv->hw_params.calib_init_cfg =
+                       BIT(IWL_CALIB_XTAL)             |
+                       BIT(IWL_CALIB_LO)               |
+                       BIT(IWL_CALIB_TX_IQ)            |
+                       BIT(IWL_CALIB_TX_IQ_PERD)       |
+                       BIT(IWL_CALIB_BASE_BAND);
+
+       return 0;
+}
+
 static struct iwl_lib_ops iwl1000_lib = {
-       .set_hw_params = iwl5000_hw_set_hw_params,
+       .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,
@@ -106,6 +176,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .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,
@@ -139,6 +210,7 @@ static struct iwl_lib_ops iwl1000_lib = {
                .temperature = iwl5000_temperature,
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
+       .add_bcast_station = iwl_add_bcast_station,
 };
 
 static const struct iwl_ops iwl1000_ops = {
@@ -174,6 +246,7 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
@@ -200,6 +273,7 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
index 08ce259a0e60a9aaefc449e9e5b11687c92eef5a..042f6bc0df133a466548902fd11ff367ef180159 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6fd10d443ba3eadefb46e495f599a0827ce32e91..3a876a8ece388a73eaf824d4baa31836e155c131 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a871d09d598f2e57f05dddf8f4f6aae0a2668c66..abe2b739c4dc33eb4dea2565bfd36b11e4801196 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index 5a1033ca7aaab32a80de45076d6af74e8e3579a4..ce990adc51e7ce9bb34709e488798365eafaeb2b 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index d4b49883b30ea5c7e307fd78ad7492b584b203dd..47909f94271e1d41ac73a7c90921f6906b2d45ba 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
index 6cde661ce0bcb52be05315cf239c08b2b0cb94cf..6940f086823c97b825d2f1c1cb904dfab52a1619 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
@@ -1951,11 +1951,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        }
 
        /* Add the broadcast address so we can send broadcast frames */
-       if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) ==
-           IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
-               return -EIO;
-       }
+       priv->cfg->ops->lib->add_bcast_station(priv);
 
        /* If we have set the ASSOC_MSK and we are in BSS mode then
         * add the IWL_AP_ID to the station rate table */
@@ -2796,6 +2792,7 @@ static struct iwl_lib_ops iwl3945_lib = {
        .post_associate = iwl3945_post_associate,
        .isr = iwl_isr_legacy,
        .config_ap = iwl3945_config_ap,
+       .add_bcast_station = iwl3945_add_bcast_station,
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
@@ -2830,6 +2827,7 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2847,6 +2845,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
index bc532ff4f88376fdb25af0a05146b6f046f339bf..8f553f36d2704e0eeac919544b279cc6d1f59f62 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index c606366b582ce81176afa4415c1ff92eae32a7c0..67ef562e8db164694fb13ef5fe6e6c7f939dcbef 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6a004abb5973205d241b8a8ca47d6979aca9402b..aebe8c51d3e18d308e25de8b36ba60d92280009c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
@@ -2206,6 +2206,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .temperature = iwl4965_temperature_calib,
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
+       .add_bcast_station = iwl_add_bcast_station,
 };
 
 static const struct iwl_ops iwl4965_ops = {
@@ -2239,6 +2240,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 /* Module firmware */
index bc056e9ab85f0e38f73f60614462f8d36236fa73..714e032f6217138ad0152e9398c924326e54c11c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c6120f0b8f98d0aabf48e4439501e099938e7c5f..6d59889013419ad90f77316f2c7c4cabe70b45b8 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -263,8 +263,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
 
        .auto_corr_max_ofdm = 120,
        .auto_corr_max_ofdm_mrc = 210,
-       .auto_corr_max_ofdm_x1 = 155,
-       .auto_corr_max_ofdm_mrc_x1 = 290,
+       .auto_corr_max_ofdm_x1 = 120,
+       .auto_corr_max_ofdm_mrc_x1 = 240,
 
        .auto_corr_min_cck = 125,
        .auto_corr_max_cck = 200,
@@ -412,12 +412,14 @@ static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
 /*
  * ucode
  */
-static int iwl5000_load_section(struct iwl_priv *priv,
-                               struct fw_desc *image,
-                               u32 dst_addr)
+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),
@@ -447,57 +449,36 @@ static int iwl5000_load_section(struct iwl_priv *priv,
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-       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_image,
-                                  IWL50_RTC_INST_LOWER_BOUND);
-       if (ret)
-               return ret;
-
-       IWL_DEBUG_INFO(priv, "INST uCode section being loaded...\n");
+       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 INST uCode section due "
-                       "to interrupt\n");
+               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 INST uCode section\n");
+               IWL_ERR(priv, "Could not load the %s uCode section\n",
+                       name);
                return -ETIMEDOUT;
        }
 
-       priv->ucode_write_complete = 0;
-
-       ret = iwl5000_load_section(
-               priv, data_image, IWL50_RTC_DATA_LOWER_BOUND);
-       if (ret)
-               return ret;
+       return 0;
+}
 
-       IWL_DEBUG_INFO(priv, "DATA uCode section being loaded...\n");
+static int iwl5000_load_given_ucode(struct iwl_priv *priv,
+               struct fw_desc *inst_image,
+               struct fw_desc *data_image)
+{
+       int ret = 0;
 
-       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 INST uCode section due "
-                       "to interrupt\n");
+       ret = iwl5000_load_section(priv, "INST", inst_image,
+                                  IWL50_RTC_INST_LOWER_BOUND);
+       if (ret)
                return ret;
-       } else if (!ret) {
-               IWL_ERR(priv, "Could not load the DATA uCode section\n");
-               return -ETIMEDOUT;
-       } else
-               ret = 0;
-
-       priv->ucode_write_complete = 0;
 
-       return ret;
+       return iwl5000_load_section(priv, "DATA", data_image,
+                                   IWL50_RTC_DATA_LOWER_BOUND);
 }
 
 int iwl5000_load_ucode(struct iwl_priv *priv)
@@ -1467,6 +1448,7 @@ struct iwl_lib_ops iwl5000_lib = {
        .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,
@@ -1502,6 +1484,7 @@ struct iwl_lib_ops iwl5000_lib = {
                .temperature = iwl5000_temperature,
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
+       .add_bcast_station = iwl_add_bcast_station,
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -1555,6 +1538,7 @@ static struct iwl_lib_ops iwl5150_lib = {
                .temperature = iwl5150_temperature,
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
+       .add_bcast_station = iwl_add_bcast_station,
 };
 
 static const struct iwl_ops iwl5000_ops = {
@@ -1602,6 +1586,7 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1626,6 +1611,7 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
@@ -1648,6 +1634,7 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .use_bsm = false,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
@@ -1672,6 +1659,7 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1696,6 +1684,7 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1720,6 +1709,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
@@ -1742,6 +1732,7 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .use_bsm = false,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
index 90185777d98bcb05745edb0fa2317a0ea9c131c8..ddba39999997a05027b78b4b44f95ed302eba422 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a5a0ed4817a471562e77c9b5ab42193d0246f253..a9f8551e0e403de8d529d37f670c28a9b4d7a5aa 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008-2009 Intel Corporation. All rights reserved.
+ * 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
@@ -108,7 +108,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
 
        .auto_corr_max_ofdm = 145,
        .auto_corr_max_ofdm_mrc = 232,
-       .auto_corr_max_ofdm_x1 = 145,
+       .auto_corr_max_ofdm_x1 = 110,
        .auto_corr_max_ofdm_mrc_x1 = 232,
 
        .auto_corr_min_cck = 125,
@@ -158,11 +158,25 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        /* Set initial sensitivity parameters */
        /* Set initial calibration set */
        priv->hw_params.sens = &iwl6000_sensitivity;
-       priv->hw_params.calib_init_cfg =
+       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_6x50:
+               priv->hw_params.calib_init_cfg =
                        BIT(IWL_CALIB_XTAL)             |
+                       BIT(IWL_CALIB_DC)               |
                        BIT(IWL_CALIB_LO)               |
                        BIT(IWL_CALIB_TX_IQ)            |
                        BIT(IWL_CALIB_BASE_BAND);
+
+               break;
+       default:
+               priv->hw_params.calib_init_cfg =
+                       BIT(IWL_CALIB_XTAL)             |
+                       BIT(IWL_CALIB_LO)               |
+                       BIT(IWL_CALIB_TX_IQ)            |
+                       BIT(IWL_CALIB_BASE_BAND);
+               break;
+       }
+
        return 0;
 }
 
@@ -216,6 +230,7 @@ static struct iwl_lib_ops iwl6000_lib = {
        .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,
@@ -251,6 +266,7 @@ static struct iwl_lib_ops iwl6000_lib = {
                .temperature = iwl5000_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
         },
+       .add_bcast_station = iwl_add_bcast_station,
 };
 
 static const struct iwl_ops iwl6000_ops = {
@@ -307,6 +323,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -336,6 +353,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl6000i_2bg_cfg = {
@@ -365,6 +383,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
@@ -395,6 +414,7 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -424,6 +444,7 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
@@ -454,6 +475,7 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
index 3bccba20f6da1993ee9fdaaed4e9d8963a933033..1a24946bc2030fade543ab154558295fd9c50de4 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index ab55f92a161d80cf433dc4aebcadd28f7a7e519c..a594e4fdc6b802ecd53830bbe76781afd8261b83 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index b93e49158196b47cc7f01c5f69c7a1b7badfbd96..6aebcedaca8d677b5e0e114a247355740b757ccf 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
index affc0c5a2f2cde463339f4118b26c35d302f0bfe..e71923961e691599f663dd5e279f3d1f07a5a5c3 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
@@ -191,7 +191,7 @@ enum {
        IWL_RATE_2M_MASK)
 
 #define IWL_CCK_RATES_MASK          \
-       (IWL_BASIC_RATES_MASK      | \
+       (IWL_CCK_BASIC_RATES_MASK  | \
        IWL_RATE_5M_MASK          | \
        IWL_RATE_11M_MASK)
 
index 344e99de4cab242798693831dcd48e3afefc7519..d0268280d679e10d3ce51194124d236893d5b123 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
 #define VD
 #endif
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define DRV_VERSION     IWLWIFI_VERSION VD VS
+#define DRV_VERSION     IWLWIFI_VERSION VD
 
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -203,7 +197,8 @@ int iwl_commit_rxon(struct iwl_priv *priv)
        priv->start_calib = 0;
 
        /* Add the broadcast address so we can send broadcast frames */
-       iwl_add_bcast_station(priv);
+       priv->cfg->ops->lib->add_bcast_station(priv);
+
 
        /* If we have set the ASSOC_MSK and we are in BSS mode then
         * add the IWL_AP_ID to the station rate table */
@@ -704,7 +699,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
 }
 
-void iwl_continuous_event_trace(struct iwl_priv *priv)
+static void iwl_continuous_event_trace(struct iwl_priv *priv)
 {
        u32 capacity;   /* event log capacity in # entries */
        u32 base;       /* SRAM byte address of event log header */
@@ -888,6 +883,8 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
        priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
        priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+       priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+                       iwl_rx_spectrum_measure_notif;
        priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
        priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
            iwl_rx_pm_debug_statistics_notif;
@@ -901,7 +898,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics;
 
-       iwl_setup_spectrum_handlers(priv);
        iwl_setup_rx_scan_handlers(priv);
 
        /* status change handler */
@@ -1761,7 +1757,7 @@ static const char *desc_lookup_text[] = {
        "DEBUG_1",
        "DEBUG_2",
        "DEBUG_3",
-       "UNKNOWN"
+       "ADVANCED SYSASSERT"
 };
 
 static const char *desc_lookup(int i)
@@ -1965,7 +1961,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                IWL_ERR(priv,
                        "Invalid event log pointer 0x%08X for %s uCode\n",
                        base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
-               return pos;
+               return -EINVAL;
        }
 
        /* event log header */
@@ -2013,7 +2009,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                        bufsz = size * 48;
                *buf = kmalloc(bufsz, GFP_KERNEL);
                if (!*buf)
-                       return pos;
+                       return -ENOMEM;
        }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /*
@@ -2443,18 +2439,6 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        return;
 }
 
-static void iwl_bg_up(struct work_struct *data)
-{
-       struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-       __iwl_up(priv);
-       mutex_unlock(&priv->mutex);
-}
-
 static void iwl_bg_restart(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -2471,7 +2455,13 @@ static void iwl_bg_restart(struct work_struct *data)
                ieee80211_restart_hw(priv->hw);
        } else {
                iwl_down(priv);
-               queue_work(priv->workqueue, &priv->up);
+
+               if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       return;
+
+               mutex_lock(&priv->mutex);
+               __iwl_up(priv);
+               mutex_unlock(&priv->mutex);
        }
 }
 
@@ -2607,7 +2597,7 @@ void iwl_post_associate(struct iwl_priv *priv)
  * Not a mac80211 entry point function, but it fits in with all the
  * other mac80211 functions grouped here.
  */
-static int iwl_setup_mac(struct iwl_priv *priv)
+static int iwl_mac_setup_register(struct iwl_priv *priv)
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
@@ -2839,14 +2829,18 @@ void iwl_config_ap(struct iwl_priv *priv)
 }
 
 static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
-                       struct ieee80211_key_conf *keyconf, const u8 *addr,
-                       u32 iv32, u16 *phase1key)
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_key_conf *keyconf,
+                                   struct ieee80211_sta *sta,
+                                   u32 iv32, u16 *phase1key)
 {
 
        struct iwl_priv *priv = hw->priv;
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key);
+       iwl_update_tkip_key(priv, keyconf,
+                           sta ? sta->addr : iwl_bcast_addr,
+                           iv32, phase1key);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
@@ -3007,6 +3001,8 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
                break;
        case STA_NOTIFY_AWAKE:
                WARN_ON(!sta_priv->client);
+               if (!sta_priv->asleep)
+                       break;
                sta_priv->asleep = false;
                sta_id = iwl_find_station(priv, sta->addr);
                if (sta_id != IWL_INVALID_STATION)
@@ -3283,7 +3279,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 
        init_waitqueue_head(&priv->wait_command_queue);
 
-       INIT_WORK(&priv->up, iwl_bg_up);
        INIT_WORK(&priv->restart, iwl_bg_restart);
        INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
@@ -3368,6 +3363,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
        priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
@@ -3619,9 +3615,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        iwl_setup_deferred_work(priv);
        iwl_setup_rx_handlers(priv);
 
-       /**********************************
-        * 8. Setup and register mac80211
-        **********************************/
+       /*********************************************
+        * 8. Enable interrupts and read RFKILL state
+        *********************************************/
 
        /* enable interrupts if needed: hw bug w/a */
        pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
@@ -3632,14 +3628,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        iwl_enable_interrupts(priv);
 
-       err = iwl_setup_mac(priv);
-       if (err)
-               goto out_remove_sysfs;
-
-       err = iwl_dbgfs_register(priv, DRV_NAME);
-       if (err)
-               IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
-
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -3651,6 +3639,18 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        iwl_power_initialize(priv);
        iwl_tt_initialize(priv);
+
+       /**************************************************
+        * 9. Setup and register with mac80211 and debugfs
+        **************************************************/
+       err = iwl_mac_setup_register(priv);
+       if (err)
+               goto out_remove_sysfs;
+
+       err = iwl_dbgfs_register(priv, DRV_NAME);
+       if (err)
+               IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
+
        return 0;
 
  out_remove_sysfs:
index dc61906290e81b92852ab845b96f661858a6d2dc..845831ac053e2fa4bb320abb5024b87d4a5632b9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b6cef989a7965beb98a150d8702819d8381c4fbf..2b7b1df83ba0fe1d718aa0a67dd4ec987914c2e9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3320cce3d57b4391c1c9f17c33d732967440d3b4..c2f31eb26bef5ceb26a908b170133776a248981e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -2247,10 +2247,22 @@ struct iwl_link_quality_cmd {
        __le32 reserved2;
 } __attribute__ ((packed));
 
+/*
+ * BT configuration enable flags:
+ *   bit 0 - 1: BT channel announcement enabled
+ *           0: disable
+ *   bit 1 - 1: priority of BT device enabled
+ *           0: disable
+ *   bit 2 - 1: BT 2 wire support enabled
+ *           0: disable
+ */
+#define BT_COEX_DISABLE (0x0)
+#define BT_ENABLE_CHANNEL_ANNOUNCE BIT(0)
+#define BT_ENABLE_PRIORITY        BIT(1)
+#define BT_ENABLE_2_WIRE          BIT(2)
+
 #define BT_COEX_DISABLE (0x0)
-#define BT_COEX_MODE_2W (0x1)
-#define BT_COEX_MODE_3W (0x2)
-#define BT_COEX_MODE_4W (0x3)
+#define BT_COEX_ENABLE  (BT_ENABLE_CHANNEL_ANNOUNCE | BT_ENABLE_PRIORITY)
 
 #define BT_LEAD_TIME_MIN (0x0)
 #define BT_LEAD_TIME_DEF (0x1E)
@@ -3095,7 +3107,12 @@ struct statistics_general {
        __le32 ttl_timestamp;
        struct statistics_div div;
        __le32 rx_enable_counter;
-       __le32 reserved1;
+       /*
+        * num_of_sos_states:
+        *  count the number of times we have to re-tune
+        *  in order to get out of bad PHY status
+        */
+       __le32 num_of_sos_states;
        __le32 reserved2;
        __le32 reserved3;
 } __attribute__ ((packed));
@@ -3160,13 +3177,30 @@ struct iwl_notif_statistics {
 
 /*
  * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ *
+ * uCode send MISSED_BEACONS_NOTIFICATION to driver when detect beacon missed
+ * in regardless of how many missed beacons, which mean when driver receive the
+ * notification, inside the command, it can find all the beacons information
+ * which include number of total missed beacons, number of consecutive missed
+ * beacons, number of beacons received and number of beacons expected to
+ * receive.
+ *
+ * If uCode detected consecutive_missed_beacons > 5, it will reset the radio
+ * in order to bring the radio/PHY back to working state; which has no relation
+ * to when driver will perform sensitivity calibration.
+ *
+ * Driver should set it own missed_beacon_threshold to decide when to perform
+ * sensitivity calibration based on number of consecutive missed beacons in
+ * order to improve overall performance, especially in noisy environment.
+ *
  */
-/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
- * then this notification will be sent. */
-#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+#define IWL_MISSED_BEACON_THRESHOLD_MIN        (1)
+#define IWL_MISSED_BEACON_THRESHOLD_DEF        (5)
+#define IWL_MISSED_BEACON_THRESHOLD_MAX        IWL_MISSED_BEACON_THRESHOLD_DEF
 
 struct iwl_missed_beacon_notif {
-       __le32 consequtive_missed_beacons;
+       __le32 consecutive_missed_beacons;
        __le32 total_missed_becons;
        __le32 num_expected_beacons;
        __le32 num_recvd_beacons;
index 5b56307a3812f6bc92a66935b2e427c0404bd5ac..02bf17ecaf54c15a17d34746bf07a1a43cec4ac4 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -47,6 +47,26 @@ MODULE_VERSION(IWLWIFI_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
+/*
+ * set bt_coex_active to true, uCode will do kill/defer
+ * every time the priority line is asserted (BT is sending signals on the
+ * priority line in the PCIx).
+ * set bt_coex_active to false, uCode will ignore the BT activity and
+ * perform the normal operation
+ *
+ * User might experience transmit issue on some platform due to WiFi/BT
+ * co-exist problem. The possible behaviors are:
+ *   Able to scan and finding all the available AP
+ *   Not able to associate with any AP
+ * On those platforms, WiFi communication can be restored by set
+ * "bt_coex_active" module parameter to "false"
+ *
+ * default: bt_coex_active = true (BT_COEX_ENABLE)
+ */
+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");
+
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
         0, COEX_UNASSOC_IDLE_FLAGS},
@@ -257,8 +277,8 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
        spin_lock_irqsave(&priv->lock, flags);
        priv->cfg->ops->lib->apm_ops.init(priv);
 
-       /* Set interrupt coalescing timer to 512 usecs */
-       iwl_write8(priv, CSR_INT_COALESCING, 512 / 32);
+       /* 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);
 
@@ -1353,6 +1373,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        priv->cfg->ops->lib->dump_nic_error_log(priv);
        if (priv->cfg->ops->lib->dump_csr)
                priv->cfg->ops->lib->dump_csr(priv);
+       if (priv->cfg->ops->lib->dump_fh)
+               priv->cfg->ops->lib->dump_fh(priv, NULL, false);
        priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
@@ -1803,6 +1825,16 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        if (val == 0xffffffff)
                val = 0;
 
+       /*
+        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+        * (bit 15 before shifting it to 31) to clear when using interrupt
+        * coalescing. fortunately, bits 18 and 19 stay set when this happens
+        * so we use them to decide on the real state of the Rx bit.
+        * In order words, bit 15 is set if bit 18 or bit 19 are set.
+        */
+       if (val & 0xC0000)
+               val |= 0x8000;
+
        inta = (0xff & val) | ((0xff00 & val) << 16);
        IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
                        inta, inta_mask, val);
@@ -1965,13 +1997,20 @@ EXPORT_SYMBOL(iwl_isr_legacy);
 int iwl_send_bt_config(struct iwl_priv *priv)
 {
        struct iwl_bt_cmd bt_cmd = {
-               .flags = BT_COEX_MODE_4W,
                .lead_time = BT_LEAD_TIME_DEF,
                .max_kill = BT_MAX_KILL_DEF,
                .kill_ack_mask = 0,
                .kill_cts_mask = 0,
        };
 
+       if (!bt_coex_active)
+               bt_cmd.flags = BT_COEX_DISABLE;
+       else
+               bt_cmd.flags = BT_COEX_ENABLE;
+
+       IWL_DEBUG_INFO(priv, "BT coex %s\n",
+               (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
+
        return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
                                sizeof(struct iwl_bt_cmd), &bt_cmd);
 }
@@ -2592,23 +2631,21 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
-       unsigned long flags;
+       int err = 0;
 
        IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
 
+       mutex_lock(&priv->mutex);
+
        if (priv->vif) {
                IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
-               return -EOPNOTSUPP;
+               err = -EOPNOTSUPP;
+               goto out;
        }
 
-       spin_lock_irqsave(&priv->lock, flags);
        priv->vif = vif;
        priv->iw_mode = vif->type;
 
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       mutex_lock(&priv->mutex);
-
        if (vif->addr) {
                IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
                memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
@@ -2618,10 +2655,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
                /* we are not ready, will run again when ready */
                set_bit(STATUS_MODE_PENDING, &priv->status);
 
+ out:
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL(iwl_mac_add_interface);
 
@@ -3268,6 +3306,93 @@ void iwl_dump_csr(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_dump_csr);
 
+const static char *get_fh_string(int cmd)
+{
+       switch (cmd) {
+               IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+               IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+               IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+               IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+               IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+               IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+               IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+               IWL_CMD(FH_TSSR_TX_STATUS_REG);
+               IWL_CMD(FH_TSSR_TX_ERROR_REG);
+       default:
+               return "UNKNOWN";
+
+       }
+}
+
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
+{
+       int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       int pos = 0;
+       size_t bufsz = 0;
+#endif
+       u32 fh_tbl[] = {
+               FH_RSCSR_CHNL0_STTS_WPTR_REG,
+               FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+               FH_RSCSR_CHNL0_WPTR,
+               FH_MEM_RCSR_CHNL0_CONFIG_REG,
+               FH_MEM_RSSR_SHARED_CTRL_REG,
+               FH_MEM_RSSR_RX_STATUS_REG,
+               FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+               FH_TSSR_TX_STATUS_REG,
+               FH_TSSR_TX_ERROR_REG
+       };
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+               pos += scnprintf(*buf + pos, bufsz - pos,
+                               "FH register values:\n");
+               for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+                       pos += scnprintf(*buf + pos, bufsz - pos,
+                               "  %34s: 0X%08x\n",
+                               get_fh_string(fh_tbl[i]),
+                               iwl_read_direct32(priv, fh_tbl[i]));
+               }
+               return pos;
+       }
+#endif
+       IWL_ERR(priv, "FH register values:\n");
+       for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
+               IWL_ERR(priv, "  %34s: 0X%08x\n",
+                       get_fh_string(fh_tbl[i]),
+                       iwl_read_direct32(priv, fh_tbl[i]));
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iwl_dump_fh);
+
+void iwl_force_rf_reset(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!iwl_is_associated(priv)) {
+               IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
+               return;
+       }
+       /*
+        * There is no easy and better way to force reset the radio,
+        * the only known method is switching channel which will force to
+        * reset and tune the radio.
+        * Use internal short scan (single channel) operation to should
+        * achieve this objective.
+        * Driver should reset the radio when number of consecutive missed
+        * beacon, or any other uCode error condition detected.
+        */
+       IWL_DEBUG_INFO(priv, "perform radio reset.\n");
+       iwl_internal_short_hw_scan(priv);
+       return;
+}
+EXPORT_SYMBOL(iwl_force_rf_reset);
+
 #ifdef CONFIG_PM
 
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
index 8deb83bfe182bbadf0eee9db9c9cbc9788221437..ec1fe1d7cc9a264671f578ea6547f8e578240d63 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,7 @@ struct iwl_cmd;
 
 
 #define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT  "Copyright(c) 2003-2009 Intel Corporation"
+#define DRV_COPYRIGHT  "Copyright(c) 2003-2010 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 #define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -171,6 +171,7 @@ struct iwl_lib_ops {
                                  bool full_log, char **buf, bool display);
        void (*dump_nic_error_log)(struct iwl_priv *priv);
        void (*dump_csr)(struct iwl_priv *priv);
+       int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
        int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
        /* power management */
        struct iwl_apm_ops apm_ops;
@@ -187,6 +188,8 @@ struct iwl_lib_ops {
 
        /* temperature */
        struct iwl_temp_ops temp_ops;
+       /* station management */
+       void (*add_bcast_station)(struct iwl_priv *priv);
 };
 
 struct iwl_led_ops {
@@ -231,6 +234,8 @@ struct iwl_mod_params {
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
  * @support_wimax_coexist: support wimax/wifi co-exist
+ * @plcp_delta_threshold: plcp error rate threshold used to trigger
+ *     radio tuning when there is a high receiving plcp error rate
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -287,6 +292,7 @@ struct iwl_cfg {
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
        const bool support_wimax_coexist;
+       u8 plcp_delta_threshold;
 };
 
 /***************************
@@ -423,6 +429,8 @@ 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);
+void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+                                         struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
 void iwl_reply_statistics(struct iwl_priv *priv,
@@ -493,6 +501,8 @@ void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
+int iwl_internal_short_hw_scan(struct iwl_priv *priv);
+void iwl_force_rf_reset(struct iwl_priv *priv);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
                       const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
@@ -523,14 +533,6 @@ int iwl_send_calib_results(struct iwl_priv *priv);
 int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
 void iwl_calib_free_results(struct iwl_priv *priv);
 
-/*******************************************************************************
- * Spectrum Measureemtns in  iwl-spectrum.c
- ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
-#else
-static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
-#endif
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
  *****************************************************/
@@ -582,6 +584,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv);
 int iwl_dump_nic_event_log(struct iwl_priv *priv,
                           bool full_log, char **buf, bool display);
 void iwl_dump_csr(struct iwl_priv *priv);
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
 #ifdef CONFIG_IWLWIFI_DEBUG
 void iwl_print_rx_config_cmd(struct iwl_priv *priv);
 #else
index 1ec8cb4d5eae4f541ec2bc158a963f72c9a456f8..1e00720bf8b1fc0a2ac80c706b3c77a13fe739b3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 58e0462cafa35744d84f4d252e1cb61f8d9d133e..1c7b53d511c7eefe9bec3fca6fc143ab8d994f46 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
@@ -67,59 +67,6 @@ do {                                                                 \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-struct iwl_debugfs {
-       const char *name;
-       struct dentry *dir_drv;
-       struct dentry *dir_data;
-       struct dentry *dir_debug;
-       struct dentry *dir_rf;
-       struct dir_data_files {
-               struct dentry *file_sram;
-               struct dentry *file_nvm;
-               struct dentry *file_stations;
-               struct dentry *file_log_event;
-               struct dentry *file_channels;
-               struct dentry *file_status;
-               struct dentry *file_interrupt;
-               struct dentry *file_qos;
-               struct dentry *file_thermal_throttling;
-               struct dentry *file_led;
-               struct dentry *file_disable_ht40;
-               struct dentry *file_sleep_level_override;
-               struct dentry *file_current_sleep_command;
-       } dbgfs_data_files;
-       struct dir_rf_files {
-               struct dentry *file_disable_sensitivity;
-               struct dentry *file_disable_chain_noise;
-               struct dentry *file_disable_tx_power;
-       } dbgfs_rf_files;
-       struct dir_debug_files {
-               struct dentry *file_rx_statistics;
-               struct dentry *file_tx_statistics;
-               struct dentry *file_traffic_log;
-               struct dentry *file_rx_queue;
-               struct dentry *file_tx_queue;
-               struct dentry *file_ucode_rx_stats;
-               struct dentry *file_ucode_tx_stats;
-               struct dentry *file_ucode_general_stats;
-               struct dentry *file_sensitivity;
-               struct dentry *file_chain_noise;
-               struct dentry *file_tx_power;
-               struct dentry *file_power_save_status;
-               struct dentry *file_clear_ucode_statistics;
-               struct dentry *file_clear_traffic_statistics;
-               struct dentry *file_csr;
-               struct dentry *file_ucode_tracing;
-       } dbgfs_debug_files;
-       u32 sram_offset;
-       u32 sram_len;
-};
-
-int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
-void iwl_dbgfs_unregister(struct iwl_priv *priv);
-#endif
-
 #else
 #define IWL_DEBUG(__priv, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
@@ -128,9 +75,10 @@ static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
 {}
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
-
-
-#ifndef CONFIG_IWLWIFI_DEBUGFS
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
+void iwl_dbgfs_unregister(struct iwl_priv *priv);
+#else
 static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 {
        return 0;
index 4a2ac9311ba8a8a8654a2e5958fe06ebc04d09d4..d134301b553c6dc8e0106842b75950bd3fe15a8e 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
 #include "iwl-calib.h"
 
 /* create and remove of files */
-#define DEBUGFS_ADD_DIR(name, parent) do {                              \
-       dbgfs->dir_##name = debugfs_create_dir(#name, parent);          \
-       if (!(dbgfs->dir_##name))                                       \
-               goto err;                                               \
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
+       if (!debugfs_create_file(#name, mode, parent, priv,             \
+                                &iwl_dbgfs_##name##_ops))              \
+               goto err;                                               \
 } while (0)
 
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {                       \
-       dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_file(#name, mode,                                \
-                               dbgfs->dir_##parent, priv,              \
-                               &iwl_dbgfs_##name##_ops);               \
-       if (!(dbgfs->dbgfs_##parent##_files.file_##name))               \
-               goto err;                                               \
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                       \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR,           \
+                                   parent, ptr);                       \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
 } while (0)
 
-#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
-       dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_bool(#name, S_IWUSR | S_IRUSR,                   \
-                           dbgfs->dir_##parent, ptr);                  \
-       if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)           \
-                       || !dbgfs->dbgfs_##parent##_files.file_##name)  \
-               goto err;                                               \
+#define DEBUGFS_ADD_X32(name, parent, ptr) do {                                \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR,            \
+                                  parent, ptr);                        \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
 } while (0)
 
-#define DEBUGFS_ADD_X32(name, parent, ptr) do {                        \
-       dbgfs->dbgfs_##parent##_files.file_##name =                     \
-       debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr);   \
-       if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)           \
-                       || !dbgfs->dbgfs_##parent##_files.file_##name)  \
-               goto err;                                               \
-} while (0)
-
-#define DEBUGFS_REMOVE(name)  do {              \
-       debugfs_remove(name);                   \
-       name = NULL;                            \
-} while (0);
-
 /* file operation */
 #define DEBUGFS_READ_FUNC(name)                                         \
 static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
@@ -236,24 +221,24 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        size_t bufsz;
 
        /* default is to dump the entire data segment */
-       if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) {
-               priv->dbgfs->sram_offset = 0x800000;
+       if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
+               priv->dbgfs_sram_offset = 0x800000;
                if (priv->ucode_type == UCODE_INIT)
-                       priv->dbgfs->sram_len = priv->ucode_init_data.len;
+                       priv->dbgfs_sram_len = priv->ucode_init_data.len;
                else
-                       priv->dbgfs->sram_len = priv->ucode_data.len;
+                       priv->dbgfs_sram_len = priv->ucode_data.len;
        }
-       bufsz =  30 + priv->dbgfs->sram_len * sizeof(char) * 10;
+       bufsz =  30 + priv->dbgfs_sram_len * sizeof(char) * 10;
        buf = kmalloc(bufsz, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
-                       priv->dbgfs->sram_len);
+                       priv->dbgfs_sram_len);
        pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
-                       priv->dbgfs->sram_offset);
-       for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
-               val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
-                                       priv->dbgfs->sram_len - i);
+                       priv->dbgfs_sram_offset);
+       for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
+               val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \
+                                       priv->dbgfs_sram_len - i);
                if (i < 4) {
                        switch (i) {
                        case 1:
@@ -293,11 +278,11 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
                return -EFAULT;
 
        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
-               priv->dbgfs->sram_offset = offset;
-               priv->dbgfs->sram_len = len;
+               priv->dbgfs_sram_offset = offset;
+               priv->dbgfs_sram_len = len;
        } else {
-               priv->dbgfs->sram_offset = 0;
-               priv->dbgfs->sram_len = 0;
+               priv->dbgfs_sram_offset = 0;
+               priv->dbgfs_sram_len = 0;
        }
 
        return count;
@@ -429,8 +414,9 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file,
        int pos = 0;
        ssize_t ret = -ENOMEM;
 
-       pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true);
-       if (pos && buf) {
+       ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
+                                       priv, true, &buf, true);
+       if (buf) {
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
                kfree(buf);
        }
@@ -829,7 +815,9 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
 
        priv->power_data.debug_sleep_level_override = value;
 
+       mutex_lock(&priv->mutex);
        iwl_power_update_mode(priv, true);
+       mutex_unlock(&priv->mutex);
 
        return count;
 }
@@ -1081,6 +1069,12 @@ static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
        return p;
 }
 
+static const char ucode_stats_header[] =
+       "%-32s     current  acumulative       delta         max\n";
+static const char ucode_stats_short_format[] =
+       "  %-30s %10u\n";
+static const char ucode_stats_format[] =
+       "  %-30s %10u  %10u  %10u  %10u\n";
 
 static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
                                        char __user *user_buf,
@@ -1089,28 +1083,19 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
        struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
-       int bufsz = sizeof(struct statistics_rx_phy) * 20 +
-               sizeof(struct statistics_rx_non_phy) * 20 +
-               sizeof(struct statistics_rx_ht_phy) * 20 + 400;
+       int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+               sizeof(struct statistics_rx_non_phy) * 40 +
+               sizeof(struct statistics_rx_ht_phy) * 40 + 400;
        ssize_t ret;
-       struct statistics_rx_phy *ofdm, *accum_ofdm;
-       struct statistics_rx_phy *cck, *accum_cck;
+       struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+       struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
        struct statistics_rx_non_phy *general, *accum_general;
-       struct statistics_rx_ht_phy *ht, *accum_ht;
+       struct statistics_rx_non_phy *delta_general, *max_general;
+       struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
 
        if (!iwl_is_alive(priv))
                return -EAGAIN;
 
-       /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (ret) {
-               IWL_ERR(priv,
-                       "Error sending statistics request: %zd\n", ret);
-               return -EAGAIN;
-       }
        buf = kzalloc(bufsz, GFP_KERNEL);
        if (!buf) {
                IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1129,267 +1114,401 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
        accum_cck = &priv->accum_statistics.rx.cck;
        accum_general = &priv->accum_statistics.rx.general;
        accum_ht = &priv->accum_statistics.rx.ofdm_ht;
+       delta_ofdm = &priv->delta_statistics.rx.ofdm;
+       delta_cck = &priv->delta_statistics.rx.cck;
+       delta_general = &priv->delta_statistics.rx.general;
+       delta_ht = &priv->delta_statistics.rx.ofdm_ht;
+       max_ofdm = &priv->max_delta.rx.ofdm;
+       max_cck = &priv->max_delta.rx.cck;
+       max_general = &priv->max_delta.rx.general;
+       max_ht = &priv->max_delta.rx.ofdm_ht;
+
        pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "overrun_err:\t\t%u\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+                        "Statistics_Rx - OFDM:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+                        accum_ofdm->ina_cnt,
+                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_cnt:",
+                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "plcp_err:",
+                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_err:",
+                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "overrun_err:",
                         le32_to_cpu(ofdm->overrun_err),
-                        accum_ofdm->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "early_overrun_err:\t%u\t\t\t%u\n",
+                        accum_ofdm->overrun_err,
+                        delta_ofdm->overrun_err, max_ofdm->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "early_overrun_err:",
                         le32_to_cpu(ofdm->early_overrun_err),
-                        accum_ofdm->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->early_overrun_err,
+                        delta_ofdm->early_overrun_err,
+                        max_ofdm->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_good:",
                         le32_to_cpu(ofdm->crc32_good),
-                        accum_ofdm->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "false_alarm_cnt:\t%u\t\t\t%u\n",
+                        accum_ofdm->crc32_good,
+                        delta_ofdm->crc32_good, max_ofdm->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "false_alarm_cnt:",
                         le32_to_cpu(ofdm->false_alarm_cnt),
-                        accum_ofdm->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+                        accum_ofdm->false_alarm_cnt,
+                        delta_ofdm->false_alarm_cnt,
+                        max_ofdm->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_sync_err_cnt:",
                         le32_to_cpu(ofdm->fina_sync_err_cnt),
-                        accum_ofdm->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sfd_timeout:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->fina_sync_err_cnt,
+                        delta_ofdm->fina_sync_err_cnt,
+                        max_ofdm->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sfd_timeout:",
                         le32_to_cpu(ofdm->sfd_timeout),
-                        accum_ofdm->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "fina_timeout:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->sfd_timeout,
+                        delta_ofdm->sfd_timeout,
+                        max_ofdm->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_timeout:",
                         le32_to_cpu(ofdm->fina_timeout),
-                        accum_ofdm->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "unresponded_rts:\t%u\t\t\t%u\n",
+                        accum_ofdm->fina_timeout,
+                        delta_ofdm->fina_timeout,
+                        max_ofdm->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "unresponded_rts:",
                         le32_to_cpu(ofdm->unresponded_rts),
-                        accum_ofdm->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+                        accum_ofdm->unresponded_rts,
+                        delta_ofdm->unresponded_rts,
+                        max_ofdm->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "rxe_frame_lmt_ovrun:",
                         le32_to_cpu(ofdm->rxe_frame_limit_overrun),
-                        accum_ofdm->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->rxe_frame_limit_overrun,
+                        delta_ofdm->rxe_frame_limit_overrun,
+                        max_ofdm->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_ack_cnt:",
                         le32_to_cpu(ofdm->sent_ack_cnt),
-                        accum_ofdm->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->sent_ack_cnt,
+                        delta_ofdm->sent_ack_cnt,
+                        max_ofdm->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_cts_cnt:",
                         le32_to_cpu(ofdm->sent_cts_cnt),
-                        accum_ofdm->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+                        accum_ofdm->sent_cts_cnt,
+                        delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_ba_rsp_cnt:",
                         le32_to_cpu(ofdm->sent_ba_rsp_cnt),
-                        accum_ofdm->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "dsp_self_kill:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->sent_ba_rsp_cnt,
+                        delta_ofdm->sent_ba_rsp_cnt,
+                        max_ofdm->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "dsp_self_kill:",
                         le32_to_cpu(ofdm->dsp_self_kill),
-                        accum_ofdm->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "mh_format_err:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->dsp_self_kill,
+                        delta_ofdm->dsp_self_kill,
+                        max_ofdm->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "mh_format_err:",
                         le32_to_cpu(ofdm->mh_format_err),
-                        accum_ofdm->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+                        accum_ofdm->mh_format_err,
+                        delta_ofdm->mh_format_err,
+                        max_ofdm->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "re_acq_main_rssi_sum:",
                         le32_to_cpu(ofdm->re_acq_main_rssi_sum),
-                        accum_ofdm->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "overrun_err:\t\t%u\t\t\t%u\n",
+                        accum_ofdm->re_acq_main_rssi_sum,
+                        delta_ofdm->re_acq_main_rssi_sum,
+                       max_ofdm->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+                        "Statistics_Rx - CCK:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "ina_cnt:",
+                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+                        delta_cck->ina_cnt, max_cck->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_cnt:",
+                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+                        delta_cck->fina_cnt, max_cck->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "plcp_err:",
+                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+                        delta_cck->plcp_err, max_cck->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_err:",
+                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+                        delta_cck->crc32_err, max_cck->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "overrun_err:",
                         le32_to_cpu(cck->overrun_err),
-                        accum_cck->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "early_overrun_err:\t%u\t\t\t%u\n",
+                        accum_cck->overrun_err,
+                        delta_cck->overrun_err, max_cck->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "early_overrun_err:",
                         le32_to_cpu(cck->early_overrun_err),
-                        accum_cck->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "false_alarm_cnt:\t%u\t\t\t%u\n",
+                        accum_cck->early_overrun_err,
+                        delta_cck->early_overrun_err,
+                        max_cck->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_good:",
+                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+                        delta_cck->crc32_good,
+                        max_cck->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "false_alarm_cnt:",
                         le32_to_cpu(cck->false_alarm_cnt),
-                        accum_cck->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+                        accum_cck->false_alarm_cnt,
+                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_sync_err_cnt:",
                         le32_to_cpu(cck->fina_sync_err_cnt),
-                        accum_cck->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sfd_timeout:\t\t%u\t\t\t%u\n",
+                        accum_cck->fina_sync_err_cnt,
+                        delta_cck->fina_sync_err_cnt,
+                        max_cck->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sfd_timeout:",
                         le32_to_cpu(cck->sfd_timeout),
-                        accum_cck->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "fina_timeout:\t\t%u\t\t\t%u\n",
+                        accum_cck->sfd_timeout,
+                        delta_cck->sfd_timeout, max_cck->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "fina_timeout:",
                         le32_to_cpu(cck->fina_timeout),
-                        accum_cck->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "unresponded_rts:\t%u\t\t\t%u\n",
+                        accum_cck->fina_timeout,
+                        delta_cck->fina_timeout, max_cck->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "unresponded_rts:",
                         le32_to_cpu(cck->unresponded_rts),
-                        accum_cck->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+                        accum_cck->unresponded_rts,
+                        delta_cck->unresponded_rts,
+                        max_cck->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "rxe_frame_lmt_ovrun:",
                         le32_to_cpu(cck->rxe_frame_limit_overrun),
-                        accum_cck->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+                        accum_cck->rxe_frame_limit_overrun,
+                        delta_cck->rxe_frame_limit_overrun,
+                        max_cck->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_ack_cnt:",
                         le32_to_cpu(cck->sent_ack_cnt),
-                        accum_cck->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+                        accum_cck->sent_ack_cnt,
+                        delta_cck->sent_ack_cnt,
+                        max_cck->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_cts_cnt:",
                         le32_to_cpu(cck->sent_cts_cnt),
-                        accum_cck->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+                        accum_cck->sent_cts_cnt,
+                        delta_cck->sent_cts_cnt,
+                        max_cck->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sent_ba_rsp_cnt:",
                         le32_to_cpu(cck->sent_ba_rsp_cnt),
-                        accum_cck->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "dsp_self_kill:\t\t%u\t\t\t%u\n",
+                        accum_cck->sent_ba_rsp_cnt,
+                        delta_cck->sent_ba_rsp_cnt,
+                        max_cck->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "dsp_self_kill:",
                         le32_to_cpu(cck->dsp_self_kill),
-                        accum_cck->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "mh_format_err:\t\t%u\t\t\t%u\n",
+                        accum_cck->dsp_self_kill,
+                        delta_cck->dsp_self_kill,
+                        max_cck->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "mh_format_err:",
                         le32_to_cpu(cck->mh_format_err),
-                        accum_cck->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+                        accum_cck->mh_format_err,
+                        delta_cck->mh_format_err, max_cck->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "re_acq_main_rssi_sum:",
                         le32_to_cpu(cck->re_acq_main_rssi_sum),
-                        accum_cck->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n",
+                        accum_cck->re_acq_main_rssi_sum,
+                        delta_cck->re_acq_main_rssi_sum,
+                        max_cck->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+                       "Statistics_Rx - GENERAL:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "bogus_cts:",
                         le32_to_cpu(general->bogus_cts),
-                        accum_general->bogus_cts);
-       pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n",
+                        accum_general->bogus_cts,
+                        delta_general->bogus_cts, max_general->bogus_cts);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "bogus_ack:",
                         le32_to_cpu(general->bogus_ack),
-                        accum_general->bogus_ack);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "non_bssid_frames:\t%u\t\t\t%u\n",
+                        accum_general->bogus_ack,
+                        delta_general->bogus_ack, max_general->bogus_ack);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "non_bssid_frames:",
                         le32_to_cpu(general->non_bssid_frames),
-                        accum_general->non_bssid_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "filtered_frames:\t%u\t\t\t%u\n",
+                        accum_general->non_bssid_frames,
+                        delta_general->non_bssid_frames,
+                        max_general->non_bssid_frames);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "filtered_frames:",
                         le32_to_cpu(general->filtered_frames),
-                        accum_general->filtered_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "non_channel_beacons:\t%u\t\t\t%u\n",
+                        accum_general->filtered_frames,
+                        delta_general->filtered_frames,
+                        max_general->filtered_frames);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "non_channel_beacons:",
                         le32_to_cpu(general->non_channel_beacons),
-                        accum_general->non_channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "channel_beacons:\t%u\t\t\t%u\n",
+                        accum_general->non_channel_beacons,
+                        delta_general->non_channel_beacons,
+                        max_general->non_channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "channel_beacons:",
                         le32_to_cpu(general->channel_beacons),
-                        accum_general->channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "num_missed_bcon:\t%u\t\t\t%u\n",
+                        accum_general->channel_beacons,
+                        delta_general->channel_beacons,
+                        max_general->channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "num_missed_bcon:",
                         le32_to_cpu(general->num_missed_bcon),
-                        accum_general->num_missed_bcon);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "adc_rx_saturation_time:\t%u\t\t\t%u\n",
+                        accum_general->num_missed_bcon,
+                        delta_general->num_missed_bcon,
+                        max_general->num_missed_bcon);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "adc_rx_saturation_time:",
                         le32_to_cpu(general->adc_rx_saturation_time),
-                        accum_general->adc_rx_saturation_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "ina_detect_search_tm:\t%u\t\t\t%u\n",
+                        accum_general->adc_rx_saturation_time,
+                        delta_general->adc_rx_saturation_time,
+                        max_general->adc_rx_saturation_time);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "ina_detect_search_tm:",
                         le32_to_cpu(general->ina_detection_search_time),
-                        accum_general->ina_detection_search_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_silence_rssi_a:\t%u\t\t\t%u\n",
+                        accum_general->ina_detection_search_time,
+                        delta_general->ina_detection_search_time,
+                        max_general->ina_detection_search_time);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_silence_rssi_a:",
                         le32_to_cpu(general->beacon_silence_rssi_a),
-                        accum_general->beacon_silence_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_silence_rssi_b:\t%u\t\t\t%u\n",
+                        accum_general->beacon_silence_rssi_a,
+                        delta_general->beacon_silence_rssi_a,
+                        max_general->beacon_silence_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_silence_rssi_b:",
                         le32_to_cpu(general->beacon_silence_rssi_b),
-                        accum_general->beacon_silence_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_silence_rssi_c:\t%u\t\t\t%u\n",
+                        accum_general->beacon_silence_rssi_b,
+                        delta_general->beacon_silence_rssi_b,
+                        max_general->beacon_silence_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_silence_rssi_c:",
                         le32_to_cpu(general->beacon_silence_rssi_c),
-                        accum_general->beacon_silence_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "interference_data_flag:\t%u\t\t\t%u\n",
+                        accum_general->beacon_silence_rssi_c,
+                        delta_general->beacon_silence_rssi_c,
+                        max_general->beacon_silence_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "interference_data_flag:",
                         le32_to_cpu(general->interference_data_flag),
-                        accum_general->interference_data_flag);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "channel_load:\t\t%u\t\t\t%u\n",
+                        accum_general->interference_data_flag,
+                        delta_general->interference_data_flag,
+                        max_general->interference_data_flag);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "channel_load:",
                         le32_to_cpu(general->channel_load),
-                        accum_general->channel_load);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "dsp_false_alarms:\t%u\t\t\t%u\n",
+                        accum_general->channel_load,
+                        delta_general->channel_load,
+                        max_general->channel_load);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "dsp_false_alarms:",
                         le32_to_cpu(general->dsp_false_alarms),
-                        accum_general->dsp_false_alarms);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_rssi_a:\t\t%u\t\t\t%u\n",
+                        accum_general->dsp_false_alarms,
+                        delta_general->dsp_false_alarms,
+                        max_general->dsp_false_alarms);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_rssi_a:",
                         le32_to_cpu(general->beacon_rssi_a),
-                        accum_general->beacon_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_rssi_b:\t\t%u\t\t\t%u\n",
+                        accum_general->beacon_rssi_a,
+                        delta_general->beacon_rssi_a,
+                        max_general->beacon_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_rssi_b:",
                         le32_to_cpu(general->beacon_rssi_b),
-                        accum_general->beacon_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_rssi_c:\t\t%u\t\t\t%u\n",
+                        accum_general->beacon_rssi_b,
+                        delta_general->beacon_rssi_b,
+                        max_general->beacon_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_rssi_c:",
                         le32_to_cpu(general->beacon_rssi_c),
-                        accum_general->beacon_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_energy_a:\t%u\t\t\t%u\n",
+                        accum_general->beacon_rssi_c,
+                        delta_general->beacon_rssi_c,
+                        max_general->beacon_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_energy_a:",
                         le32_to_cpu(general->beacon_energy_a),
-                        accum_general->beacon_energy_a);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_energy_b:\t%u\t\t\t%u\n",
+                        accum_general->beacon_energy_a,
+                        delta_general->beacon_energy_a,
+                        max_general->beacon_energy_a);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_energy_b:",
                         le32_to_cpu(general->beacon_energy_b),
-                        accum_general->beacon_energy_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "beacon_energy_c:\t%u\t\t\t%u\n",
+                        accum_general->beacon_energy_b,
+                        delta_general->beacon_energy_b,
+                        max_general->beacon_energy_b);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "beacon_energy_c:",
                         le32_to_cpu(general->beacon_energy_c),
-                        accum_general->beacon_energy_c);
+                        accum_general->beacon_energy_c,
+                        delta_general->beacon_energy_c,
+                        max_general->beacon_energy_c);
 
        pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "overrun_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "early_overrun_err:\t%u\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+                       "Statistics_Rx - OFDM_HT:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "plcp_err:",
+                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+                        delta_ht->plcp_err, max_ht->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "overrun_err:",
+                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+                        delta_ht->overrun_err, max_ht->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "early_overrun_err:",
                         le32_to_cpu(ht->early_overrun_err),
-                        accum_ht->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "mh_format_err:\t\t%u\t\t\t%u\n",
+                        accum_ht->early_overrun_err,
+                        delta_ht->early_overrun_err,
+                        max_ht->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_good:",
+                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+                        delta_ht->crc32_good, max_ht->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "crc32_err:",
+                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+                        delta_ht->crc32_err, max_ht->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "mh_format_err:",
                         le32_to_cpu(ht->mh_format_err),
-                        accum_ht->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg_crc32_good:\t\t%u\t\t\t%u\n",
+                        accum_ht->mh_format_err,
+                        delta_ht->mh_format_err, max_ht->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg_crc32_good:",
                         le32_to_cpu(ht->agg_crc32_good),
-                        accum_ht->agg_crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg_mpdu_cnt:\t\t%u\t\t\t%u\n",
+                        accum_ht->agg_crc32_good,
+                        delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg_mpdu_cnt:",
                         le32_to_cpu(ht->agg_mpdu_cnt),
-                        accum_ht->agg_mpdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n",
+                        accum_ht->agg_mpdu_cnt,
+                        delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg_cnt:",
+                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+                        delta_ht->agg_cnt, max_ht->agg_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "unsupport_mcs:",
                         le32_to_cpu(ht->unsupport_mcs),
-                        accum_ht->unsupport_mcs);
+                        accum_ht->unsupport_mcs,
+                        delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
@@ -1403,23 +1522,13 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
        struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
-       int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
+       int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
        ssize_t ret;
-       struct statistics_tx *tx, *accum_tx;
+       struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
 
        if (!iwl_is_alive(priv))
                return -EAGAIN;
 
-       /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (ret) {
-               IWL_ERR(priv,
-                       "Error sending statistics request: %zd\n", ret);
-               return -EAGAIN;
-       }
        buf = kzalloc(bufsz, GFP_KERNEL);
        if (!buf) {
                IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1432,106 +1541,148 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
         */
        tx = &priv->statistics.tx;
        accum_tx = &priv->accum_statistics.tx;
+       delta_tx = &priv->delta_statistics.tx;
+       max_tx = &priv->max_delta.tx;
        pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos,  ucode_stats_header,
+                       "Statistics_Tx:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "preamble:",
                         le32_to_cpu(tx->preamble_cnt),
-                        accum_tx->preamble_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "rx_detected_cnt:\t\t%u\t\t\t%u\n",
+                        accum_tx->preamble_cnt,
+                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "rx_detected_cnt:",
                         le32_to_cpu(tx->rx_detected_cnt),
-                        accum_tx->rx_detected_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n",
+                        accum_tx->rx_detected_cnt,
+                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "bt_prio_defer_cnt:",
                         le32_to_cpu(tx->bt_prio_defer_cnt),
-                        accum_tx->bt_prio_defer_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n",
+                        accum_tx->bt_prio_defer_cnt,
+                        delta_tx->bt_prio_defer_cnt,
+                        max_tx->bt_prio_defer_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "bt_prio_kill_cnt:",
                         le32_to_cpu(tx->bt_prio_kill_cnt),
-                        accum_tx->bt_prio_kill_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "few_bytes_cnt:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->bt_prio_kill_cnt,
+                        delta_tx->bt_prio_kill_cnt,
+                        max_tx->bt_prio_kill_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "few_bytes_cnt:",
                         le32_to_cpu(tx->few_bytes_cnt),
-                        accum_tx->few_bytes_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "cts_timeout:\t\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "ack_timeout:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->few_bytes_cnt,
+                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "cts_timeout:",
+                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+                        delta_tx->cts_timeout, max_tx->cts_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "ack_timeout:",
                         le32_to_cpu(tx->ack_timeout),
-                        accum_tx->ack_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "expected_ack_cnt:\t\t%u\t\t\t%u\n",
+                        accum_tx->ack_timeout,
+                        delta_tx->ack_timeout, max_tx->ack_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "expected_ack_cnt:",
                         le32_to_cpu(tx->expected_ack_cnt),
-                        accum_tx->expected_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "actual_ack_cnt:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->expected_ack_cnt,
+                        delta_tx->expected_ack_cnt,
+                        max_tx->expected_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "actual_ack_cnt:",
                         le32_to_cpu(tx->actual_ack_cnt),
-                        accum_tx->actual_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->actual_ack_cnt,
+                        delta_tx->actual_ack_cnt,
+                        max_tx->actual_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "dump_msdu_cnt:",
                         le32_to_cpu(tx->dump_msdu_cnt),
-                        accum_tx->dump_msdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "abort_nxt_frame_mismatch:"
-                        "\t%u\t\t\t%u\n",
+                        accum_tx->dump_msdu_cnt,
+                        delta_tx->dump_msdu_cnt,
+                        max_tx->dump_msdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "abort_nxt_frame_mismatch:",
                         le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
-                        accum_tx->burst_abort_next_frame_mismatch_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "abort_missing_nxt_frame:"
-                        "\t%u\t\t\t%u\n",
+                        accum_tx->burst_abort_next_frame_mismatch_cnt,
+                        delta_tx->burst_abort_next_frame_mismatch_cnt,
+                        max_tx->burst_abort_next_frame_mismatch_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "abort_missing_nxt_frame:",
                         le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
-                        accum_tx->burst_abort_missing_next_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "cts_timeout_collision:\t\t%u\t\t\t%u\n",
+                        accum_tx->burst_abort_missing_next_frame_cnt,
+                        delta_tx->burst_abort_missing_next_frame_cnt,
+                        max_tx->burst_abort_missing_next_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "cts_timeout_collision:",
                         le32_to_cpu(tx->cts_timeout_collision),
-                        accum_tx->cts_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "ack_ba_timeout_collision:\t%u\t\t\t%u\n",
+                        accum_tx->cts_timeout_collision,
+                        delta_tx->cts_timeout_collision,
+                        max_tx->cts_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "ack_ba_timeout_collision:",
                         le32_to_cpu(tx->ack_or_ba_timeout_collision),
-                        accum_tx->ack_or_ba_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg ba_timeout:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->ack_or_ba_timeout_collision,
+                        delta_tx->ack_or_ba_timeout_collision,
+                        max_tx->ack_or_ba_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg ba_timeout:",
                         le32_to_cpu(tx->agg.ba_timeout),
-                        accum_tx->agg.ba_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "agg ba_resched_frames:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.ba_timeout,
+                        delta_tx->agg.ba_timeout,
+                        max_tx->agg.ba_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "agg ba_resched_frames:",
                         le32_to_cpu(tx->agg.ba_reschedule_frames),
-                        accum_tx->agg.ba_reschedule_frames);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "agg scd_query_agg_frame:\t%u\t\t\t%u\n",
+                        accum_tx->agg.ba_reschedule_frames,
+                        delta_tx->agg.ba_reschedule_frames,
+                        max_tx->agg.ba_reschedule_frames);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "agg scd_query_agg_frame:",
                         le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
-                        accum_tx->agg.scd_query_agg_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg scd_query_no_agg:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.scd_query_agg_frame_cnt,
+                        delta_tx->agg.scd_query_agg_frame_cnt,
+                        max_tx->agg.scd_query_agg_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg scd_query_no_agg:",
                         le32_to_cpu(tx->agg.scd_query_no_agg),
-                        accum_tx->agg.scd_query_no_agg);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg scd_query_agg:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.scd_query_no_agg,
+                        delta_tx->agg.scd_query_no_agg,
+                        max_tx->agg.scd_query_no_agg);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg scd_query_agg:",
                         le32_to_cpu(tx->agg.scd_query_agg),
-                        accum_tx->agg.scd_query_agg);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "agg scd_query_mismatch:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.scd_query_agg,
+                        delta_tx->agg.scd_query_agg,
+                        max_tx->agg.scd_query_agg);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                       "agg scd_query_mismatch:",
                         le32_to_cpu(tx->agg.scd_query_mismatch),
-                        accum_tx->agg.scd_query_mismatch);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg frame_not_ready:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.scd_query_mismatch,
+                        delta_tx->agg.scd_query_mismatch,
+                        max_tx->agg.scd_query_mismatch);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg frame_not_ready:",
                         le32_to_cpu(tx->agg.frame_not_ready),
-                        accum_tx->agg.frame_not_ready);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg underrun:\t\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.frame_not_ready,
+                        delta_tx->agg.frame_not_ready,
+                        max_tx->agg.frame_not_ready);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg underrun:",
                         le32_to_cpu(tx->agg.underrun),
-                        accum_tx->agg.underrun);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg bt_prio_kill:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.underrun,
+                        delta_tx->agg.underrun, max_tx->agg.underrun);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg bt_prio_kill:",
                         le32_to_cpu(tx->agg.bt_prio_kill),
-                        accum_tx->agg.bt_prio_kill);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n",
+                        accum_tx->agg.bt_prio_kill,
+                        delta_tx->agg.bt_prio_kill,
+                        max_tx->agg.bt_prio_kill);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "agg rx_ba_rsp_cnt:",
                         le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
-                        accum_tx->agg.rx_ba_rsp_cnt);
+                        accum_tx->agg.rx_ba_rsp_cnt,
+                        delta_tx->agg.rx_ba_rsp_cnt,
+                        max_tx->agg.rx_ba_rsp_cnt);
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
@@ -1545,25 +1696,16 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
        struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
-       int bufsz = sizeof(struct statistics_general) * 4 + 250;
+       int bufsz = sizeof(struct statistics_general) * 10 + 300;
        ssize_t ret;
        struct statistics_general *general, *accum_general;
-       struct statistics_dbg *dbg, *accum_dbg;
-       struct statistics_div *div, *accum_div;
+       struct statistics_general *delta_general, *max_general;
+       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+       struct statistics_div *div, *accum_div, *delta_div, *max_div;
 
        if (!iwl_is_alive(priv))
                return -EAGAIN;
 
-       /* make request to uCode to retrieve statistics information */
-       mutex_lock(&priv->mutex);
-       ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (ret) {
-               IWL_ERR(priv,
-                       "Error sending statistics request: %zd\n", ret);
-               return -EAGAIN;
-       }
        buf = kzalloc(bufsz, GFP_KERNEL);
        if (!buf) {
                IWL_ERR(priv, "Can not allocate Buffer\n");
@@ -1578,52 +1720,78 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
        dbg = &priv->statistics.general.dbg;
        div = &priv->statistics.general.div;
        accum_general = &priv->accum_statistics.general;
+       delta_general = &priv->delta_statistics.general;
+       max_general = &priv->max_delta.general;
        accum_dbg = &priv->accum_statistics.general.dbg;
+       delta_dbg = &priv->delta_statistics.general.dbg;
+       max_dbg = &priv->max_delta.general.dbg;
        accum_div = &priv->accum_statistics.general.div;
+       delta_div = &priv->delta_statistics.general.div;
+       max_div = &priv->max_delta.general.div;
        pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "\t\t\tcurrent\t\t\taccumulative\n");
-       pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
+                       "Statistics_General:");
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
+                        "temperature:",
                         le32_to_cpu(general->temperature));
-       pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
+                        "temperature_m:",
                         le32_to_cpu(general->temperature_m));
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "burst_check:\t\t\t%u\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "burst_check:",
                         le32_to_cpu(dbg->burst_check),
-                        accum_dbg->burst_check);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "burst_count:\t\t\t%u\t\t\t%u\n",
+                        accum_dbg->burst_check,
+                        delta_dbg->burst_check, max_dbg->burst_check);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "burst_count:",
                         le32_to_cpu(dbg->burst_count),
-                        accum_dbg->burst_count);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "sleep_time:\t\t\t%u\t\t\t%u\n",
+                        accum_dbg->burst_count,
+                        delta_dbg->burst_count, max_dbg->burst_count);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "sleep_time:",
                         le32_to_cpu(general->sleep_time),
-                        accum_general->sleep_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "slots_out:\t\t\t%u\t\t\t%u\n",
+                        accum_general->sleep_time,
+                        delta_general->sleep_time, max_general->sleep_time);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "slots_out:",
                         le32_to_cpu(general->slots_out),
-                        accum_general->slots_out);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "slots_idle:\t\t\t%u\t\t\t%u\n",
+                        accum_general->slots_out,
+                        delta_general->slots_out, max_general->slots_out);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "slots_idle:",
                         le32_to_cpu(general->slots_idle),
-                        accum_general->slots_idle);
+                        accum_general->slots_idle,
+                        delta_general->slots_idle, max_general->slots_idle);
        pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
                         le32_to_cpu(general->ttl_timestamp));
-       pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a);
-       pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "exec_time:\t\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(div->exec_time), accum_div->exec_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "probe_time:\t\t\t%u\t\t\t%u\n",
-                        le32_to_cpu(div->probe_time), accum_div->probe_time);
-       pos += scnprintf(buf + pos, bufsz - pos,
-                        "rx_enable_counter:\t\t%u\t\t\t%u\n",
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "tx_on_a:",
+                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+                        delta_div->tx_on_a, max_div->tx_on_a);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "tx_on_b:",
+                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+                        delta_div->tx_on_b, max_div->tx_on_b);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "exec_time:",
+                        le32_to_cpu(div->exec_time), accum_div->exec_time,
+                        delta_div->exec_time, max_div->exec_time);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "probe_time:",
+                        le32_to_cpu(div->probe_time), accum_div->probe_time,
+                        delta_div->probe_time, max_div->probe_time);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "rx_enable_counter:",
                         le32_to_cpu(general->rx_enable_counter),
-                        accum_general->rx_enable_counter);
+                        accum_general->rx_enable_counter,
+                        delta_general->rx_enable_counter,
+                        max_general->rx_enable_counter);
+       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
+                        "num_of_sos_states:",
+                        le32_to_cpu(general->num_of_sos_states),
+                        accum_general->num_of_sos_states,
+                        delta_general->num_of_sos_states,
+                        max_general->num_of_sos_states);
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
        return ret;
@@ -1775,23 +1943,12 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
        struct iwl_priv *priv = file->private_data;
        char buf[128];
        int pos = 0;
-       ssize_t ret;
        const size_t bufsz = sizeof(buf);
        struct statistics_tx *tx;
 
        if (!iwl_is_alive(priv))
                pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
        else {
-               /* make request to uCode to retrieve statistics information */
-               mutex_lock(&priv->mutex);
-               ret = iwl_send_statistics_request(priv, CMD_SYNC, false);
-               mutex_unlock(&priv->mutex);
-
-               if (ret) {
-                       IWL_ERR(priv, "Error sending statistics request: %zd\n",
-                               ret);
-                       return -EAGAIN;
-               }
                tx = &priv->statistics.tx;
                if (tx->tx_power.ant_a ||
                    tx->tx_power.ant_b ||
@@ -1940,6 +2097,132 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -EFAULT;
+
+       if (priv->cfg->ops->lib->dump_fh) {
+               ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
+               if (buf) {
+                       ret = simple_read_from_buffer(user_buf,
+                                                     count, ppos, buf, pos);
+                       kfree(buf);
+               }
+       }
+
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char buf[12];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
+                       priv->missed_beacon_threshold);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int missed;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &missed) != 1)
+               return -EINVAL;
+
+       if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
+           missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
+               priv->missed_beacon_threshold =
+                       IWL_MISSED_BEACON_THRESHOLD_DEF;
+       else
+               priv->missed_beacon_threshold = missed;
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int scan;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &scan) != 1)
+               return -EINVAL;
+
+       iwl_internal_short_hw_scan(priv);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[12];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
+                       priv->cfg->plcp_delta_threshold);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int plcp;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &plcp) != 1)
+               return -EINVAL;
+       if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
+               (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
+               priv->cfg->plcp_delta_threshold =
+                       IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
+       else
+               priv->cfg->plcp_delta_threshold = plcp;
+       return count;
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1956,6 +2239,10 @@ DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
 DEBUGFS_WRITE_FILE_OPS(csr);
 DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
+DEBUGFS_WRITE_FILE_OPS(internal_scan);
+DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
 
 /*
  * Create the debugfs files and directories
@@ -1963,71 +2250,73 @@ DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
  */
 int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 {
-       struct iwl_debugfs *dbgfs;
        struct dentry *phyd = priv->hw->wiphy->debugfsdir;
-       int ret = 0;
+       struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
 
-       dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
-       if (!dbgfs) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       dir_drv = debugfs_create_dir(name, phyd);
+       if (!dir_drv)
+               return -ENOMEM;
 
-       priv->dbgfs = dbgfs;
-       dbgfs->name = name;
-       dbgfs->dir_drv = debugfs_create_dir(name, phyd);
-       if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) {
-               ret = -ENOENT;
+       priv->debugfs_dir = dir_drv;
+
+       dir_data = debugfs_create_dir("data", dir_drv);
+       if (!dir_data)
+               goto err;
+       dir_rf = debugfs_create_dir("rf", dir_drv);
+       if (!dir_rf)
+               goto err;
+       dir_debug = debugfs_create_dir("debug", dir_drv);
+       if (!dir_debug)
                goto err;
-       }
 
-       DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
-       DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
-       DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
-       DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(status, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(qos, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(led, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR);
-       DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
+       DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
-               DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
        }
-       DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
-       DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
+       DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal);
+       DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
                         &priv->disable_chain_noise_cal);
        if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
            ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
-               DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+               DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
                                &priv->disable_tx_power_cal);
        return 0;
 
 err:
-       IWL_ERR(priv, "Can't open the debugfs directory\n");
+       IWL_ERR(priv, "Can't create the debugfs directory\n");
        iwl_dbgfs_unregister(priv);
-       return ret;
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(iwl_dbgfs_register);
 
@@ -2037,59 +2326,11 @@ EXPORT_SYMBOL(iwl_dbgfs_register);
  */
 void iwl_dbgfs_unregister(struct iwl_priv *priv)
 {
-       if (!priv->dbgfs)
+       if (!priv->debugfs_dir)
                return;
 
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
-       DEBUGFS_REMOVE(priv->dbgfs->dir_data);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_statistics);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_statistics);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_traffic_log);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_clear_ucode_statistics);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_clear_traffic_statistics);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_ucode_rx_stats);
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_ucode_tx_stats);
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_ucode_general_stats);
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_sensitivity);
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_chain_noise);
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
-                       file_ucode_tracing);
-       }
-       DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
-       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
-       if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
-           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
-               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
-       DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
-       DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
-       kfree(priv->dbgfs);
-       priv->dbgfs = NULL;
+       debugfs_remove_recursive(priv->debugfs_dir);
+       priv->debugfs_dir = NULL;
 }
 EXPORT_SYMBOL(iwl_dbgfs_unregister);
 
index 70f0e79c8e4a8226bd0e4b834af5c4a592db0789..55dc5a866542e8da792aed03182f66c49804e3f3 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
@@ -1011,6 +1011,30 @@ struct iwl_event_log {
        int wraps_more_count;
 };
 
+/*
+ * host interrupt timeout value
+ * used with setting interrupt coalescing timer
+ * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit
+ *
+ * default interrupt coalescing timer is 64 x 32 = 2048 usecs
+ * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs
+ */
+#define IWL_HOST_INT_TIMEOUT_MAX       (0xFF)
+#define IWL_HOST_INT_TIMEOUT_DEF       (0x40)
+#define IWL_HOST_INT_TIMEOUT_MIN       (0x0)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF)
+#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10)
+#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0)
+
+/*
+ * This is the threshold value of plcp error rate per 100mSecs.  It is
+ * used to set and check for the validity of plcp_delta.
+ */
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50)
+#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF    (100)
+#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255)
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1031,13 +1055,16 @@ struct iwl_priv {
 
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
-#if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT)
        /* spectrum measurement report caching */
        struct iwl_spectrum_notification measure_report;
        u8 measurement_status;
-#endif
+
        /* ucode beacon time */
        u32 ucode_beacon_time;
+       int missed_beacon_threshold;
+
+       /* storing the jiffies when the plcp error rate is received */
+       unsigned long plcp_jiffies;
 
        /* we allocate array of iwl4965_channel_info for NIC's valid channels.
         *    Access via channel # using indirect index array */
@@ -1056,14 +1083,15 @@ struct iwl_priv {
        struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
        /* Scan related variables */
-       unsigned long last_scan_jiffies;
        unsigned long next_scan_jiffies;
        unsigned long scan_start;
        unsigned long scan_pass_start;
        unsigned long scan_start_tsf;
+       unsigned long last_internal_scan_jiffies;
        void *scan;
        int scan_bands;
        struct cfg80211_scan_request *scan_request;
+       bool is_internal_short_scan;
        u8 scan_tx_ant[IEEE80211_NUM_BANDS];
        u8 mgmt_tx_ant;
 
@@ -1162,6 +1190,8 @@ struct iwl_priv {
        struct iwl_notif_statistics statistics;
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_notif_statistics accum_statistics;
+       struct iwl_notif_statistics delta_statistics;
+       struct iwl_notif_statistics max_delta;
 #endif
 
        /* context information */
@@ -1234,15 +1264,10 @@ struct iwl_priv {
 
        struct workqueue_struct *workqueue;
 
-       struct work_struct up;
        struct work_struct restart;
-       struct work_struct calibrated_work;
        struct work_struct scan_completed;
        struct work_struct rx_replenish;
        struct work_struct abort_scan;
-       struct work_struct update_link_led;
-       struct work_struct auth_work;
-       struct work_struct report_work;
        struct work_struct request_scan;
        struct work_struct beacon_update;
        struct work_struct tt_work;
@@ -1278,7 +1303,8 @@ struct iwl_priv {
        u16 rx_traffic_idx;
        u8 *tx_traffic;
        u8 *rx_traffic;
-       struct iwl_debugfs *dbgfs;
+       struct dentry *debugfs_dir;
+       u32 dbgfs_sram_offset, dbgfs_sram_len;
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 #endif /* CONFIG_IWLWIFI_DEBUG */
 
index 4a30969689ff5eb777e76f4d8609f84f66570bd4..fd37152abae3afe3f393e99ce93e929e36f50576 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0cd9c02ee0441be719117a81037c2db9cd5993da..4e1ba824dc50521ba84ebe191bc25da1fb688235 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 65fa8a69fd5ab65fba6322182db3773804d4c3f6..113c3669b9ce407e9165ee4b40b88436b294a514 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #define FH_TSSR_TX_STATUS_REG          (FH_TSSR_LOWER_BOUND + 0x010)
 
+/**
+ * Bit fields for TSSR(Tx Shared Status & Control) error status register:
+ * 31:  Indicates an address error when accessed to internal memory
+ *     uCode/driver must write "1" in order to clear this flag
+ * 30:  Indicates that Host did not send the expected number of dwords to FH
+ *     uCode/driver must write "1" in order to clear this flag
+ * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA
+ *     command was received from the scheduler while the TRB was already full
+ *     with previous command
+ *     uCode/driver must write "1" in order to clear this flag
+ * 7-0: Each status bit indicates a channel's TxCredit error. When an error
+ *     bit is set, it indicates that the FH has received a full indication
+ *     from the RTC TxFIFO and the current value of the TxCredit counter was
+ *     not equal to zero. This mean that the credit mechanism was not
+ *     synchronized to the TxFIFO status
+ *     uCode/driver must write "1" in order to clear this flag
+ */
+#define FH_TSSR_TX_ERROR_REG           (FH_TSSR_LOWER_BOUND + 0x018)
+
 #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
 #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
 
index 87d684efe110efc24a121fe354abea6bb243420b..86783c27d97c9a930e94befabfdf75878dc70215 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
index bd0b12efb5c7fdaa5aecd4de3271d6bdb48c47ac..45af5bbc1c5657e86a3937ae4dbe38eafc23da03 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
index e552d4c4bdbe0e31ea34a160373b87ccd191a8ab..c719baf2585a49583f2cef7a4b02107e044830a5 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index 46c7a95b88f00103e41a9db3cee25f7e13fabf08..a6f9c918aabcd0507c3ec10de7550da58fc4ebe5 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index f47f053f02ead25492c9df1864ccdb8a0d468a2c..49a70baa3fb67a4137fd722fb0c4d3cac7d2b637 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 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
index 8ccc0bb1d9ed00c0fe9391acae0aa0dff0fbfaa2..1a1a9f081cc712288b552e49f667601bc7e5d5a9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -303,13 +303,12 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
                                sizeof(struct iwl_powertable_cmd), cmd);
 }
 
-
+/* priv->mutex must be held */
 int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 {
        int ret = 0;
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) &&
-                       (priv->hw->conf.flags & IEEE80211_CONF_PS);
+       bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
        bool update_chains;
        struct iwl_powertable_cmd cmd;
        int dtimper;
@@ -319,7 +318,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
                        priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
 
        if (priv->vif)
-               dtimper = priv->vif->bss_conf.dtim_period;
+               dtimper = priv->hw->conf.ps_dtim_period;
        else
                dtimper = 1;
 
index 310c32e8f6989672a569c6ce9a2d0b970689aab5..5db91c10dcc8ca602a4f1760ac4dbd395105bdae 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
index 6d95832db06dec2bdda4fc2a4fc07583d11d97fa..d2d2a9174900e7d84ecfa97acbae6c20206bad77 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6f36b6e79f5e3db56d72fdcbcab1da493ae41e8a..5df66382d92284280fd672b8512d55550a7ce36b 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -473,8 +473,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
                           (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
                           (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
 
-       /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */
-       iwl_write8(priv, CSR_INT_COALESCING, 0x40);
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
 
        return 0;
 }
@@ -499,9 +499,10 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
        struct iwl_missed_beacon_notif *missed_beacon;
 
        missed_beacon = &pkt->u.missed_beacon;
-       if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+       if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >
+           priv->missed_beacon_threshold) {
                IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-                   le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+                   le32_to_cpu(missed_beacon->consecutive_missed_beacons),
                    le32_to_cpu(missed_beacon->total_missed_becons),
                    le32_to_cpu(missed_beacon->num_recvd_beacons),
                    le32_to_cpu(missed_beacon->num_expected_beacons));
@@ -511,6 +512,24 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
 
+void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+                                         struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+       if (!report->state) {
+               IWL_DEBUG_11H(priv,
+                       "Spectrum Measure Notification: Start\n");
+               return;
+       }
+
+       memcpy(&priv->measure_report, report, sizeof(*report));
+       priv->measurement_status |= MEASUREMENT_READY;
+}
+EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);
+
+
 
 /* Calculate noise level, based on measurements during network silence just
  *   before arriving beacon.  This measurement can be done only if we know
@@ -564,15 +583,24 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
        int i;
        __le32 *prev_stats;
        u32 *accum_stats;
+       u32 *delta, *max_delta;
 
        prev_stats = (__le32 *)&priv->statistics;
        accum_stats = (u32 *)&priv->accum_statistics;
+       delta = (u32 *)&priv->delta_statistics;
+       max_delta = (u32 *)&priv->max_delta;
 
        for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
-            i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
-               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
-                       *accum_stats += (le32_to_cpu(*stats) -
+            i += sizeof(__le32), stats++, prev_stats++, delta++,
+            max_delta++, accum_stats++) {
+               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+                       *delta = (le32_to_cpu(*stats) -
                                le32_to_cpu(*prev_stats));
+                       *accum_stats += *delta;
+                       if (*delta > *max_delta)
+                               *max_delta = *delta;
+               }
+       }
 
        /* reset accumulative statistics for "no-counter" type statistics */
        priv->accum_statistics.general.temperature =
@@ -592,11 +620,15 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
 
 #define REG_RECALIB_PERIOD (60)
 
+#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb)
 {
        int change;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       int combined_plcp_delta;
+       unsigned int plcp_msec;
+       unsigned long plcp_received_jiffies;
 
        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
                     (int)sizeof(priv->statistics),
@@ -611,6 +643,56 @@ void iwl_rx_statistics(struct iwl_priv *priv,
 #ifdef CONFIG_IWLWIFI_DEBUG
        iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
 #endif
+       /*
+        * check for plcp_err and trigger radio reset if it exceeds
+        * the plcp error threshold plcp_delta.
+        */
+       plcp_received_jiffies = jiffies;
+       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+                                       (long) priv->plcp_jiffies);
+       priv->plcp_jiffies = plcp_received_jiffies;
+       /*
+        * check to make sure plcp_msec is not 0 to prevent division
+        * by zero.
+        */
+       if (plcp_msec) {
+               combined_plcp_delta =
+                       (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -
+                       le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +
+                       (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -
+                       le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
+
+               if ((combined_plcp_delta > 0) &&
+                       ((combined_plcp_delta * 100) / plcp_msec) >
+                       priv->cfg->plcp_delta_threshold) {
+                       /*
+                        * if plcp_err exceed the threshold, the following
+                        * data is printed in csv format:
+                        *    Text: plcp_err exceeded %d,
+                        *    Received ofdm.plcp_err,
+                        *    Current ofdm.plcp_err,
+                        *    Received ofdm_ht.plcp_err,
+                        *    Current ofdm_ht.plcp_err,
+                        *    combined_plcp_delta,
+                        *    plcp_msec
+                        */
+                       IWL_DEBUG_RADIO(priv, PLCP_MSG,
+                               priv->cfg->plcp_delta_threshold,
+                               le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
+                               le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
+                               le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
+                               le32_to_cpu(
+                                       priv->statistics.rx.ofdm_ht.plcp_err),
+                               combined_plcp_delta, plcp_msec);
+
+                       /*
+                        * Reset the RF radio due to the high plcp
+                        * error rate
+                        */
+                       iwl_force_rf_reset(priv);
+               }
+       }
+
        memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
 
        set_bit(STATUS_STATISTICS, &priv->status);
@@ -638,11 +720,13 @@ void iwl_reply_statistics(struct iwl_priv *priv,
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
        if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
-               memset(&priv->statistics, 0,
-                       sizeof(struct iwl_notif_statistics));
 #ifdef CONFIG_IWLWIFI_DEBUG
                memset(&priv->accum_statistics, 0,
                        sizeof(struct iwl_notif_statistics));
+               memset(&priv->delta_statistics, 0,
+                       sizeof(struct iwl_notif_statistics));
+               memset(&priv->max_delta, 0,
+                       sizeof(struct iwl_notif_statistics));
 #endif
                IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
        }
index fa1c89ba6459645632d3425511b0a016edd97a08..08faafae8497722f1f45cf39d36883152b83d35a 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved.
+ * 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
@@ -192,19 +192,17 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
        IWL_DEBUG_SCAN(priv, "Scan ch.res: "
                       "%d [802.11%s] "
                       "(TSF: 0x%08X:%08X) - %d "
-                      "elapsed=%lu usec (%dms since last)\n",
+                      "elapsed=%lu usec\n",
                       notif->channel,
                       notif->band ? "bg" : "a",
                       le32_to_cpu(notif->tsf_high),
                       le32_to_cpu(notif->tsf_low),
                       le32_to_cpu(notif->statistics[0]),
-                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
-                      jiffies_to_msecs(elapsed_jiffies
-                                       (priv->last_scan_jiffies, jiffies)));
+                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
 #endif
 
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
+       if (!priv->is_internal_short_scan)
+               priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
@@ -250,8 +248,11 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                        goto reschedule;
        }
 
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
+       if (!priv->is_internal_short_scan)
+               priv->next_scan_jiffies = 0;
+       else
+               priv->last_internal_scan_jiffies = jiffies;
+
        IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 
        clear_bit(STATUS_SCANNING, &priv->status);
@@ -314,6 +315,72 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_get_passive_dwell_time);
 
+static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
+                                    enum ieee80211_band band,
+                                    struct iwl_scan_channel *scan_ch)
+{
+       const struct ieee80211_supported_band *sband;
+       const struct iwl_channel_info *ch_info;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int i, added = 0;
+       u16 channel = 0;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband) {
+               IWL_ERR(priv, "invalid band\n");
+               return added;
+       }
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       /* only scan single channel, good enough to reset the RF */
+       /* pick the first valid not in-use channel */
+       if (band == IEEE80211_BAND_5GHZ) {
+               for (i = 14; i < priv->channel_count; i++) {
+                       if (priv->channel_info[i].channel !=
+                           le16_to_cpu(priv->staging_rxon.channel)) {
+                               channel = priv->channel_info[i].channel;
+                               ch_info = iwl_get_channel_info(priv,
+                                       band, channel);
+                               if (is_channel_valid(ch_info))
+                                       break;
+                       }
+               }
+       } else {
+               for (i = 0; i < 14; i++) {
+                       if (priv->channel_info[i].channel !=
+                           le16_to_cpu(priv->staging_rxon.channel)) {
+                                       channel =
+                                               priv->channel_info[i].channel;
+                                       ch_info = iwl_get_channel_info(priv,
+                                               band, channel);
+                                       if (is_channel_valid(ch_info))
+                                               break;
+                       }
+               }
+       }
+       if (channel) {
+               scan_ch->channel = cpu_to_le16(channel);
+               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+               added++;
+       } else
+               IWL_ERR(priv, "no valid channel found\n");
+       return added;
+}
+
 static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                                     enum ieee80211_band band,
                                     u8 is_active, u8 n_probes,
@@ -421,6 +488,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
 
        IWL_DEBUG_INFO(priv, "Starting scan...\n");
        set_bit(STATUS_SCANNING, &priv->status);
+       priv->is_internal_short_scan = false;
        priv->scan_start = jiffies;
        priv->scan_pass_start = priv->scan_start;
 
@@ -461,15 +529,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /* if we just finished scan ask for delay */
-       if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
-           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
-               IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n");
-               queue_work(priv->workqueue, &priv->scan_completed);
-               ret = 0;
-               goto out_unlock;
-       }
-
        priv->scan_bands = 0;
        for (i = 0; i < req->n_channels; i++)
                priv->scan_bands |= BIT(req->channels[i]->band);
@@ -488,6 +547,54 @@ out_unlock:
 }
 EXPORT_SYMBOL(iwl_mac_hw_scan);
 
+/*
+ * internal short scan, this function should only been called while associated.
+ * It will reset and tune the radio to prevent possible RF related problem
+ */
+#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1)
+
+int iwl_internal_short_hw_scan(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       if (!iwl_is_ready_rf(priv)) {
+               ret = -EIO;
+               IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
+               goto out;
+       }
+       if (test_bit(STATUS_SCANNING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
+               ret = -EAGAIN;
+               goto out;
+       }
+       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
+               ret = -EAGAIN;
+               goto out;
+       }
+       if (priv->last_internal_scan_jiffies &&
+           time_after(priv->last_internal_scan_jiffies +
+                      IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) {
+               IWL_DEBUG_SCAN(priv, "internal scan rejected\n");
+               goto out;
+       }
+
+       priv->scan_bands = 0;
+       if (priv->band == IEEE80211_BAND_5GHZ)
+               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
+       else
+               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+
+       IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
+       set_bit(STATUS_SCANNING, &priv->status);
+       priv->is_internal_short_scan = true;
+       queue_work(priv->workqueue, &priv->request_scan);
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(iwl_internal_short_hw_scan);
+
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 void iwl_bg_scan_check(struct work_struct *data)
@@ -551,7 +658,8 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
        if (WARN_ON(left < ie_len))
                return len;
 
-       memcpy(pos, ies, ie_len);
+       if (ies)
+               memcpy(pos, ies, ie_len);
        len += ie_len;
        left -= ie_len;
 
@@ -654,7 +762,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
                unsigned long flags;
 
                IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-
                spin_lock_irqsave(&priv->lock, flags);
                interval = priv->beacon_int;
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -672,7 +779,9 @@ static void iwl_bg_request_scan(struct work_struct *data)
                               scan_suspend_time, interval);
        }
 
-       if (priv->scan_request->n_ssids) {
+       if (priv->is_internal_short_scan) {
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+       } else if (priv->scan_request->n_ssids) {
                int i, p = 0;
                IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
                for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -753,24 +862,38 @@ static void iwl_bg_request_scan(struct work_struct *data)
        rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
        rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
        scan->rx_chain = cpu_to_le16(rx_chain);
-       cmd_len = iwl_fill_probe_req(priv,
-                               (struct ieee80211_mgmt *)scan->data,
-                               priv->scan_request->ie,
-                               priv->scan_request->ie_len,
-                               IWL_MAX_SCAN_SIZE - sizeof(*scan));
+       if (!priv->is_internal_short_scan) {
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       priv->scan_request->ie,
+                                       priv->scan_request->ie_len,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
+       } else {
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       NULL, 0,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
 
+       }
        scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
        if (iwl_is_monitor_mode(priv))
                scan->filter_flags = RXON_FILTER_PROMISC_MSK;
 
        scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
                               RXON_FILTER_BCON_AWARE_MSK);
 
-       scan->channel_count =
-               iwl_get_channels_for_scan(priv, band, is_active, n_probes,
-                       (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-
+       if (priv->is_internal_short_scan) {
+               scan->channel_count =
+                       iwl_get_single_channel_for_scan(priv, band,
+                               (void *)&scan->data[le16_to_cpu(
+                               scan->tx_cmd.len)]);
+       } else {
+               scan->channel_count =
+                       iwl_get_channels_for_scan(priv, band,
+                               is_active, n_probes,
+                               (void *)&scan->data[le16_to_cpu(
+                               scan->tx_cmd.len)]);
+       }
        if (scan->channel_count == 0) {
                IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
                goto done;
@@ -831,7 +954,12 @@ void iwl_bg_scan_completed(struct work_struct *work)
 
        cancel_delayed_work(&priv->scan_check);
 
-       ieee80211_scan_completed(priv->hw, false);
+       if (!priv->is_internal_short_scan)
+               ieee80211_scan_completed(priv->hw, false);
+       else {
+               priv->is_internal_short_scan = false;
+               IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
+       }
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
deleted file mode 100644 (file)
index 1ea5cd3..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-io.h"
-#include "iwl-spectrum.h"
-
-#define BEACON_TIME_MASK_LOW   0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH  0xFF000000
-#define TIME_UNIT              1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-/* TOOD: was used in sysfs debug interface need to add to mac */
-#if 0
-static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
-       u32 quot;
-       u32 rem;
-       u32 interval = beacon_interval * 1024;
-
-       if (!interval || !usec)
-               return 0;
-
-       quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
-       rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
-       return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
-       u32 base_low = base & BEACON_TIME_MASK_LOW;
-       u32 addon_low = addon & BEACON_TIME_MASK_LOW;
-       u32 interval = beacon_interval * TIME_UNIT;
-       u32 res = (base & BEACON_TIME_MASK_HIGH) +
-           (addon & BEACON_TIME_MASK_HIGH);
-
-       if (base_low > addon_low)
-               res += base_low - addon_low;
-       else if (base_low < addon_low) {
-               res += interval + base_low - addon_low;
-               res += (1 << 24);
-       } else
-               res += (1 << 24);
-
-       return cpu_to_le32(res);
-}
-static int iwl_get_measurement(struct iwl_priv *priv,
-                              struct ieee80211_measurement_params *params,
-                              u8 type)
-{
-       struct iwl4965_spectrum_cmd spectrum;
-       struct iwl_rx_packet *res;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
-               .data = (void *)&spectrum,
-               .meta.flags = CMD_WANT_SKB,
-       };
-       u32 add_time = le64_to_cpu(params->start_time);
-       int rc;
-       int spectrum_resp_status;
-       int duration = le16_to_cpu(params->duration);
-
-       if (iwl_is_associated(priv))
-               add_time =
-                   iwl_usecs_to_beacons(
-                       le64_to_cpu(params->start_time) - priv->last_tsf,
-                       le16_to_cpu(priv->rxon_timing.beacon_interval));
-
-       memset(&spectrum, 0, sizeof(spectrum));
-
-       spectrum.channel_count = cpu_to_le16(1);
-       spectrum.flags =
-           RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
-       spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
-       cmd.len = sizeof(spectrum);
-       spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
-
-       if (iwl_is_associated(priv))
-               spectrum.start_time =
-                   iwl_add_beacon_time(priv->last_beacon_time,
-                               add_time,
-                               le16_to_cpu(priv->rxon_timing.beacon_interval));
-       else
-               spectrum.start_time = 0;
-
-       spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
-       spectrum.channels[0].channel = params->channel;
-       spectrum.channels[0].type = type;
-       if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
-               spectrum.flags |= RXON_FLG_BAND_24G_MSK |
-                   RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
-
-       rc = iwl_send_cmd_sync(priv, &cmd);
-       if (rc)
-               return rc;
-
-       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
-               rc = -EIO;
-       }
-
-       spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
-       switch (spectrum_resp_status) {
-       case 0:         /* Command will be handled */
-               if (res->u.spectrum.id != 0xff) {
-                       IWL_DEBUG_INFO(priv,
-                               "Replaced existing measurement: %d\n",
-                               res->u.spectrum.id);
-                       priv->measurement_status &= ~MEASUREMENT_READY;
-               }
-               priv->measurement_status |= MEASUREMENT_ACTIVE;
-               rc = 0;
-               break;
-
-       case 1:         /* Command will not be handled */
-               rc = -EAGAIN;
-               break;
-       }
-
-       dev_kfree_skb_any(cmd.meta.u.skb);
-
-       return rc;
-}
-#endif
-
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
-       if (!report->state) {
-               IWL_DEBUG_11H(priv,
-                       "Spectrum Measure Notification: Start\n");
-               return;
-       }
-
-       memcpy(&priv->measure_report, report, sizeof(*report));
-       priv->measurement_status |= MEASUREMENT_READY;
-}
-
-void iwl_setup_spectrum_handlers(struct iwl_priv *priv)
-{
-       priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-                       iwl_rx_spectrum_measure_notif;
-}
-EXPORT_SYMBOL(iwl_setup_spectrum_handlers);
index a77c1e6190623bd536e287a2a762b5b464ee0ffa..af6babee28915f1d9a0d81d5b4d8a1818134c8f5 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ieee80211 subsystem header files.
  *
index 90fbdb25399e14ed32d831cefeac0571ea74f44e..4a6686fa6b3649971c218bd060836ef0ba64084a 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -80,46 +80,103 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 }
 EXPORT_SYMBOL(iwl_get_ra_sta_id);
 
+/* priv->sta_lock must be held */
 static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
 
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
-               IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
-                       sta_id);
-
-       priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
-       IWL_DEBUG_ASSOC(priv, "Added STA to Ucode: %pM\n",
-                       priv->stations[sta_id].sta.sta.addr);
+               IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n",
+                       sta_id, priv->stations[sta_id].sta.sta.addr);
 
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) {
+               IWL_DEBUG_ASSOC(priv,
+                               "STA id %u addr %pM already present in uCode (according to driver)\n",
+                               sta_id, priv->stations[sta_id].sta.sta.addr);
+       } else {
+               priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
+               IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n",
+                               sta_id, priv->stations[sta_id].sta.sta.addr);
+       }
 }
 
-static void iwl_add_sta_callback(struct iwl_priv *priv,
-                                struct iwl_device_cmd *cmd,
-                                struct iwl_rx_packet *pkt)
+static void iwl_process_add_sta_resp(struct iwl_priv *priv,
+                                    struct iwl_addsta_cmd *addsta,
+                                    struct iwl_rx_packet *pkt,
+                                    bool sync)
 {
-       struct iwl_addsta_cmd *addsta =
-               (struct iwl_addsta_cmd *)cmd->cmd.payload;
        u8 sta_id = addsta->sta.sta_id;
+       unsigned long flags;
 
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
                IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
-                         pkt->hdr.flags);
+                       pkt->hdr.flags);
                return;
        }
 
+       IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",
+                      sta_id);
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+
        switch (pkt->u.add_sta.status) {
        case ADD_STA_SUCCESS_MSK:
+               IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
                iwl_sta_ucode_activate(priv, sta_id);
-                /* fall through */
+               break;
+       case ADD_STA_NO_ROOM_IN_TABLE:
+               IWL_ERR(priv, "Adding station %d failed, no room in table.\n",
+                       sta_id);
+               break;
+       case ADD_STA_NO_BLOCK_ACK_RESOURCE:
+               IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n",
+                       sta_id);
+               break;
+       case ADD_STA_MODIFY_NON_EXIST_STA:
+               IWL_ERR(priv, "Attempting to modify non-existing station %d \n",
+                       sta_id);
+               break;
        default:
-               IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
-                            pkt->u.add_sta.status);
+               IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
+                               pkt->u.add_sta.status);
                break;
        }
+
+       IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n",
+                      priv->stations[sta_id].sta.mode ==
+                      STA_CONTROL_MODIFY_MSK ?  "Modified" : "Added",
+                      sta_id, priv->stations[sta_id].sta.sta.addr);
+
+       /*
+        * XXX: The MAC address in the command buffer is often changed from
+        * the original sent to the device. That is, the MAC address
+        * written to the command buffer often is not the same MAC adress
+        * read from the command buffer when the command returns. This
+        * issue has not yet been resolved and this debugging is left to
+        * observe the problem.
+        */
+       IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n",
+                      priv->stations[sta_id].sta.mode ==
+                      STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
+                      addsta->sta.addr);
+
+       /*
+        * Determine if we wanted to modify or add a station,
+        * if adding a station succeeded we have some more initialization
+        * to do when using station notification. TODO
+        */
+
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+static void iwl_add_sta_callback(struct iwl_priv *priv,
+                                struct iwl_device_cmd *cmd,
+                                struct iwl_rx_packet *pkt)
+{
+       struct iwl_addsta_cmd *addsta =
+               (struct iwl_addsta_cmd *)cmd->cmd.payload;
+
+       iwl_process_add_sta_resp(priv, addsta, pkt, false);
+
 }
 
 int iwl_send_add_sta(struct iwl_priv *priv,
@@ -145,24 +202,9 @@ int iwl_send_add_sta(struct iwl_priv *priv,
        if (ret || (flags & CMD_ASYNC))
                return ret;
 
-       pkt = (struct iwl_rx_packet *)cmd.reply_page;
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
-                         pkt->hdr.flags);
-               ret = -EIO;
-       }
-
        if (ret == 0) {
-               switch (pkt->u.add_sta.status) {
-               case ADD_STA_SUCCESS_MSK:
-                       iwl_sta_ucode_activate(priv, sta->sta.sta_id);
-                       IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
-                       break;
-               default:
-                       ret = -EIO;
-                       IWL_WARN(priv, "REPLY_ADD_STA failed\n");
-                       break;
-               }
+               pkt = (struct iwl_rx_packet *)cmd.reply_page;
+               iwl_process_add_sta_resp(priv, sta, pkt, true);
        }
        iwl_free_pages(priv, cmd.reply_page);
 
@@ -1003,24 +1045,19 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
        struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
        u8 sta_id;
 
-       /* Add station to device's station table */
-
        /*
-        * XXX: This check is definitely not correct, if we're an AP
-        *      it'll always be false which is not what we want, but
-        *      it doesn't look like iwlagn is prepared to be an HT
-        *      AP anyway.
+        * Set HT capabilities. It is ok to set this struct even if not using
+        * HT config: the priv->current_ht_config.is_ht flag will just be false
         */
-       if (priv->current_ht_config.is_ht) {
-               rcu_read_lock();
-               sta = ieee80211_find_sta(priv->vif, addr);
-               if (sta) {
-                       memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
-                       cur_ht_config = &ht_config;
-               }
-               rcu_read_unlock();
+       rcu_read_lock();
+       sta = ieee80211_find_sta(priv->vif, addr);
+       if (sta) {
+               memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
+               cur_ht_config = &ht_config;
        }
+       rcu_read_unlock();
 
+       /* Add station to device's station table */
        sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
 
        /* Set up default rate scaling table in device's station table */
@@ -1085,6 +1122,7 @@ static void iwl_sta_init_bcast_lq(struct iwl_priv *priv)
  */
 void iwl_add_bcast_station(struct iwl_priv *priv)
 {
+       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
        iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
 
        /* Set up default rate scaling table in device's station table */
@@ -1092,6 +1130,16 @@ void iwl_add_bcast_station(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_add_bcast_station);
 
+/**
+ * iwl3945_add_bcast_station - add broadcast station into station table.
+ */
+void iwl3945_add_bcast_station(struct iwl_priv *priv)
+{
+       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
+       iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
+}
+EXPORT_SYMBOL(iwl3945_add_bcast_station);
+
 /**
  * iwl_get_sta_id - Find station's index within station table
  *
index 8d052de2d40579fd0d9ac9fea5cb8ba4ad9f35db..2dc35fe28f56420e9a3fcaef2a57d6105bc54cb9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -53,6 +53,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
 
 int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
 void iwl_add_bcast_station(struct iwl_priv *priv);
+void iwl3945_add_bcast_station(struct iwl_priv *priv);
 int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
 void iwl_clear_stations_table(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
index 87ce2bd292c7810630cd382239a15283f82add76..d365d13e32917e6b2c13218c6fa79ceb059fc014 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
index 10b0aa8024c435d017e0455265ea9e24663e71eb..119da54116de696400fdf547df16af6bc4cbd716 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -56,6 +56,7 @@
 #include "iwl-helpers.h"
 #include "iwl-core.h"
 #include "iwl-dev.h"
+#include "iwl-spectrum.h"
 
 /*
  * module name, copyright, version, etc.
 #define VD
 #endif
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define DRV_VERSION  IWLWIFI_VERSION VD VS
-#define DRV_COPYRIGHT  "Copyright(c) 2003-2009 Intel Corporation"
+/*
+ * add "s" to indicate spectrum measurement included.
+ * we add it here to be consistent with previous releases in which
+ * this was configurable.
+ */
+#define DRV_VERSION  IWLWIFI_VERSION VD "s"
+#define DRV_COPYRIGHT  "Copyright(c) 2003-2010 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -689,10 +689,6 @@ drop:
        return -1;
 }
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
 #define BEACON_TIME_MASK_LOW   0x00FFFFFF
 #define BEACON_TIME_MASK_HIGH  0xFF000000
 #define TIME_UNIT              1024
@@ -819,7 +815,6 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 
        return rc;
 }
-#endif
 
 static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb)
@@ -962,6 +957,8 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
        priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
        priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+       priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+                       iwl_rx_spectrum_measure_notif;
        priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
        priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
            iwl_rx_pm_debug_statistics_notif;
@@ -975,7 +972,6 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
-       iwl_setup_spectrum_handlers(priv);
        iwl_setup_rx_scan_handlers(priv);
        priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
 
@@ -1644,7 +1640,7 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
        if (!iwl3945_hw_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return pos;
+               return  -EINVAL;
        }
 
        /* event log header */
@@ -1693,7 +1689,7 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                        bufsz = size * 48;
                *buf = kmalloc(bufsz, GFP_KERNEL);
                if (!*buf)
-                       return pos;
+                       return -ENOMEM;
        }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /* if uCode has wrapped back to top of log,
@@ -3037,18 +3033,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        mutex_unlock(&priv->mutex);
 }
 
-static void iwl3945_bg_up(struct work_struct *data)
-{
-       struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-       __iwl3945_up(priv);
-       mutex_unlock(&priv->mutex);
-}
-
 static void iwl3945_bg_restart(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -3065,7 +3049,13 @@ static void iwl3945_bg_restart(struct work_struct *data)
                ieee80211_restart_hw(priv->hw);
        } else {
                iwl3945_down(priv);
-               queue_work(priv->workqueue, &priv->up);
+
+               if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       return;
+
+               mutex_lock(&priv->mutex);
+               __iwl3945_up(priv);
+               mutex_unlock(&priv->mutex);
        }
 }
 
@@ -3569,8 +3559,6 @@ static ssize_t store_filter_flags(struct device *d,
 static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
                   store_filter_flags);
 
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-
 static ssize_t show_measurement(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
@@ -3640,7 +3628,6 @@ static ssize_t store_measurement(struct device *d,
 
 static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
                   show_measurement, store_measurement);
-#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
 
 static ssize_t store_retry_rate(struct device *d,
                                struct device_attribute *attr,
@@ -3789,7 +3776,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
 
        init_waitqueue_head(&priv->wait_command_queue);
 
-       INIT_WORK(&priv->up, iwl3945_bg_up);
        INIT_WORK(&priv->restart, iwl3945_bg_restart);
        INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish);
        INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
@@ -3823,9 +3809,7 @@ static struct attribute *iwl3945_sysfs_entries[] = {
        &dev_attr_dump_errors.attr,
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
        &dev_attr_measurement.attr,
-#endif
        &dev_attr_retry_rate.attr,
        &dev_attr_statistics.attr,
        &dev_attr_status.attr,
@@ -3881,6 +3865,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 
        iwl_reset_qos(priv);
 
index 5e650f35841545313d160baf4e658d48bb83d2a8..f03d5e4e59c31c1da78c271d4665f158825c712f 100644 (file)
@@ -1160,11 +1160,11 @@ int lbs_adhoc_stop(struct lbs_private *priv)
 static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
                                        struct bss_descriptor *match_bss)
 {
-       if (!secinfo->wep_enabled  && !secinfo->WPAenabled
-           && !secinfo->WPA2enabled
-           && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
-           && match_bss->rsn_ie[0] != WLAN_EID_RSN
-           && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+       if (!secinfo->wep_enabled &&
+           !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+           match_bss->wpa_ie[0] != WLAN_EID_GENERIC &&
+           match_bss->rsn_ie[0] != WLAN_EID_RSN &&
+           !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
                return 1;
        else
                return 0;
@@ -1173,9 +1173,9 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
 static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
                                       struct bss_descriptor *match_bss)
 {
-       if (secinfo->wep_enabled && !secinfo->WPAenabled
-           && !secinfo->WPA2enabled
-           && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+       if (secinfo->wep_enabled &&
+           !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+           (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
                return 1;
        else
                return 0;
@@ -1184,8 +1184,8 @@ static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
 static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
                                struct bss_descriptor *match_bss)
 {
-       if (!secinfo->wep_enabled && secinfo->WPAenabled
-           && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
+       if (!secinfo->wep_enabled && secinfo->WPAenabled &&
+           (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
            /* privacy bit may NOT be set in some APs like LinkSys WRT54G
            && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
           )
@@ -1210,11 +1210,11 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
 static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
                                        struct bss_descriptor *match_bss)
 {
-       if (!secinfo->wep_enabled && !secinfo->WPAenabled
-           && !secinfo->WPA2enabled
-           && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
-           && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
-           && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
+       if (!secinfo->wep_enabled &&
+           !secinfo->WPAenabled && !secinfo->WPA2enabled &&
+           (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) &&
+           (match_bss->rsn_ie[0] != WLAN_EID_RSN) &&
+           (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
                return 1;
        else
                return 0;
@@ -1525,8 +1525,8 @@ static int assoc_helper_associate(struct lbs_private *priv,
        /* If we're given and 'any' BSSID, try associating based on SSID */
 
        if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               if (compare_ether_addr(bssid_any, assoc_req->bssid)
-                   && compare_ether_addr(bssid_off, assoc_req->bssid)) {
+               if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
+                   compare_ether_addr(bssid_off, assoc_req->bssid)) {
                        ret = assoc_helper_bssid(priv, assoc_req);
                        done = 1;
                }
@@ -1612,11 +1612,9 @@ static int assoc_helper_channel(struct lbs_private *priv,
                goto restore_mesh;
        }
 
-       if (   assoc_req->secinfo.wep_enabled
-           &&   (assoc_req->wep_keys[0].len
-              || assoc_req->wep_keys[1].len
-              || assoc_req->wep_keys[2].len
-              || assoc_req->wep_keys[3].len)) {
+       if (assoc_req->secinfo.wep_enabled &&
+           (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
+            assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
                /* Make sure WEP keys are re-sent to firmware */
                set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
        }
@@ -1983,14 +1981,14 @@ void lbs_association_worker(struct work_struct *work)
                assoc_req->secinfo.auth_mode);
 
        /* If 'any' SSID was specified, find an SSID to associate with */
-       if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
-           && !assoc_req->ssid_len)
+       if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
+           !assoc_req->ssid_len)
                find_any_ssid = 1;
 
        /* But don't use 'any' SSID if there's a valid locked BSSID to use */
        if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-               if (compare_ether_addr(assoc_req->bssid, bssid_any)
-                   && compare_ether_addr(assoc_req->bssid, bssid_off))
+               if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
+                   compare_ether_addr(assoc_req->bssid, bssid_off))
                        find_any_ssid = 0;
        }
 
@@ -2052,13 +2050,6 @@ void lbs_association_worker(struct work_struct *work)
                        goto out;
        }
 
-       if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
-           || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
-               ret = assoc_helper_wep_keys(priv, assoc_req);
-               if (ret)
-                       goto out;
-       }
-
        if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
                ret = assoc_helper_secinfo(priv, assoc_req);
                if (ret)
@@ -2071,18 +2062,31 @@ void lbs_association_worker(struct work_struct *work)
                        goto out;
        }
 
-       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
-           || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+       /*
+        * v10 FW wants WPA keys to be set/cleared before WEP key operations,
+        * otherwise it will fail to correctly associate to WEP networks.
+        * Other firmware versions don't appear to care.
+        */
+       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
+           test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
                ret = assoc_helper_wpa_keys(priv, assoc_req);
                if (ret)
                        goto out;
        }
 
+       if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
+           test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+               ret = assoc_helper_wep_keys(priv, assoc_req);
+               if (ret)
+                       goto out;
+       }
+
+
        /* SSID/BSSID should be the _last_ config option set, because they
         * trigger the association attempt.
         */
-       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
-           || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+       if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
+           test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
                int success = 1;
 
                ret = assoc_helper_associate(priv, assoc_req);
index 84df3fcf37b393c35d4fac12ce948448a7191d12..0dbda8dfbd9941bcbcaaa36e3d58e3065283b55f 100644 (file)
@@ -281,6 +281,8 @@ struct mac80211_hwsim_data {
        struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
        struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
 
+       struct mac_address addresses[2];
+
        struct ieee80211_channel *channel;
        unsigned long beacon_int; /* in jiffies unit */
        unsigned int rx_filter;
@@ -1154,7 +1156,11 @@ static int __init init_mac80211_hwsim(void)
                SET_IEEE80211_DEV(hw, data->dev);
                addr[3] = i >> 8;
                addr[4] = i;
-               SET_IEEE80211_PERM_ADDR(hw, addr);
+               memcpy(data->addresses[0].addr, addr, ETH_ALEN);
+               memcpy(data->addresses[1].addr, addr, ETH_ALEN);
+               data->addresses[1].addr[0] |= 0x40;
+               hw->wiphy->n_addresses = 2;
+               hw->wiphy->addresses = data->addresses;
 
                hw->channel_change_time = 1;
                hw->queues = 4;
index 68546ca0ba378b72a602ffd08e04eaafe958958c..f0f08f3919ccdc536ade931d6bb591ac6fe86b2c 100644 (file)
@@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
        struct mwl8k_priv *priv =
                container_of(work, struct mwl8k_priv, finalize_join_worker);
        struct sk_buff *skb = priv->beacon_skb;
-       struct mwl8k_vif *mwl8k_vif;
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+       const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM,
+                                        mgmt->u.beacon.variable, len);
+       int dtim_period = 1;
+
+       if (tim && tim[1] >= 2)
+               dtim_period = tim[3];
 
-       mwl8k_vif = mwl8k_first_vif(priv);
-       if (mwl8k_vif != NULL)
-               mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
-                                       mwl8k_vif->vif->bss_conf.dtim_period);
+       mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period);
 
        dev_kfree_skb(skb);
        priv->beacon_skb = NULL;
index 57c646598062c28e3b04aeef970192b780cde530..ed4bdffdd63e4ede90f262760dd1abbae27ffb88 100644 (file)
@@ -157,6 +157,14 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
                                                 skb_tail_pointer(skb),
                                                 priv->common.rx_mtu + 32,
                                                 PCI_DMA_FROMDEVICE);
+
+                       if (pci_dma_mapping_error(priv->pdev, mapping)) {
+                               dev_kfree_skb_any(skb);
+                               dev_err(&priv->pdev->dev,
+                                       "RX DMA Mapping error\n");
+                               break;
+                       }
+
                        desc->host_addr = cpu_to_le32(mapping);
                        desc->device_addr = 0;  // FIXME: necessary?
                        desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
@@ -226,14 +234,14 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
        p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
 }
 
-/* caller must hold priv->lock */
 static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
        int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       void **tx_buf)
+       struct sk_buff **tx_buf)
 {
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
        struct p54p_desc *desc;
+       struct sk_buff *skb;
        u32 idx, i;
 
        i = (*index) % ring_limit;
@@ -242,9 +250,8 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
 
        while (i != idx) {
                desc = &ring[i];
-               if (tx_buf[i])
-                       if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
-                               p54_free_skb(dev, tx_buf[i]);
+
+               skb = tx_buf[i];
                tx_buf[i] = NULL;
 
                pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@@ -255,17 +262,28 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
                desc->len = 0;
                desc->flags = 0;
 
+               if (skb && FREE_AFTER_TX(skb))
+                       p54_free_skb(dev, skb);
+
                i++;
                i %= ring_limit;
        }
 }
 
-static void p54p_rx_tasklet(unsigned long dev_id)
+static void p54p_tasklet(unsigned long dev_id)
 {
        struct ieee80211_hw *dev = (struct ieee80211_hw *)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);
 
@@ -280,59 +298,49 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 {
        struct ieee80211_hw *dev = dev_id;
        struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
        __le32 reg;
 
-       spin_lock(&priv->lock);
        reg = P54P_READ(int_ident);
        if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) {
-               spin_unlock(&priv->lock);
-               return IRQ_HANDLED;
+               goto out;
        }
-
        P54P_WRITE(int_ack, reg);
 
        reg &= P54P_READ(int_enable);
 
-       if (reg & cpu_to_le32(ISL38XX_INT_IDENT_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);
-
-               tasklet_schedule(&priv->rx_tasklet);
-
-       } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+       if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE))
+               tasklet_schedule(&priv->tasklet);
+       else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
                complete(&priv->boot_comp);
 
-       spin_unlock(&priv->lock);
-
+out:
        return reg ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
+       unsigned long flags;
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
-       unsigned long flags;
        struct p54p_desc *desc;
        dma_addr_t mapping;
        u32 device_idx, idx, i;
 
        spin_lock_irqsave(&priv->lock, flags);
-
        device_idx = le32_to_cpu(ring_control->device_idx[1]);
        idx = le32_to_cpu(ring_control->host_idx[1]);
        i = idx % ARRAY_SIZE(ring_control->tx_data);
 
-       priv->tx_buf_data[i] = skb;
        mapping = pci_map_single(priv->pdev, skb->data, skb->len,
                                 PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(priv->pdev, mapping)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               p54_free_skb(dev, skb);
+               dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
+               return ;
+       }
+       priv->tx_buf_data[i] = skb;
+
        desc = &ring_control->tx_data[i];
        desc->host_addr = cpu_to_le32(mapping);
        desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -354,14 +362,14 @@ static void p54p_stop(struct ieee80211_hw *dev)
        unsigned int i;
        struct p54p_desc *desc;
 
-       tasklet_kill(&priv->rx_tasklet);
-
        P54P_WRITE(int_enable, cpu_to_le32(0));
        P54P_READ(int_enable);
        udelay(10);
 
        free_irq(priv->pdev->irq, dev);
 
+       tasklet_kill(&priv->tasklet);
+
        P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
 
        for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
@@ -545,7 +553,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        priv->common.tx = p54p_tx;
 
        spin_lock_init(&priv->lock);
-       tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
+       tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
 
        err = request_firmware(&priv->firmware, "isl3886pci",
                               &priv->pdev->dev);
index fbb683953fb258b8949627398fff499fd21355fd..2feead617a3bf151d075f32cd87b2e0787f16417 100644 (file)
@@ -92,7 +92,7 @@ struct p54p_priv {
        struct p54_common common;
        struct pci_dev *pdev;
        struct p54p_csr __iomem *map;
-       struct tasklet_struct rx_tasklet;
+       struct tasklet_struct tasklet;
        const struct firmware *firmware;
        spinlock_t lock;
        struct p54p_ring_control *ring_control;
@@ -101,8 +101,8 @@ struct p54p_priv {
        u32 rx_idx_mgmt, tx_idx_mgmt;
        struct sk_buff *rx_buf_data[8];
        struct sk_buff *rx_buf_mgmt[4];
-       void *tx_buf_data[32];
-       void *tx_buf_mgmt[4];
+       struct sk_buff *tx_buf_data[32];
+       struct sk_buff *tx_buf_mgmt[4];
        struct completion boot_comp;
 };
 
index b9192bfcc5576168e306d4d768e9a0e4cf9f4185..2b928ecf47bdb9815289bf35819bd4fbe4cc42b9 100644 (file)
@@ -761,6 +761,14 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
        rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
 }
 
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
 static const struct ieee80211_ops rtl8180_ops = {
        .tx                     = rtl8180_tx,
        .start                  = rtl8180_start,
@@ -771,6 +779,7 @@ static const struct ieee80211_ops rtl8180_ops = {
        .bss_info_changed       = rtl8180_bss_info_changed,
        .prepare_multicast      = rtl8180_prepare_multicast,
        .configure_filter       = rtl8180_configure_filter,
+       .get_tsf                = rtl8180_get_tsf,
 };
 
 static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
index f336c63053c1a052bd31a146ef54cfc643a71812..a05382557789f5387876c639ad086dca6ed5844d 100644 (file)
@@ -1265,6 +1265,14 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
        return 0;
 }
 
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+{
+       struct rtl8187_priv *priv = dev->priv;
+
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
        .tx                     = rtl8187_tx,
        .start                  = rtl8187_start,
@@ -1276,7 +1284,8 @@ static const struct ieee80211_ops rtl8187_ops = {
        .prepare_multicast      = rtl8187_prepare_multicast,
        .configure_filter       = rtl8187_configure_filter,
        .conf_tx                = rtl8187_conf_tx,
-       .rfkill_poll            = rtl8187_rfkill_poll
+       .rfkill_poll            = rtl8187_rfkill_poll,
+       .get_tsf                = rtl8187_get_tsf,
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
index 6301578d15654e8cdccde6f3473fe7ff2417daf9..37c61c19cae5da8f99b95bc674abcd57c560ffb3 100644 (file)
@@ -341,9 +341,6 @@ struct wl1251 {
        /* Are we currently scanning */
        bool scanning;
 
-       /* Our association ID */
-       u16 aid;
-
        /* Default key (for WEP) */
        u32 default_key;
 
index 595f0f94d16ea03a6bc7eb8882b5a2429a1fe334..a717dde4822e1bdc3edd2a250b838d99621dbe99 100644 (file)
@@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 
                wl->psm_requested = true;
 
+               wl->dtim_period = conf->ps_dtim_period;
+
+               ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
+                                                 wl->dtim_period);
+
                /*
-                * We enter PSM only if we're already associated.
-                * If we're not, we'll enter it when joining an SSID,
-                * through the bss_info_changed() hook.
+                * mac80211 enables PSM only if we're already associated.
                 */
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
@@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                                       struct ieee80211_bss_conf *bss_conf,
                                       u32 changed)
 {
-       enum wl1251_cmd_ps_mode mode;
        struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon, *skb;
        int ret;
@@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
                        wl->beacon_int = bss_conf->beacon_int;
-                       wl->dtim_period = bss_conf->dtim_period;
-
-                       ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
-                                                         wl->dtim_period);
-                       wl->aid = bss_conf->aid;
 
                        skb = ieee80211_pspoll_get(wl->hw, wl->vif);
                        if (!skb)
@@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (ret < 0)
                                goto out_sleep;
 
-                       ret = wl1251_acx_aid(wl, wl->aid);
+                       ret = wl1251_acx_aid(wl, bss_conf->aid);
                        if (ret < 0)
                                goto out_sleep;
-
-                       /* If we want to go in PSM but we're not there yet */
-                       if (wl->psm_requested && !wl->psm) {
-                               mode = STATION_POWER_SAVE_MODE;
-                               ret = wl1251_ps_set_mode(wl, mode);
-                               if (ret < 0)
-                                       goto out_sleep;
-                       }
                } else {
                        /* use defaults when not associated */
                        wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
index 842701906ae9d2fbaa19d61f036542b146d0b210..19984958ab7b65fc5507f100edfd50c8d6a2acd7 100644 (file)
 #define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK   0x03
 #define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT  5
 
+#define IEEE80211_HT_CTL_LEN           4
+
 struct ieee80211_hdr {
        __le16 frame_control;
        __le16 duration_id;
index 2af52704e670590d9792a0d0a4b44e159e6104ef..a3f0a7ed31ac9ec3a1d3157aad284b873b5f71bb 100644 (file)
@@ -1195,6 +1195,10 @@ enum wiphy_flags {
        WIPHY_FLAG_4ADDR_STATION        = BIT(6),
 };
 
+struct mac_address {
+       u8 addr[ETH_ALEN];
+};
+
 /**
  * struct wiphy - wireless hardware description
  * @idx: the wiphy index assigned to this item
@@ -1213,12 +1217,28 @@ enum wiphy_flags {
  *     -1 = fragmentation disabled, only odd values >= 256 used
  * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
  * @net: the network namespace this wiphy currently lives in
+ * @perm_addr: permanent MAC address of this device
+ * @addr_mask: If the device supports multiple MAC addresses by masking,
+ *     set this to a mask with variable bits set to 1, e.g. if the last
+ *     four bits are variable then set it to 00:...:00:0f. The actual
+ *     variable bits shall be determined by the interfaces added, with
+ *     interfaces not matching the mask being rejected to be brought up.
+ * @n_addresses: number of addresses in @addresses.
+ * @addresses: If the device has more than one address, set this pointer
+ *     to a list of addresses (6 bytes each). The first one will be used
+ *     by default for perm_addr. In this case, the mask should be set to
+ *     all-zeroes. In this case it is assumed that the device can handle
+ *     the same number of arbitrary MAC addresses.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
 
-       /* permanent MAC address */
+       /* permanent MAC address(es) */
        u8 perm_addr[ETH_ALEN];
+       u8 addr_mask[ETH_ALEN];
+
+       u16 n_addresses;
+       struct mac_address *addresses;
 
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
@@ -1638,6 +1658,22 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
  */
 unsigned int cfg80211_classify8021d(struct sk_buff *skb);
 
+/**
+ * cfg80211_find_ie - find information element in data
+ *
+ * @eid: element ID
+ * @ies: data consisting of IEs
+ * @len: length of data
+ *
+ * This function will return %NULL if the element ID could
+ * not be found or if the element is invalid (claims to be
+ * longer than the given data), or a pointer to the first byte
+ * of the requested element, that is the byte containing the
+ * element ID. There are no checks on the element length
+ * other than having to fit into the given data.
+ */
+const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
+
 /*
  * Regulatory helper functions for wiphys
  */
index c90047de4428583d7f836de64f11fdd3978966a4..74ccf30fdf8ec74e743c2244dc878e74dc16456c 100644 (file)
@@ -186,7 +186,8 @@ enum ieee80211_bss_change {
  * @use_short_slot: use short slot time (only relevant for ERP);
  *     if the hardware cannot handle this it must set the
  *     IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
- * @dtim_period: num of beacons before the next DTIM, for PSM
+ * @dtim_period: num of beacons before the next DTIM, for beaconing,
+ *     not valid in station mode (cf. hw conf ps_dtim_period)
  * @timestamp: beacon timestamp
  * @beacon_int: beacon interval
  * @assoc_capability: capabilities taken from assoc resp
@@ -271,6 +272,11 @@ struct ieee80211_bss_conf {
  *     transmit function after the current frame, this can be used
  *     by drivers to kick the DMA queue only if unset or when the
  *     queue gets full.
+ * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
+ *     after TX status because the destination was asleep, it must not
+ *     be modified again (no seqno assignment, crypto, etc.)
+ * @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still
+ *     has a radiotap header at skb->data.
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
@@ -291,6 +297,8 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
        IEEE80211_TX_CTL_PSPOLL_RESPONSE        = BIT(17),
        IEEE80211_TX_CTL_MORE_FRAMES            = BIT(18),
+       IEEE80211_TX_INTFL_RETRANSMISSION       = BIT(19),
+       IEEE80211_TX_INTFL_HAS_RADIOTAP         = BIT(20),
 };
 
 /**
@@ -644,6 +652,9 @@ enum ieee80211_smps_mode {
  *     value will be only achievable between DTIM frames, the hardware
  *     needs to check for the multicast traffic bit in DTIM beacons.
  *     This variable is valid only when the CONF_PS flag is set.
+ * @ps_dtim_period: The DTIM period of the AP we're connected to, for use
+ *     in power saving. Power saving will not be enabled until a beacon
+ *     has been received and the DTIM period is known.
  * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
  *     powersave documentation below. This variable is valid only when
  *     the CONF_PS flag is set.
@@ -670,6 +681,7 @@ struct ieee80211_conf {
        int max_sleep_period;
 
        u16 listen_interval;
+       u8 ps_dtim_period;
 
        u8 long_frame_max_tx_count, short_frame_max_tx_count;
 
@@ -1485,7 +1497,7 @@ enum ieee80211_ampdu_mlme_action {
  * @update_tkip_key: See the section "Hardware crypto acceleration"
  *     This callback will be called in the context of Rx. Called for drivers
  *     which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
- *     The callback can sleep.
+ *     The callback must be atomic.
  *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *     the scan state machine in stack. The scan must honour the channel
@@ -1610,8 +1622,10 @@ struct ieee80211_ops {
                       struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                       struct ieee80211_key_conf *key);
        void (*update_tkip_key)(struct ieee80211_hw *hw,
-                       struct ieee80211_key_conf *conf, const u8 *address,
-                       u32 iv32, u16 *phase1key);
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_key_conf *conf,
+                               struct ieee80211_sta *sta,
+                               u32 iv32, u16 *phase1key);
        int (*hw_scan)(struct ieee80211_hw *hw,
                       struct cfg80211_scan_request *req);
        void (*sw_scan_start)(struct ieee80211_hw *hw);
index 47995b81c5d72ee3582b328b8cbfca246a8778b1..f873ee37f7e4d5e341d1fcd3a303f15f82b08579 100644 (file)
@@ -39,6 +39,7 @@ enum environment_cap {
  *     00 - World regulatory domain
  *     99 - built by driver but a specific alpha2 cannot be determined
  *     98 - result of an intersection between two regulatory domains
+ *     97 - regulatory domain has not yet been configured
  * @intersect: indicates whether the wireless core should intersect
  *     the requested regulatory domain with the presently set regulatory
  *     domain.
index 0d4a759ba72c1ae0e60129dd3d095002f0da9eb9..d92800bb2d2f4c0ec2cfe3333548e992aee1fb8c 100644 (file)
@@ -120,36 +120,38 @@ 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[30 + STA_TID_NUM * 70], *p = buf;
+       char buf[64 + STA_TID_NUM * 40], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
 
        spin_lock_bh(&sta->lock);
-       p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n",
+       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");
        for (i = 0; i < STA_TID_NUM; i++) {
-               p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i);
-               p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x",
+               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]);
-               p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
                                sta->ampdu_mlme.tid_state_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
-               p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
                                sta->ampdu_mlme.tid_state_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->ssn : 0);
 
-               p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
                                sta->ampdu_mlme.tid_state_tx[i]);
-               p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
                                sta->ampdu_mlme.tid_state_tx[i] ?
                                sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
-               p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
                                sta->ampdu_mlme.tid_state_tx[i] ?
                                sta->ampdu_mlme.tid_tx[i]->ssn : 0);
-               p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d",
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
                                sta->ampdu_mlme.tid_state_tx[i] ?
                                skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
-               p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+               p += scnprintf(p, sizeof(buf) + buf - p, "\n");
        }
        spin_unlock_bh(&sta->lock);
 
@@ -165,7 +167,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
        if (_cond) \
                        p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \
        } while (0)
-       char buf[1024], *p = buf;
+       char buf[512], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
        struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
index de91d39e02762c496dc27a2c8e4bc8dd04884092..6c31f38ac7f5b9a825c1d8c7ae1850399191cf50 100644 (file)
@@ -137,16 +137,20 @@ static inline int drv_set_key(struct ieee80211_local *local,
 }
 
 static inline void drv_update_tkip_key(struct ieee80211_local *local,
+                                      struct ieee80211_sub_if_data *sdata,
                                       struct ieee80211_key_conf *conf,
-                                      const u8 *address, u32 iv32,
+                                      struct sta_info *sta, u32 iv32,
                                       u16 *phase1key)
 {
-       might_sleep();
+       struct ieee80211_sta *ista = NULL;
+
+       if (sta)
+               ista = &sta->sta;
 
        if (local->ops->update_tkip_key)
-               local->ops->update_tkip_key(&local->hw, conf, address,
-                                           iv32, phase1key);
-       trace_drv_update_tkip_key(local, conf, address, iv32);
+               local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
+                                           ista, iv32, phase1key);
+       trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
 }
 
 static inline int drv_hw_scan(struct ieee80211_local *local,
index d6bd9f5174014655c9597dc0d36256c0c17a6f8a..502424b2538a8220a9aa456b34b2db966b2c7d2a 100644 (file)
@@ -331,26 +331,29 @@ TRACE_EVENT(drv_set_key,
 
 TRACE_EVENT(drv_update_tkip_key,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_key_conf *conf,
-                const u8 *address, u32 iv32),
+                struct ieee80211_sta *sta, u32 iv32),
 
-       TP_ARGS(local, conf, address, iv32),
+       TP_ARGS(local, sdata, conf, sta, iv32),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
-               __array(u8, addr, 6)
+               VIF_ENTRY
+               STA_ENTRY
                __field(u32, iv32)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
-               memcpy(__entry->addr, address, 6);
+               VIF_ASSIGN;
+               STA_ASSIGN;
                __entry->iv32 = iv32;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " addr:%pM iv32:%#x",
-               LOCAL_PR_ARG, __entry->addr, __entry->iv32
+               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
+               LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
        )
 );
 
index 5bcde4c3fba1595569dd1675a18dbe48053d1fb0..f95750b423e38328d27d49fb823ab7b7021257e4 100644 (file)
@@ -293,12 +293,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        /* check if we need to merge IBSS */
 
-       /* merge only on beacons (???) */
-       if (!beacon)
-               goto put_bss;
-
        /* we use a fixed BSSID */
-       if (sdata->u.ibss.bssid)
+       if (sdata->u.ibss.fixed_bssid)
                goto put_bss;
 
        /* not an IBSS */
@@ -454,6 +450,9 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
        return active;
 }
 
+/*
+ * This function is called with state == IEEE80211_IBSS_MLME_JOINED
+ */
 
 static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
 {
@@ -519,6 +518,10 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
                                  capability, 0);
 }
 
+/*
+ * This function is called with state == IEEE80211_IBSS_MLME_SEARCH
+ */
+
 static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
@@ -575,18 +578,14 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
        /* Selected IBSS not found in current scan results - try to scan */
-       if (ifibss->state == IEEE80211_IBSS_MLME_JOINED &&
-           !ieee80211_sta_active_ibss(sdata)) {
-               mod_timer(&ifibss->timer,
-                         round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
-       } else if (time_after(jiffies, ifibss->last_scan_completed +
+       if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
                       "join\n", sdata->name);
 
                ieee80211_request_internal_scan(sdata, ifibss->ssid,
                                                ifibss->ssid_len);
-       } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
+       } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
                if (time_after(jiffies, ifibss->ibss_join_req +
@@ -604,7 +603,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                        interval = IEEE80211_SCAN_INTERVAL_SLOW;
                }
 
-               ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
                mod_timer(&ifibss->timer,
                          round_jiffies(jiffies + interval));
        }
index c18f576f18481fa31b587fdbd84a8c5e84edaa2b..3067fbd69d6360e51c1832032317a39180b1ad5e 100644 (file)
@@ -299,7 +299,6 @@ struct ieee80211_work {
                } assoc;
                struct {
                        u32 duration;
-                       bool started;
                } remain;
        };
 
index edf21cebeee8984b5b5f1852520fea2065a51e21..09fff4662e80d13429ced56f48e78a3e23d5e724 100644 (file)
@@ -695,10 +695,14 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
 
        hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
 
-       if (!ieee80211_is_data_qos(hdr->frame_control)) {
+       if (!ieee80211_is_data(hdr->frame_control)) {
                skb->priority = 7;
                return ieee802_1d_to_ac[skb->priority];
        }
+       if (!ieee80211_is_data_qos(hdr->frame_control)) {
+               skb->priority = 0;
+               return ieee802_1d_to_ac[skb->priority];
+       }
 
        p = ieee80211_get_qos_ctl(hdr);
        skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
index 1e1d16c55ee57be5e9c4366d7c8094454e943e5d..86c6ad1b058df8511cb36e5c3e2c67994db58cfb 100644 (file)
@@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 
        if (count == 1 && found->u.mgd.powersave &&
            found->u.mgd.associated &&
+           found->u.mgd.associated->beacon_ies &&
            !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
                                    IEEE80211_STA_CONNECTION_POLL))) {
                s32 beaconint_us;
@@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
                } else {
-                       u8 dtimper = found->vif.bss_conf.dtim_period;
+                       struct ieee80211_bss *bss;
                        int maxslp = 1;
+                       u8 dtimper;
 
-                       if (dtimper > 1)
+                       bss = (void *)found->u.mgd.associated->priv;
+                       dtimper = bss->dtim_period;
+
+                       /* If the TIM IE is invalid, pretend the value is 1 */
+                       if (!dtimper)
+                               dtimper = 1;
+                       else if (dtimper > 1)
                                maxslp = min_t(int, dtimper,
                                                    latency / beaconint_us);
 
                        local->hw.conf.max_sleep_period = maxslp;
+                       local->hw.conf.ps_dtim_period = dtimper;
                        local->ps_sdata = found;
                }
        } else {
@@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        /* set timing information */
        sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
        sdata->vif.bss_conf.timestamp = cbss->tsf;
-       sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
        bss_info_changed |= BSS_CHANGED_BEACON_INT;
        bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        int freq;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
+       bool need_ps = false;
+
+       if (sdata->u.mgd.associated) {
+               bss = (void *)sdata->u.mgd.associated->priv;
+               /* not previously set so we may need to recalc */
+               need_ps = !bss->dtim_period;
+       }
 
        if (elems->ds_params && elems->ds_params_len == 1)
                freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
@@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        if (!sdata->u.mgd.associated)
                return;
 
+       if (need_ps) {
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
+       }
+
        if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
            (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
                                                        ETH_ALEN) == 0)) {
index 669dddd405210551a58cabc61d9c1580cf71edac..998cf7a935b66f80b01600816fb81205d97759ea 100644 (file)
@@ -44,6 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
        struct rate_control_ref *ref = local->rate_ctrl;
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
+
+       if (!ref)
+               return;
+
        ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
 }
 
index 29bc4c516238ed9cfafbd5c7416c0bdc13d528fd..2652a374974eb786cb80cd90ae42e5293840e054 100644 (file)
@@ -157,9 +157,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 
        /* In case nothing happened during the previous control interval, turn
         * the sharpening factor on. */
-       period = (HZ * pinfo->sampling_period + 500) / 1000;
-       if (!period)
-               period = 1;
+       period = msecs_to_jiffies(pinfo->sampling_period);
        if (jiffies - spinfo->last_sample > 2 * period)
                spinfo->sharp_cnt = pinfo->sharpen_duration;
 
@@ -252,9 +250,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba
        }
 
        /* Update PID controller state. */
-       period = (HZ * pinfo->sampling_period + 500) / 1000;
-       if (!period)
-               period = 1;
+       period = msecs_to_jiffies(pinfo->sampling_period);
        if (time_after(jiffies, spinfo->last_sample + period))
                rate_control_pid_sample(pinfo, sband, sta, spinfo);
 }
index a8e15b84c05ba7c88cca76a25f4370a95ba9765d..5709307fcb9b90ff1d578cbc9593508bd04070f3 100644 (file)
@@ -2348,22 +2348,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                                continue;
 
-                       rx.sta = sta_info_get(sdata, hdr->addr2);
-
-                       rx.flags |= IEEE80211_RX_RA_MATCH;
-                       prepares = prepare_for_handlers(sdata, &rx, hdr);
-
-                       if (!prepares)
-                               continue;
-
-                       if (status->flag & RX_FLAG_MMIC_ERROR) {
-                               rx.sdata = sdata;
-                               if (rx.flags & IEEE80211_RX_RA_MATCH)
-                                       ieee80211_rx_michael_mic_report(hdr,
-                                                                       &rx);
-                               continue;
-                       }
-
                        /*
                         * frame is destined for this interface, but if it's
                         * not also for the previous one we handle that after
@@ -2375,6 +2359,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                continue;
                        }
 
+                       rx.sta = sta_info_get_bss(prev, hdr->addr2);
+
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(prev, &rx, hdr);
+
+                       if (!prepares)
+                               goto next;
+
+                       if (status->flag & RX_FLAG_MMIC_ERROR) {
+                               rx.sdata = prev;
+                               if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                       ieee80211_rx_michael_mic_report(hdr,
+                                                                       &rx);
+                               goto next;
+                       }
+
                        /*
                         * frame was destined for the previous interface
                         * so invoke RX handlers for it
@@ -2387,11 +2387,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                               "multicast frame for %s\n",
                                               wiphy_name(local->hw.wiphy),
                                               prev->name);
-                               continue;
+                               goto next;
                        }
                        ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
+next:
                        prev = sdata;
                }
+
+               if (prev) {
+                       rx.sta = sta_info_get_bss(prev, hdr->addr2);
+
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(prev, &rx, hdr);
+
+                       if (!prepares)
+                               prev = NULL;
+               }
        }
        if (prev)
                ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
index 9afe2f9885dc93f68582809bcc778c5a9f2b3d25..bc061f6296742c27a578c378ca152b0c629b7057 100644 (file)
@@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = tim_ie->dtim_period;
        }
 
-       /* set default value for buggy AP/no TIM element */
-       if (bss->dtim_period == 0)
-               bss->dtim_period = 1;
-
        bss->supp_rates_len = 0;
        if (elems->supp_rates) {
                clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
index 0ebcdda2420028819c0ed4f90e299d9f28f39f53..e57ad6b1d7ea31c334f69079cb589979951d42e3 100644 (file)
@@ -45,29 +45,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        /*
-        * XXX: This is temporary!
-        *
-        *      The problem here is that when we get here, the driver will
-        *      quite likely have pretty much overwritten info->control by
-        *      using info->driver_data or info->rate_driver_data. Thus,
-        *      when passing out the frame to the driver again, we would be
-        *      passing completely bogus data since the driver would then
-        *      expect a properly filled info->control. In mac80211 itself
-        *      the same problem occurs, since we need info->control.vif
-        *      internally.
-        *
-        *      To fix this, we should send the frame through TX processing
-        *      again. However, it's not that simple, since the frame will
-        *      have been software-encrypted (if applicable) already, and
-        *      encrypting it again doesn't do much good. So to properly do
-        *      that, we not only have to skip the actual 'raw' encryption
-        *      (key selection etc. still has to be done!) but also the
-        *      sequence number assignment since that impacts the crypto
-        *      encapsulation, of course.
-        *
-        *      Hence, for now, fix the bug by just dropping the frame.
+        * This skb 'survived' a round-trip through the driver, and
+        * hopefully the driver didn't mangle it too badly. However,
+        * we can definitely not rely on the the control information
+        * being correct. Clear it so we don't get junk there, and
+        * indicate that it needs new processing, but must not be
+        * modified/encrypted again.
         */
-       goto drop;
+       memset(&info->control, 0, sizeof(info->control));
+
+       info->control.jiffies = jiffies;
+       info->control.vif = &sta->sdata->vif;
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
+                      IEEE80211_TX_INTFL_RETRANSMISSION;
 
        sta->tx_filtered_count++;
 
@@ -122,7 +112,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
- drop:
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: dropped TX filtered frame, "
index b73454a507f9cfd2dc89b45bac88352d32c75f2c..7ef491e9d66d0954aa6eba8891bcb22319f5b54b 100644 (file)
@@ -195,11 +195,13 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
 }
 EXPORT_SYMBOL(ieee80211_get_tkip_key);
 
-/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the
+/*
+ * Encrypt packet payload with TKIP using @key. @pos is a pointer to the
  * beginning of the buffer containing payload. This payload must include
- * headroom of eight octets for IV and Ext. IV and taildroom of four octets
- * for ICV. @payload_len is the length of payload (_not_ including extra
- * headroom and tailroom). @ta is the transmitter addresses. */
+ * the IV/Ext.IV and space for (taildroom) four octets for ICV.
+ * @payload_len is the length of payload (_not_ including IV/ICV length).
+ * @ta is the transmitter addresses.
+ */
 void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
                                 struct ieee80211_key *key,
                                 u8 *pos, size_t payload_len, u8 *ta)
@@ -214,7 +216,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
 
        tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
 
-       pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
        ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
 }
 
@@ -303,14 +304,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        if (key->local->ops->update_tkip_key &&
            key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
            key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
-               static const u8 bcast[ETH_ALEN] =
-               {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-               const u8 *sta_addr = key->sta->sta.addr;
-
-               if (is_multicast_ether_addr(ra))
-                       sta_addr = bcast;
+               struct ieee80211_sub_if_data *sdata = key->sdata;
 
-               drv_update_tkip_key(key->local, &key->conf, sta_addr,
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       sdata = container_of(key->sdata->bss,
+                                       struct ieee80211_sub_if_data, u.ap);
+               drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
                                iv32, key->u.tkip.rx[queue].p1k);
                key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
        }
index daf81048c1f74ab103b55bc1d79fbbc343221d2e..85e382aa894ef58b3da48be30b8d2410a2fa3ef0 100644 (file)
@@ -529,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key = NULL;
 
        if (tx->key) {
+               bool skip_hw = false;
+
                tx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
 
@@ -545,16 +547,32 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                            !ieee80211_use_mfp(hdr->frame_control, tx->sta,
                                               tx->skb))
                                tx->key = NULL;
+                       else
+                               skip_hw = (tx->key->conf.flags &
+                                          IEEE80211_KEY_FLAG_SW_MGMT) &&
+                                       ieee80211_is_mgmt(hdr->frame_control);
                        break;
                case ALG_AES_CMAC:
                        if (!ieee80211_is_mgmt(hdr->frame_control))
                                tx->key = NULL;
                        break;
                }
+
+               if (!skip_hw && tx->key &&
+                   tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+                       info->control.hw_key = &tx->key->conf;
        }
 
-       if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_sta(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       if (tx->sta)
+               info->control.sta = &tx->sta->sta;
 
        return TX_CONTINUE;
 }
@@ -733,17 +751,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        return TX_CONTINUE;
 }
 
-static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-
-       if (tx->sta)
-               info->control.sta = &tx->sta->sta;
-
-       return TX_CONTINUE;
-}
-
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 {
@@ -1101,7 +1108,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
        tx->flags |= IEEE80211_TX_FRAGMENTED;
 
        /* process and remove the injection radiotap header */
-       if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
                if (!__ieee80211_parse_tx_radiotap(tx, skb))
                        return TX_DROP;
 
@@ -1110,6 +1117,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                 * the radiotap header that was present and pre-filled
                 * 'tx' with tx control information.
                 */
+               info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP;
        }
 
        /*
@@ -1125,6 +1133,8 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                tx->sta = rcu_dereference(sdata->u.vlan.sta);
                if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
                        return TX_DROP;
+       } else if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+               tx->sta = sta_info_get_bss(sdata, hdr->addr1);
        }
        if (!tx->sta)
                tx->sta = sta_info_get(sdata, hdr->addr1);
@@ -1279,6 +1289,7 @@ static int __ieee80211_tx(struct ieee80211_local *local,
 static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb = tx->skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        ieee80211_tx_result res = TX_DROP;
 
 #define CALL_TXH(txh) \
@@ -1292,10 +1303,14 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        CALL_TXH(ieee80211_tx_h_check_assoc);
        CALL_TXH(ieee80211_tx_h_ps_buf);
        CALL_TXH(ieee80211_tx_h_select_key);
-       CALL_TXH(ieee80211_tx_h_michael_mic_add);
+       CALL_TXH(ieee80211_tx_h_sta);
        if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
                CALL_TXH(ieee80211_tx_h_rate_ctrl);
-       CALL_TXH(ieee80211_tx_h_misc);
+
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION))
+               goto txh_done;
+
+       CALL_TXH(ieee80211_tx_h_michael_mic_add);
        CALL_TXH(ieee80211_tx_h_sequence);
        CALL_TXH(ieee80211_tx_h_fragment);
        /* handlers after fragment must be aware of tx info fragmentation! */
@@ -1487,7 +1502,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                int hdrlen;
                u16 len_rthdr;
 
-               info->flags |= IEEE80211_TX_CTL_INJECTED;
+               info->flags |= IEEE80211_TX_CTL_INJECTED |
+                              IEEE80211_TX_INTFL_HAS_RADIOTAP;
 
                len_rthdr = ieee80211_get_radiotap_len(skb->data);
                hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
index 247123fe1a7a6307aa41a7fea01a7378ccec53e3..5d745f2d72364fcc8289cd104856c2150d7ec61d 100644 (file)
@@ -305,20 +305,19 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-       if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
+       if (!info->control.hw_key) {
                if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
                                          tx->key->conf.keylen,
                                          tx->key->conf.keyidx))
                        return -1;
-       } else {
-               info->control.hw_key = &tx->key->conf;
-               if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
-                       if (!ieee80211_wep_add_iv(tx->local, skb,
-                                                 tx->key->conf.keylen,
-                                                 tx->key->conf.keyidx))
-                               return -1;
-               }
+       } else if (info->control.hw_key->flags &
+                       IEEE80211_KEY_FLAG_GENERATE_IV) {
+               if (!ieee80211_wep_add_iv(tx->local, skb,
+                                         tx->key->conf.keylen,
+                                         tx->key->conf.keyidx))
+                       return -1;
        }
+
        return 0;
 }
 
index 81bd5d592bb489f837018a93e15ed5a49a0bc258..7e708d5c88b4e156586413a23c3d9e4f2c638920 100644 (file)
@@ -535,8 +535,7 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
         * First time we run, do nothing -- the generic code will
         * have switched to the right channel etc.
         */
-       if (!wk->remain.started) {
-               wk->remain.started = true;
+       if (!wk->started) {
                wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
 
                cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
@@ -821,15 +820,17 @@ static void ieee80211_work_work(struct work_struct *work)
        mutex_lock(&local->work_mtx);
 
        list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
+               bool started = wk->started;
+
                /* mark work as started if it's on the current off-channel */
-               if (!wk->started && local->tmp_channel &&
+               if (!started && local->tmp_channel &&
                    wk->chan == local->tmp_channel &&
                    wk->chan_type == local->tmp_channel_type) {
-                       wk->started = true;
+                       started = true;
                        wk->timeout = jiffies;
                }
 
-               if (!wk->started && !local->tmp_channel) {
+               if (!started && !local->tmp_channel) {
                        /*
                         * TODO: could optimize this by leaving the
                         *       station vifs in awake mode if they
@@ -842,12 +843,12 @@ static void ieee80211_work_work(struct work_struct *work)
                        local->tmp_channel = wk->chan;
                        local->tmp_channel_type = wk->chan_type;
                        ieee80211_hw_config(local, 0);
-                       wk->started = true;
+                       started = true;
                        wk->timeout = jiffies;
                }
 
                /* don't try to work with items that aren't started */
-               if (!wk->started)
+               if (!started)
                        continue;
 
                if (time_is_after_jiffies(wk->timeout)) {
@@ -882,6 +883,8 @@ static void ieee80211_work_work(struct work_struct *work)
                        break;
                }
 
+               wk->started = started;
+
                switch (rma) {
                case WORK_ACT_NONE:
                        /* might have changed the timeout */
@@ -1022,8 +1025,6 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
                case IEEE80211_STYPE_PROBE_RESP:
                case IEEE80211_STYPE_ASSOC_RESP:
                case IEEE80211_STYPE_REASSOC_RESP:
-               case IEEE80211_STYPE_DEAUTH:
-               case IEEE80211_STYPE_DISASSOC:
                        skb_queue_tail(&local->work_skb_queue, skb);
                        ieee80211_queue_work(&local->hw, &local->work_work);
                        return RX_QUEUED;
index 5332014cb22915c20a1f3015ea80f2bb59077833..f4971cd45c64f53eaa248680ca965a471abb7564 100644 (file)
@@ -31,8 +31,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
        unsigned int hdrlen;
        struct ieee80211_hdr *hdr;
        struct sk_buff *skb = tx->skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int authenticator;
-       int wpa_test = 0;
        int tail;
 
        hdr = (struct ieee80211_hdr *)skb->data;
@@ -47,16 +47,15 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
        data = skb->data + hdrlen;
        data_len = skb->len - hdrlen;
 
-       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+       if (info->control.hw_key &&
            !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
-           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
-           !wpa_test) {
-               /* hwaccel - with no need for preallocated room for MMIC */
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
+               /* hwaccel - with no need for SW-generated MMIC */
                return TX_CONTINUE;
        }
 
        tail = MICHAEL_MIC_LEN;
-       if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+       if (!info->control.hw_key)
                tail += TKIP_ICV_LEN;
 
        if (WARN_ON(skb_tailroom(skb) < tail ||
@@ -147,17 +146,16 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        int len, tail;
        u8 *pos;
 
-       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
-           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
-               /* hwaccel - with no need for preallocated room for IV/ICV */
-               info->control.hw_key = &tx->key->conf;
+       if (info->control.hw_key &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+               /* hwaccel - with no need for software-generated IV */
                return 0;
        }
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        len = skb->len - hdrlen;
 
-       if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+       if (info->control.hw_key)
                tail = 0;
        else
                tail = TKIP_ICV_LEN;
@@ -175,13 +173,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        if (key->u.tkip.tx.iv16 == 0)
                key->u.tkip.tx.iv32++;
 
-       if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-               /* hwaccel - with preallocated room for IV */
-               ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
+       pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
 
-               info->control.hw_key = &tx->key->conf;
+       /* hwaccel - with software IV */
+       if (info->control.hw_key)
                return 0;
-       }
 
        /* Add room for ICV */
        skb_put(skb, TKIP_ICV_LEN);
@@ -363,24 +359,20 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        int hdrlen, len, tail;
        u8 *pos, *pn;
        int i;
-       bool skip_hw;
-
-       skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) &&
-               ieee80211_is_mgmt(hdr->frame_control);
 
-       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
-           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
-           !skip_hw) {
-               /* hwaccel - with no need for preallocated room for CCMP
-                * header or MIC fields */
-               info->control.hw_key = &tx->key->conf;
+       if (info->control.hw_key &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+               /*
+                * hwaccel has no need for preallocated room for CCMP
+                * header or MIC fields
+                */
                return 0;
        }
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        len = skb->len - hdrlen;
 
-       if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
+       if (info->control.hw_key)
                tail = 0;
        else
                tail = CCMP_MIC_LEN;
@@ -405,11 +397,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        ccmp_pn2hdr(pos, pn, key->conf.keyidx);
 
-       if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) {
-               /* hwaccel - with preallocated room for CCMP header */
-               info->control.hw_key = &tx->key->conf;
+       /* hwaccel - with software CCMP header */
+       if (info->control.hw_key)
                return 0;
-       }
 
        pos += CCMP_HDR_LEN;
        ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0);
@@ -525,11 +515,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
        u8 *pn, aad[20];
        int i;
 
-       if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-               /* hwaccel */
-               info->control.hw_key = &tx->key->conf;
+       if (info->control.hw_key)
                return 0;
-       }
 
        if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
                return TX_DROP;
index 20db90246de5a04889cce289d13edd0f4f5bae5c..71b6b3a9cf1f1b38484a1764c43d17d3c0372d86 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This is the linux wireless configuration interface.
  *
- * Copyright 2006-2009         Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2010         Johannes Berg <johannes@sipsolutions.net>
  */
 
 #include <linux/if.h>
@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("wireless configuration support");
 
-/* RCU might be appropriate here since we usually
- * only read the list, and that can happen quite
- * often because we need to do it for each command */
+/* RCU-protected (and cfg80211_mutex for writers) */
 LIST_HEAD(cfg80211_rdev_list);
 int cfg80211_rdev_list_generation;
 
-/*
- * This is used to protect the cfg80211_rdev_list
- */
 DEFINE_MUTEX(cfg80211_mutex);
 
 /* for debugfs */
@@ -418,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy)
        int i;
        u16 ifmodes = wiphy->interface_modes;
 
+       if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
+               return -EINVAL;
+
+       if (WARN_ON(wiphy->addresses &&
+                   !is_zero_ether_addr(wiphy->perm_addr) &&
+                   memcmp(wiphy->perm_addr, wiphy->addresses[0].addr,
+                          ETH_ALEN)))
+               return -EINVAL;
+
+       if (wiphy->addresses)
+               memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
+
        /* sanity check ifmodes */
        WARN_ON(!ifmodes);
        ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -477,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy)
        /* set up regulatory info */
        wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
-       list_add(&rdev->list, &cfg80211_rdev_list);
+       list_add_rcu(&rdev->list, &cfg80211_rdev_list);
        cfg80211_rdev_list_generation++;
 
        mutex_unlock(&cfg80211_mutex);
@@ -554,7 +561,8 @@ void wiphy_unregister(struct wiphy *wiphy)
         * it impossible to find from userspace.
         */
        debugfs_remove_recursive(rdev->wiphy.debugfsdir);
-       list_del(&rdev->list);
+       list_del_rcu(&rdev->list);
+       synchronize_rcu();
 
        /*
         * Try to grab rdev->mtx. If a command is still in progress,
@@ -670,7 +678,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                INIT_LIST_HEAD(&wdev->event_list);
                spin_lock_init(&wdev->event_lock);
                mutex_lock(&rdev->devlist_mtx);
-               list_add(&wdev->list, &rdev->netdev_list);
+               list_add_rcu(&wdev->list, &rdev->netdev_list);
                rdev->devlist_generation++;
                /* can only change netns with wiphy */
                dev->features |= NETIF_F_NETNS_LOCAL;
@@ -782,13 +790,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                 */
                if (!list_empty(&wdev->list)) {
                        sysfs_remove_link(&dev->dev.kobj, "phy80211");
-                       list_del_init(&wdev->list);
+                       list_del_rcu(&wdev->list);
                        rdev->devlist_generation++;
 #ifdef CONFIG_CFG80211_WEXT
                        kfree(wdev->wext.keys);
 #endif
                }
                mutex_unlock(&rdev->devlist_mtx);
+               /*
+                * synchronise (so that we won't find this netdev
+                * from other code any more) and then clear the list
+                * head so that the above code can safely check for
+                * !list_empty() to avoid double-cleanup.
+                */
+               synchronize_rcu();
+               INIT_LIST_HEAD(&wdev->list);
                break;
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
index 2d6a6b9c0c438f6f06ab691bffc94f4d7e794dad..c326a667022aba000cf7a880eb87d9e02431d328 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Wireless configuration interface internals.
  *
- * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  */
 #ifndef __NET_WIRELESS_CORE_H
 #define __NET_WIRELESS_CORE_H
@@ -48,6 +48,7 @@ struct cfg80211_registered_device {
 
        /* associate netdev list */
        struct mutex devlist_mtx;
+       /* protected by devlist_mtx or RCU */
        struct list_head netdev_list;
        int devlist_generation;
        int opencount; /* also protected by devlist_mtx */
index 2301dc1edc4cda417335e0747f7505f748de7d8e..b7fa31d5fd13892a93c774de5ce3a2daa02af62d 100644 (file)
@@ -237,7 +237,6 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                return -1;
 
        pos = skb->data + hdr_len + CCMP_HDR_LEN;
-       mic = skb_put(skb, CCMP_MIC_LEN);
        hdr = (struct ieee80211_hdr *)skb->data;
        ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
 
@@ -257,6 +256,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
                pos += len;
        }
 
+       mic = skb_put(skb, CCMP_MIC_LEN);
        for (i = 0; i < CCMP_MIC_LEN; i++)
                mic[i] = b[i] ^ s0[i];
 
index c36287399d7ea2155f53a535a1e0ad540e104be3..8cbdb32ff31657fd312969ff319e1e79246e2238 100644 (file)
@@ -36,6 +36,8 @@ MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("lib80211 crypt: TKIP");
 MODULE_LICENSE("GPL");
 
+#define TKIP_HDR_LEN 8
+
 struct lib80211_tkip_data {
 #define TKIP_KEY_LEN 32
        u8 key[TKIP_KEY_LEN];
@@ -314,13 +316,12 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
                              u8 * rc4key, int keylen, void *priv)
 {
        struct lib80211_tkip_data *tkey = priv;
-       int len;
        u8 *pos;
        struct ieee80211_hdr *hdr;
 
        hdr = (struct ieee80211_hdr *)skb->data;
 
-       if (skb_headroom(skb) < 8 || skb->len < hdr_len)
+       if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
                return -1;
 
        if (rc4key == NULL || keylen < 16)
@@ -333,9 +334,8 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
        }
        tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
 
-       len = skb->len - hdr_len;
-       pos = skb_push(skb, 8);
-       memmove(pos, pos + 8, hdr_len);
+       pos = skb_push(skb, TKIP_HDR_LEN);
+       memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
        pos += hdr_len;
 
        *pos++ = *rc4key;
@@ -353,7 +353,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
                tkey->tx_iv32++;
        }
 
-       return 8;
+       return TKIP_HDR_LEN;
 }
 
 static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
@@ -384,9 +384,8 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
        if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
                return -1;
 
-       icv = skb_put(skb, 4);
-
        crc = ~crc32_le(~0, pos, len);
+       icv = skb_put(skb, 4);
        icv[0] = crc;
        icv[1] = crc >> 8;
        icv[2] = crc >> 16;
@@ -434,7 +433,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                return -1;
        }
 
-       if (skb->len < hdr_len + 8 + 4)
+       if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
                return -1;
 
        pos = skb->data + hdr_len;
@@ -462,7 +461,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        }
        iv16 = (pos[0] << 8) | pos[2];
        iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
-       pos += 8;
+       pos += TKIP_HDR_LEN;
 
        if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
 #ifdef CONFIG_LIB80211_DEBUG
@@ -523,8 +522,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        tkey->rx_iv16_new = iv16;
 
        /* Remove IV and ICV */
-       memmove(skb->data + 8, skb->data, hdr_len);
-       skb_pull(skb, 8);
+       memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
+       skb_pull(skb, TKIP_HDR_LEN);
        skb_trim(skb, skb->len - 4);
 
        return keyidx;
index 4af7991a9ec8745bc0adc42ec5357d76c1f38d86..5b79ecf17bea47a102a57187d04cf4ce2af0589d 100644 (file)
@@ -3571,6 +3571,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
        struct net_device *dev;
+       struct wireless_dev *wdev;
        struct cfg80211_crypto_settings crypto;
        struct ieee80211_channel *chan, *fixedchan;
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
@@ -3616,7 +3617,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        }
 
        mutex_lock(&rdev->devlist_mtx);
-       fixedchan = rdev_fixed_channel(rdev, NULL);
+       wdev = dev->ieee80211_ptr;
+       fixedchan = rdev_fixed_channel(rdev, wdev);
        if (fixedchan && chan != fixedchan) {
                err = -EBUSY;
                mutex_unlock(&rdev->devlist_mtx);
index 5f8071de7950d5f769d2d8a5a0f8179101f95bb3..ed89c59bb431ab9c320c5f300123b501628f6c64 100644 (file)
@@ -134,6 +134,7 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom =
        &world_regdom;
 
 static char *ieee80211_regdom = "00";
+static char user_alpha2[2];
 
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
@@ -252,6 +253,27 @@ static bool regdom_changes(const char *alpha2)
        return true;
 }
 
+/*
+ * The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets
+ * you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER
+ * has ever been issued.
+ */
+static bool is_user_regdom_saved(void)
+{
+       if (user_alpha2[0] == '9' && user_alpha2[1] == '7')
+               return false;
+
+       /* This would indicate a mistake on the design */
+       if (WARN((!is_world_regdom(user_alpha2) &&
+                 !is_an_alpha2(user_alpha2)),
+                "Unexpected user alpha2: %c%c\n",
+                user_alpha2[0],
+                user_alpha2[1]))
+               return false;
+
+       return true;
+}
+
 /**
  * country_ie_integrity_changes - tells us if the country IE has changed
  * @checksum: checksum of country IE of fields we are interested in
@@ -1646,7 +1668,7 @@ static int ignore_request(struct wiphy *wiphy,
 
        switch (pending_request->initiator) {
        case NL80211_REGDOM_SET_BY_CORE:
-               return -EINVAL;
+               return 0;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
 
                last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
@@ -1785,6 +1807,11 @@ new_request:
 
        pending_request = NULL;
 
+       if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
+               user_alpha2[0] = last_request->alpha2[0];
+               user_alpha2[1] = last_request->alpha2[1];
+       }
+
        /* When r == REG_INTERSECT we do need to call CRDA */
        if (r < 0) {
                /*
@@ -1904,12 +1931,16 @@ static void queue_regulatory_request(struct regulatory_request *request)
        schedule_work(&reg_work);
 }
 
-/* Core regulatory hint -- happens once during cfg80211_init() */
+/*
+ * Core regulatory hint -- happens during cfg80211_init()
+ * and when we restore regulatory settings.
+ */
 static int regulatory_hint_core(const char *alpha2)
 {
        struct regulatory_request *request;
 
-       BUG_ON(last_request);
+       kfree(last_request);
+       last_request = NULL;
 
        request = kzalloc(sizeof(struct regulatory_request),
                          GFP_KERNEL);
@@ -1920,14 +1951,12 @@ static int regulatory_hint_core(const char *alpha2)
        request->alpha2[1] = alpha2[1];
        request->initiator = NL80211_REGDOM_SET_BY_CORE;
 
-       queue_regulatory_request(request);
-
        /*
         * This ensures last_request is populated once modules
         * come swinging in and calling regulatory hints and
         * wiphy_apply_custom_regulatory().
         */
-       flush_scheduled_work();
+       reg_process_hint(request);
 
        return 0;
 }
@@ -2109,6 +2138,123 @@ out:
        mutex_unlock(&reg_mutex);
 }
 
+static void restore_alpha2(char *alpha2, bool reset_user)
+{
+       /* indicates there is no alpha2 to consider for restoration */
+       alpha2[0] = '9';
+       alpha2[1] = '7';
+
+       /* The user setting has precedence over the module parameter */
+       if (is_user_regdom_saved()) {
+               /* Unless we're asked to ignore it and reset it */
+               if (reset_user) {
+                       REG_DBG_PRINT("cfg80211: Restoring regulatory settings "
+                              "including user preference\n");
+                       user_alpha2[0] = '9';
+                       user_alpha2[1] = '7';
+
+                       /*
+                        * If we're ignoring user settings, we still need to
+                        * check the module parameter to ensure we put things
+                        * back as they were for a full restore.
+                        */
+                       if (!is_world_regdom(ieee80211_regdom)) {
+                               REG_DBG_PRINT("cfg80211: Keeping preference on "
+                                      "module parameter ieee80211_regdom: %c%c\n",
+                                      ieee80211_regdom[0],
+                                      ieee80211_regdom[1]);
+                               alpha2[0] = ieee80211_regdom[0];
+                               alpha2[1] = ieee80211_regdom[1];
+                       }
+               } else {
+                       REG_DBG_PRINT("cfg80211: Restoring regulatory settings "
+                              "while preserving user preference for: %c%c\n",
+                              user_alpha2[0],
+                              user_alpha2[1]);
+                       alpha2[0] = user_alpha2[0];
+                       alpha2[1] = user_alpha2[1];
+               }
+       } else if (!is_world_regdom(ieee80211_regdom)) {
+               REG_DBG_PRINT("cfg80211: Keeping preference on "
+                      "module parameter ieee80211_regdom: %c%c\n",
+                      ieee80211_regdom[0],
+                      ieee80211_regdom[1]);
+               alpha2[0] = ieee80211_regdom[0];
+               alpha2[1] = ieee80211_regdom[1];
+       } else
+               REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n");
+}
+
+/*
+ * Restoring regulatory settings involves ingoring any
+ * possibly stale country IE information and user regulatory
+ * settings if so desired, this includes any beacon hints
+ * learned as we could have traveled outside to another country
+ * after disconnection. To restore regulatory settings we do
+ * exactly what we did at bootup:
+ *
+ *   - send a core regulatory hint
+ *   - send a user regulatory hint if applicable
+ *
+ * Device drivers that send a regulatory hint for a specific country
+ * keep their own regulatory domain on wiphy->regd so that does does
+ * not need to be remembered.
+ */
+static void restore_regulatory_settings(bool reset_user)
+{
+       char alpha2[2];
+       struct reg_beacon *reg_beacon, *btmp;
+
+       mutex_lock(&cfg80211_mutex);
+       mutex_lock(&reg_mutex);
+
+       reset_regdomains();
+       restore_alpha2(alpha2, reset_user);
+
+       /* Clear beacon hints */
+       spin_lock_bh(&reg_pending_beacons_lock);
+       if (!list_empty(&reg_pending_beacons)) {
+               list_for_each_entry_safe(reg_beacon, btmp,
+                                        &reg_pending_beacons, list) {
+                       list_del(&reg_beacon->list);
+                       kfree(reg_beacon);
+               }
+       }
+       spin_unlock_bh(&reg_pending_beacons_lock);
+
+       if (!list_empty(&reg_beacon_list)) {
+               list_for_each_entry_safe(reg_beacon, btmp,
+                                        &reg_beacon_list, list) {
+                       list_del(&reg_beacon->list);
+                       kfree(reg_beacon);
+               }
+       }
+
+       /* First restore to the basic regulatory settings */
+       cfg80211_regdomain = cfg80211_world_regdom;
+
+       mutex_unlock(&reg_mutex);
+       mutex_unlock(&cfg80211_mutex);
+
+       regulatory_hint_core(cfg80211_regdomain->alpha2);
+
+       /*
+        * This restores the ieee80211_regdom module parameter
+        * preference or the last user requested regulatory
+        * settings, user regulatory settings takes precedence.
+        */
+       if (is_an_alpha2(alpha2))
+               regulatory_hint_user(user_alpha2);
+}
+
+
+void regulatory_hint_disconnect(void)
+{
+       REG_DBG_PRINT("cfg80211: All devices are disconnected, going to "
+                     "restore regulatory settings\n");
+       restore_regulatory_settings(false);
+}
+
 static bool freq_is_chan_12_13_14(u16 freq)
 {
        if (freq == ieee80211_channel_to_frequency(12) ||
@@ -2498,6 +2644,9 @@ int regulatory_init(void)
 
        cfg80211_regdomain = cfg80211_world_regdom;
 
+       user_alpha2[0] = '9';
+       user_alpha2[1] = '7';
+
        /* We always try to get an update for the static regdomain */
        err = regulatory_hint_core(cfg80211_regdomain->alpha2);
        if (err) {
index 3018508226ab3efae623bef25112347f9d92b9ae..b26224a9f3bc2ab2ea28d19a3a2ebbc2f5b2a765 100644 (file)
@@ -63,4 +63,22 @@ void regulatory_hint_11d(struct wiphy *wiphy,
                         u8 *country_ie,
                         u8 country_ie_len);
 
+/**
+ * regulatory_hint_disconnect - informs all devices have been disconneted
+ *
+ * Regulotory rules can be enhanced further upon scanning and upon
+ * connection to an AP. These rules become stale if we disconnect
+ * and go to another country, whether or not we suspend and resume.
+ * If we suspend, go to another country and resume we'll automatically
+ * get disconnected shortly after resuming and things will be reset as well.
+ * This routine is a helper to restore regulatory settings to how they were
+ * prior to our first connect attempt. This includes ignoring country IE and
+ * beacon regulatory hints. The ieee80211_regdom module parameter will always
+ * be respected but if a user had set the regulatory domain that will take
+ * precedence.
+ *
+ * Must be called from process context.
+ */
+void regulatory_hint_disconnect(void);
+
 #endif  /* __NET_WIRELESS_REG_H */
index 06b0231ee5e3145db236ca4ccaff2d34ac0ff3f5..978cac3414b558fd80bc41e3c87aa56510584beb 100644 (file)
@@ -143,9 +143,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
                dev->bss_generation++;
 }
 
-static u8 *find_ie(u8 num, u8 *ies, int len)
+const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
 {
-       while (len > 2 && ies[0] != num) {
+       while (len > 2 && ies[0] != eid) {
                len -= ies[1] + 2;
                ies += ies[1] + 2;
        }
@@ -155,11 +155,12 @@ static u8 *find_ie(u8 num, u8 *ies, int len)
                return NULL;
        return ies;
 }
+EXPORT_SYMBOL(cfg80211_find_ie);
 
 static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 {
-       const u8 *ie1 = find_ie(num, ies1, len1);
-       const u8 *ie2 = find_ie(num, ies2, len2);
+       const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
+       const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
        int r;
 
        if (!ie1 && !ie2)
@@ -185,9 +186,9 @@ static bool is_bss(struct cfg80211_bss *a,
        if (!ssid)
                return true;
 
-       ssidie = find_ie(WLAN_EID_SSID,
-                        a->information_elements,
-                        a->len_information_elements);
+       ssidie = cfg80211_find_ie(WLAN_EID_SSID,
+                                 a->information_elements,
+                                 a->len_information_elements);
        if (!ssidie)
                return false;
        if (ssidie[1] != ssid_len)
@@ -204,9 +205,9 @@ static bool is_mesh(struct cfg80211_bss *a,
        if (!is_zero_ether_addr(a->bssid))
                return false;
 
-       ie = find_ie(WLAN_EID_MESH_ID,
-                    a->information_elements,
-                    a->len_information_elements);
+       ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
+                             a->information_elements,
+                             a->len_information_elements);
        if (!ie)
                return false;
        if (ie[1] != meshidlen)
@@ -214,9 +215,9 @@ static bool is_mesh(struct cfg80211_bss *a,
        if (memcmp(ie + 2, meshid, meshidlen))
                return false;
 
-       ie = find_ie(WLAN_EID_MESH_CONFIG,
-                    a->information_elements,
-                    a->len_information_elements);
+       ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
+                             a->information_elements,
+                             a->len_information_elements);
        if (!ie)
                return false;
        if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
@@ -395,11 +396,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
        if (is_zero_ether_addr(res->pub.bssid)) {
                /* must be mesh, verify */
-               meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
-                                res->pub.len_information_elements);
-               meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
-                                 res->pub.information_elements,
-                                 res->pub.len_information_elements);
+               meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
+                                         res->pub.information_elements,
+                                         res->pub.len_information_elements);
+               meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
+                                          res->pub.information_elements,
+                                          res->pub.len_information_elements);
                if (!meshid || !meshcfg ||
                    meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
                        /* bogus mesh */
index 745c37e7992e1e410972dcfff89b332fdf619f30..17fde0da1b08658db9882f000a51928dbd9ad339 100644 (file)
@@ -34,6 +34,44 @@ struct cfg80211_conn {
        bool auto_auth, prev_bssid_valid;
 };
 
+bool cfg80211_is_all_idle(void)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       bool is_all_idle = true;
+
+       mutex_lock(&cfg80211_mutex);
+
+       /*
+        * All devices must be idle as otherwise if you are actively
+        * scanning some new beacon hints could be learned and would
+        * count as new regulatory hints.
+        */
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               cfg80211_lock_rdev(rdev);
+               list_for_each_entry(wdev, &rdev->netdev_list, list) {
+                       wdev_lock(wdev);
+                       if (wdev->sme_state != CFG80211_SME_IDLE)
+                               is_all_idle = false;
+                       wdev_unlock(wdev);
+               }
+               cfg80211_unlock_rdev(rdev);
+       }
+
+       mutex_unlock(&cfg80211_mutex);
+
+       return is_all_idle;
+}
+
+static void disconnect_work(struct work_struct *work)
+{
+       if (!cfg80211_is_all_idle())
+               return;
+
+       regulatory_hint_disconnect();
+}
+
+static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
 
 static int cfg80211_conn_scan(struct wireless_dev *wdev)
 {
@@ -658,6 +696,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
        wdev->wext.connect.ssid_len = 0;
 #endif
+
+       schedule_work(&cfg80211_disconnect_work);
 }
 
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
index efe3c5c92b2dedbb48271d89d1664cd57cf182cf..9f2cef3e0ca0cd21640127a27fd72edba88434a5 100644 (file)
@@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev,                    \
 
 SHOW_FMT(index, "%d", wiphy_idx);
 SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
+SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
+
+static ssize_t addresses_show(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
+       char *start = buf;
+       int i;
+
+       if (!wiphy->addresses)
+               return sprintf(buf, "%pM\n", wiphy->perm_addr);
+
+       for (i = 0; i < wiphy->n_addresses; i++)
+               buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr);
+
+       return buf - start;
+}
 
 static struct device_attribute ieee80211_dev_attrs[] = {
        __ATTR_RO(index),
        __ATTR_RO(macaddress),
+       __ATTR_RO(address_mask),
+       __ATTR_RO(addresses),
        {}
 };
 
index 23557c1d0a9caafd0e8c7b211846c9bd0f8a32b0..be2ab8c59e3a9806425b2b958d87dfe50d80111d 100644 (file)
@@ -227,8 +227,11 @@ unsigned int ieee80211_hdrlen(__le16 fc)
        if (ieee80211_is_data(fc)) {
                if (ieee80211_has_a4(fc))
                        hdrlen = 30;
-               if (ieee80211_is_data_qos(fc))
+               if (ieee80211_is_data_qos(fc)) {
                        hdrlen += IEEE80211_QOS_CTL_LEN;
+                       if (ieee80211_has_order(fc))
+                               hdrlen += IEEE80211_HT_CTL_LEN;
+               }
                goto out;
        }
 
index 966d2f01beac2a26060df2bd284369fc3656f251..b17eeae448d54417d30ee687395eb075ec7a7f5a 100644 (file)
@@ -1214,7 +1214,7 @@ int cfg80211_wext_siwrate(struct net_device *dev,
 
        memset(&mask, 0, sizeof(mask));
        fixed = 0;
-       maxrate = 0;
+       maxrate = (u32)-1;
 
        if (rate->value < 0) {
                /* nothing */