Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 15 Jul 2011 14:05:24 +0000 (10:05 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 15 Jul 2011 14:05:24 +0000 (10:05 -0400)
Conflicts:
net/bluetooth/l2cap_core.c

162 files changed:
Documentation/DocBook/80211.tmpl
drivers/bcma/main.c
drivers/bcma/sprom.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/net/wireless/ath/ath5k/ahb.c
drivers/net/wireless/ath/ath5k/ani.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/caps.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/desc.h
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/eeprom.h
drivers/net/wireless/ath/ath5k/initvals.c
drivers/net/wireless/ath/ath5k/led.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath5k/pci.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/rfbuffer.h
drivers/net/wireless/ath/ath5k/rfgain.h
drivers/net/wireless/ath/ath5k/sysfs.c
drivers/net/wireless/ath/ath5k/trace.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/bus.c
drivers/net/wireless/b43/bus.h
drivers/net/wireless/b43/dma.c
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_ht.c
drivers/net/wireless/b43/phy_lcn.c [new file with mode: 0644]
drivers/net/wireless/b43/phy_lcn.h [new file with mode: 0644]
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/tables_phy_lcn.c [new file with mode: 0644]
drivers/net/wireless/b43/tables_phy_lcn.h [new file with mode: 0644]
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/iwlegacy/iwl-4965-tx.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.h
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.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-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-led.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-testmode.h
drivers/net/wireless/iwlwifi/iwl-trans.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_tx.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/sdio.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/wl12xx.h
include/linux/nl80211.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/smp.h
include/net/cfg80211.h
include/net/mac80211.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/mac80211/aes_ccm.c
net/mac80211/aes_ccm.h
net/mac80211/aes_cmac.c
net/mac80211/aes_cmac.h
net/mac80211/cfg.c
net/mac80211/debugfs_key.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/tkip.c
net/mac80211/tkip.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wpa.c
net/wireless/scan.c

index 8906648..445289c 100644 (file)
 !Finclude/net/mac80211.h set_key_cmd
 !Finclude/net/mac80211.h ieee80211_key_conf
 !Finclude/net/mac80211.h ieee80211_key_flags
-!Finclude/net/mac80211.h ieee80211_tkip_key_type
-!Finclude/net/mac80211.h ieee80211_get_tkip_key
+!Finclude/net/mac80211.h ieee80211_get_tkip_p1k
+!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv
+!Finclude/net/mac80211.h ieee80211_get_tkip_p2k
 !Finclude/net/mac80211.h ieee80211_key_removed
       </chapter>
 
index 08a14a3..873e2e4 100644 (file)
@@ -149,7 +149,9 @@ int bcma_bus_register(struct bcma_bus *bus)
 
        /* Try to get SPROM */
        err = bcma_sprom_get(bus);
-       if (err) {
+       if (err == -ENOENT) {
+               pr_err("No SPROM available\n");
+       } else if (err) {
                pr_err("Failed to get SPROM: %d\n", err);
                return -ENOENT;
        }
index ffbb0e3..8e8d5cf 100644 (file)
@@ -143,6 +143,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
        if (!bus->drv_cc.core)
                return -EOPNOTSUPP;
 
+       if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
+               return -ENOENT;
+
        sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                        GFP_KERNEL);
        if (!sprom)
index 6bacef3..a585473 100644 (file)
@@ -375,6 +375,11 @@ static int ath3k_probe(struct usb_interface *intf,
 
        /* load patch and sysconfig files for AR3012 */
        if (id->driver_info & BTUSB_ATH3012) {
+
+               /* New firmware with patch and sysconfig files already loaded */
+               if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001)
+                       return -ENODEV;
+
                ret = ath3k_load_patch(udev);
                if (ret < 0) {
                        BT_ERR("Loading patch file failed");
index c2de895..91d13a9 100644 (file)
@@ -54,6 +54,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BCM92035         0x10
 #define BTUSB_BROKEN_ISOC      0x20
 #define BTUSB_WRONG_SCO_MTU    0x40
+#define BTUSB_ATH3012          0x80
 
 static struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
@@ -110,7 +111,7 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
        /* Atheros 3012 with sflash firmware */
-       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -914,6 +915,15 @@ static int btusb_probe(struct usb_interface *intf,
        if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
                return -ENODEV;
 
+       if (id->driver_info & BTUSB_ATH3012) {
+               struct usb_device *udev = interface_to_usbdev(intf);
+
+               /* Old firmware would otherwise let ath3k driver load
+                * patch and sysconfig files */
+               if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
+                       return -ENODEV;
+       }
+
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
index c38e9e8..ba682a0 100644 (file)
@@ -167,8 +167,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
                 * driver for it
                 */
                if (to_platform_device(sc->dev)->id == 0 &&
-                   (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
-                    (BD_WLAN1|BD_WLAN0))
+                   (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
+                    (BD_WLAN1 | BD_WLAN0))
                        __set_bit(ATH_STAT_2G_DISABLED, sc->status);
        }
 
index f915f40..2f0b967 100644 (file)
@@ -74,7 +74,7 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
        static const s8 fr[] = { -78, -80 };
 #endif
        if (level < 0 || level >= ARRAY_SIZE(sz)) {
-               ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range",
+               ATH5K_ERR(ah->ah_sc, "noise immunity level %d out of range",
                          level);
                return;
        }
@@ -630,6 +630,11 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
        if (ah->ah_version < AR5K_AR5212)
                return;
 
+       if (mode < ATH5K_ANI_MODE_OFF || mode > ATH5K_ANI_MODE_AUTO) {
+               ATH5K_ERR(ah->ah_sc, "ANI mode %d out of range", mode);
+               return;
+       }
+
        /* clear old state information */
        memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state));
 
@@ -642,7 +647,7 @@ ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
        /* initial values for our ani parameters */
        if (mode == ATH5K_ANI_MODE_OFF) {
                ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n");
-       } else if  (mode == ATH5K_ANI_MODE_MANUAL_LOW) {
+       } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) {
                ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
                        "ANI manual low -> high sensitivity\n");
                ath5k_ani_set_noise_immunity_level(ah, 0);
index c4c02d5..8ff1794 100644 (file)
@@ -18,9 +18,9 @@
 #ifndef _ATH5K_H
 #define _ATH5K_H
 
-/* TODO: Clean up channel debuging -doesn't work anyway- and start
+/* TODO: Clean up channel debugging (doesn't work anyway) and start
  * working on reg. control code using all available eeprom information
- * -rev. engineering needed- */
+ * (rev. engineering needed) */
 #define CHAN_DEBUG     0
 
 #include <linux/io.h>
 #include "../ath.h"
 
 /* PCI IDs */
-#define PCI_DEVICE_ID_ATHEROS_AR5210           0x0007 /* AR5210 */
-#define PCI_DEVICE_ID_ATHEROS_AR5311           0x0011 /* AR5311 */
-#define PCI_DEVICE_ID_ATHEROS_AR5211           0x0012 /* AR5211 */
-#define PCI_DEVICE_ID_ATHEROS_AR5212           0x0013 /* AR5212 */
-#define PCI_DEVICE_ID_3COM_3CRDAG675           0x0013 /* 3CRDAG675 (Atheros AR5212) */
-#define PCI_DEVICE_ID_3COM_2_3CRPAG175                 0x0013 /* 3CRPAG175 (Atheros AR5212) */
-#define PCI_DEVICE_ID_ATHEROS_AR5210_AP        0x0207 /* AR5210 (Early) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210           0x0007 /* AR5210 */
+#define PCI_DEVICE_ID_ATHEROS_AR5311           0x0011 /* AR5311 */
+#define PCI_DEVICE_ID_ATHEROS_AR5211           0x0012 /* AR5211 */
+#define PCI_DEVICE_ID_ATHEROS_AR5212           0x0013 /* AR5212 */
+#define PCI_DEVICE_ID_3COM_3CRDAG675           0x0013 /* 3CRDAG675 (Atheros AR5212) */
+#define PCI_DEVICE_ID_3COM_2_3CRPAG175         0x0013 /* 3CRPAG175 (Atheros AR5212) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_AP                0x0207 /* AR5210 (Early) */
 #define PCI_DEVICE_ID_ATHEROS_AR5212_IBM       0x1014 /* AR5212 (IBM MiniPCI) */
-#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT   0x1107 /* AR5210 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT   0x1113 /* AR5212 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT   0x1112 /* AR5211 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA      0xf013 /* AR5212 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY    0xff12 /* AR5211 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B   0xf11b /* AR5211 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2      0x0052 /* AR5312 WMAC (AP31) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7      0x0057 /* AR5312 WMAC (AP30-040) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8      0x0058 /* AR5312 WMAC (AP43-030) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0014      0x0014 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0015      0x0015 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0016      0x0016 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0017      0x0017 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0018      0x0018 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0019      0x0019 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR2413           0x001a /* AR2413 (Griffin-lite) */
-#define PCI_DEVICE_ID_ATHEROS_AR5413           0x001b /* AR5413 (Eagle) */
-#define PCI_DEVICE_ID_ATHEROS_AR5424           0x001c /* AR5424 (Condor PCI-E) */
-#define PCI_DEVICE_ID_ATHEROS_AR5416           0x0023 /* AR5416 */
-#define PCI_DEVICE_ID_ATHEROS_AR5418           0x0024 /* AR5418 */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT   0x1107 /* AR5210 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT   0x1113 /* AR5212 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT   0x1112 /* AR5211 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA      0xf013 /* AR5212 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY    0xff12 /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B   0xf11b /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2      0x0052 /* AR5312 WMAC (AP31) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7      0x0057 /* AR5312 WMAC (AP30-040) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8      0x0058 /* AR5312 WMAC (AP43-030) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0014      0x0014 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0015      0x0015 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0016      0x0016 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0017      0x0017 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0018      0x0018 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0019      0x0019 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR2413           0x001a /* AR2413 (Griffin-lite) */
+#define PCI_DEVICE_ID_ATHEROS_AR5413           0x001b /* AR5413 (Eagle) */
+#define PCI_DEVICE_ID_ATHEROS_AR5424           0x001c /* AR5424 (Condor PCI-E) */
+#define PCI_DEVICE_ID_ATHEROS_AR5416           0x0023 /* AR5416 */
+#define PCI_DEVICE_ID_ATHEROS_AR5418           0x0024 /* AR5418 */
 
 /****************************\
   GENERIC DRIVER DEFINITIONS
 \****************************/
 
-#define ATH5K_PRINTF(fmt, ...)   printk("%s: " fmt, __func__, ##__VA_ARGS__)
+#define ATH5K_PRINTF(fmt, ...) \
+       printk(KERN_WARNING "%s: " fmt, __func__, ##__VA_ARGS__)
 
 #define ATH5K_PRINTK(_sc, _level, _fmt, ...) \
        printk(_level "ath5k %s: " _fmt, \
 } while (0)
 
 /*
- * Some tuneable values (these should be changeable by the user)
+ * Some tunable values (these should be changeable by the user)
  * TODO: Make use of them and add more options OR use debug/configfs
  */
 #define AR5K_TUNE_DMA_BEACON_RESP              2
 #define AR5K_TUNE_RSSI_THRES                   129
 /* This must be set when setting the RSSI threshold otherwise it can
  * prevent a reset. If AR5K_RSSI_THR is read after writing to it
- * the BMISS_THRES will be seen as 0, seems harware doesn't keep
- * track of it. Max value depends on harware. For AR5210 this is just 7.
+ * the BMISS_THRES will be seen as 0, seems hardware doesn't keep
+ * track of it. Max value depends on hardware. For AR5210 this is just 7.
  * For AR5211+ this seems to be up to 255. */
 #define AR5K_TUNE_BMISS_THRES                  7
 #define AR5K_TUNE_REGISTER_DWELL_TIME          20000
@@ -361,7 +362,7 @@ struct ath5k_srev_name {
 /*
  * Some of this information is based on Documentation from:
  *
- * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG 
+ * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG
  *
  * Modulation for Atheros' eXtended Range - range enhancing extension that is
  * supposed to double the distance an Atheros client device can keep a
@@ -374,12 +375,12 @@ struct ath5k_srev_name {
  * they are exclusive.
  *
  */
-#define MODULATION_XR          0x00000200
+#define MODULATION_XR          0x00000200
 /*
  * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
  * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
  * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
- * channels. To use this feature your Access Point must also suport it.
+ * channels. To use this feature your Access Point must also support it.
  * There is also a distinction between "static" and "dynamic" turbo modes:
  *
  * - Static: is the dumb version: devices set to this mode stick to it until
@@ -495,9 +496,9 @@ enum ath5k_tx_queue {
  */
 enum ath5k_tx_queue_subtype {
        AR5K_WME_AC_BK = 0,     /*Background traffic*/
-       AR5K_WME_AC_BE,         /*Best-effort (normal) traffic)*/
-       AR5K_WME_AC_VI,         /*Video traffic*/
-       AR5K_WME_AC_VO,         /*Voice traffic*/
+       AR5K_WME_AC_BE,         /*Best-effort (normal) traffic*/
+       AR5K_WME_AC_VI,         /*Video traffic*/
+       AR5K_WME_AC_VO,         /*Voice traffic*/
 };
 
 /*
@@ -616,8 +617,8 @@ struct ath5k_rx_status {
 #define AR5K_RXERR_FIFO                0x04
 #define AR5K_RXERR_DECRYPT     0x08
 #define AR5K_RXERR_MIC         0x10
-#define AR5K_RXKEYIX_INVALID   ((u8) - 1)
-#define AR5K_TXKEYIX_INVALID   ((u32) - 1)
+#define AR5K_RXKEYIX_INVALID   ((u8) -1)
+#define AR5K_TXKEYIX_INVALID   ((u32) -1)
 
 
 /**************************\
@@ -678,17 +679,18 @@ struct ath5k_gain {
 #define        CHANNEL_DYN     0x0400  /* Dynamic CCK-OFDM channel (for g operation) */
 #define        CHANNEL_XR      0x0800  /* XR channel */
 
-#define        CHANNEL_A       (CHANNEL_5GHZ|CHANNEL_OFDM)
-#define        CHANNEL_B       (CHANNEL_2GHZ|CHANNEL_CCK)
-#define        CHANNEL_G       (CHANNEL_2GHZ|CHANNEL_OFDM)
-#define        CHANNEL_X       (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+#define        CHANNEL_A       (CHANNEL_5GHZ | CHANNEL_OFDM)
+#define        CHANNEL_B       (CHANNEL_2GHZ | CHANNEL_CCK)
+#define        CHANNEL_G       (CHANNEL_2GHZ | CHANNEL_OFDM)
+#define        CHANNEL_X       (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR)
 
-#define        CHANNEL_ALL     (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ)
+#define        CHANNEL_ALL     (CHANNEL_OFDM | CHANNEL_CCK | \
+                        CHANNEL_2GHZ | CHANNEL_5GHZ)
 
 #define CHANNEL_MODES          CHANNEL_ALL
 
 /*
- * Used internaly for reset_tx_queue).
+ * Used internally for ath5k_hw_reset_tx_queue().
  * Also see struct struct ieee80211_channel.
  */
 #define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
@@ -710,7 +712,7 @@ struct ath5k_athchan_2ghz {
 \******************/
 
 /**
- * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
+ * Seems the ar5xxx hardware supports up to 32 rates, indexed by 1-32.
  *
  * The rate code is used to get the RX rate or set the TX rate on the
  * hardware descriptors. It is also used for internal modulation control
@@ -776,11 +778,11 @@ extern int ath5k_modparam_nohwcrypt;
 /*
  * Misc definitions
  */
-#define        AR5K_RSSI_EP_MULTIPLIER (1<<7)
+#define        AR5K_RSSI_EP_MULTIPLIER (1 << 7)
 
 #define AR5K_ASSERT_ENTRY(_e, _s) do {         \
        if (_e >= _s)                           \
-               return (false);                 \
+               return false;                   \
 } while (0)
 
 /*
@@ -791,52 +793,52 @@ extern int ath5k_modparam_nohwcrypt;
  * enum ath5k_int - Hardware interrupt masks helpers
  *
  * @AR5K_INT_RX: mask to identify received frame interrupts, of type
- *     AR5K_ISR_RXOK or AR5K_ISR_RXERR
+ *     AR5K_ISR_RXOK or AR5K_ISR_RXERR
  * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
  * @AR5K_INT_RXNOFRM: No frame received (?)
  * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
- *     Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
- *     LinkPtr is NULL. For more details, refer to:
- *     http://www.freepatentsonline.com/20030225739.html
+ *     Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
+ *     LinkPtr is NULL. For more details, refer to:
+ *     http://www.freepatentsonline.com/20030225739.html
  * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
- *     Note that Rx overrun is not always fatal, on some chips we can continue
- *     operation without reseting the card, that's why int_fatal is not
- *     common for all chips.
+ *     Note that Rx overrun is not always fatal, on some chips we can continue
+ *     operation without resetting the card, that's why int_fatal is not
+ *     common for all chips.
  * @AR5K_INT_TX: mask to identify received frame interrupts, of type
- *     AR5K_ISR_TXOK or AR5K_ISR_TXERR
+ *     AR5K_ISR_TXOK or AR5K_ISR_TXERR
  * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
  * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
- *     We currently do increments on interrupt by
- *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
+ *     We currently do increments on interrupt by
+ *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
  * @AR5K_INT_MIB: Indicates the either Management Information Base counters or
  *     one of the PHY error counters reached the maximum value and should be
  *     read and cleared.
  * @AR5K_INT_RXPHY: RX PHY Error
  * @AR5K_INT_RXKCM: RX Key cache miss
  * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
- *     beacon that must be handled in software. The alternative is if you
- *     have VEOL support, in that case you let the hardware deal with things.
+ *     beacon that must be handled in software. The alternative is if you
+ *     have VEOL support, in that case you let the hardware deal with things.
  * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
- *     beacons from the AP have associated with, we should probably try to
- *     reassociate. When in IBSS mode this might mean we have not received
- *     any beacons from any local stations. Note that every station in an
- *     IBSS schedules to send beacons at the Target Beacon Transmission Time
- *     (TBTT) with a random backoff.
+ *     beacons from the AP have associated with, we should probably try to
+ *     reassociate. When in IBSS mode this might mean we have not received
+ *     any beacons from any local stations. Note that every station in an
+ *     IBSS schedules to send beacons at the Target Beacon Transmission Time
+ *     (TBTT) with a random backoff.
  * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
  * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
- *     until properly handled
+ *     until properly handled
  * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
- *     errors. These types of errors we can enable seem to be of type
- *     AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ *     errors. These types of errors we can enable seem to be of type
+ *     AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
  * @AR5K_INT_GLOBAL: Used to clear and set the IER
  * @AR5K_INT_NOCARD: signals the card has been removed
- * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
- *     bit value
+ * @AR5K_INT_COMMON: common interrupts shared among MACs with the same
+ *     bit value
  *
  * These are mapped to take advantage of some common bits
  * between the MACs, to be able to set intr properties
  * easier. Some of them are not used yet inside hw.c. Most map
- * to the respective hw interrupt value as they are common amogst different
+ * to the respective hw interrupt value as they are common among different
  * MACs.
  */
 enum ath5k_int {
@@ -968,9 +970,9 @@ enum ath5k_capability_type {
        AR5K_CAP_MCAST_KEYSRCH          = 14,   /* Supports multicast key search */
        AR5K_CAP_TSF_ADJUST             = 15,   /* Supports beacon tsf adjust */
        AR5K_CAP_XR                     = 16,   /* Supports XR mode */
-       AR5K_CAP_WME_TKIPMIC            = 17,   /* Supports TKIP MIC when using WMM */
-       AR5K_CAP_CHAN_HALFRATE          = 18,   /* Supports half rate channels */
-       AR5K_CAP_CHAN_QUARTERRATE       = 19,   /* Supports quarter rate channels */
+       AR5K_CAP_WME_TKIPMIC            = 17,   /* Supports TKIP MIC when using WMM */
+       AR5K_CAP_CHAN_HALFRATE          = 18,   /* Supports half rate channels */
+       AR5K_CAP_CHAN_QUARTERRATE       = 19,   /* Supports quarter rate channels */
        AR5K_CAP_RFSILENT               = 20,   /* Supports RFsilent */
 };
 
@@ -1010,8 +1012,7 @@ struct ath5k_capabilities {
 
 /* size of noise floor history (keep it a power of two) */
 #define ATH5K_NF_CAL_HIST_MAX  8
-struct ath5k_nfcal_hist
-{
+struct ath5k_nfcal_hist {
        s16 index;                              /* current index into nfval */
        s16 nfval[ATH5K_NF_CAL_HIST_MAX];       /* last few noise floors */
 };
@@ -1066,6 +1067,8 @@ struct ath5k_hw {
        u8                      ah_retry_long;
        u8                      ah_retry_short;
 
+       u32                     ah_use_32khz_clock;
+
        u8                      ah_coverage_class;
        bool                    ah_ack_bitrate_high;
        u8                      ah_bwmode;
@@ -1357,17 +1360,17 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                                u8 mode, bool fast);
 
 /*
- * Functions used internaly
+ * Functions used internally
  */
 
 static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
 {
-        return &ah->common;
+       return &ah->common;
 }
 
 static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
 {
-        return &(ath5k_hw_common(ah)->regulatory);
+       return &(ath5k_hw_common(ah)->regulatory);
 }
 
 #ifdef CONFIG_ATHEROS_AR231X
@@ -1378,7 +1381,7 @@ static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
        /* On AR2315 and AR2317 the PCI clock domain registers
         * are outside of the WMAC register space */
        if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
-               (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
+           (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
                return AR5K_AR2315_PCI_BASE + reg;
 
        return ah->ah_iobase + reg;
index 1588401..14dc52e 100644 (file)
@@ -104,6 +104,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
  */
 int ath5k_hw_init(struct ath5k_softc *sc)
 {
+       static const u8 zero_mac[ETH_ALEN] = { };
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
        struct pci_dev *pdev = sc->pdev;
@@ -191,7 +192,7 @@ int ath5k_hw_init(struct ath5k_softc *sc)
                break;
        case AR5K_SREV_RAD_5424:
                if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
-               ah->ah_mac_version == AR5K_SREV_AR2417){
+                   ah->ah_mac_version == AR5K_SREV_AR2417) {
                        ah->ah_radio = AR5K_RF2425;
                        ah->ah_single_chip = true;
                } else {
@@ -210,28 +211,28 @@ int ath5k_hw_init(struct ath5k_softc *sc)
                        ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
                                                                CHANNEL_2GHZ);
                } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
-               ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
-               ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
+                          ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
+                          ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
                        ah->ah_radio = AR5K_RF2425;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
                } else if (srev == AR5K_SREV_AR5213A &&
-               ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
+                          ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
                        ah->ah_radio = AR5K_RF5112;
                        ah->ah_single_chip = false;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4) ||
-                       ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) {
+                          ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) {
                        ah->ah_radio = AR5K_RF2316;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
-               ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
+                          ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
                        ah->ah_radio = AR5K_RF5413;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
                } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
-               ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
+                          ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
                        ah->ah_radio = AR5K_RF2413;
                        ah->ah_single_chip = true;
                        ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
@@ -243,9 +244,8 @@ int ath5k_hw_init(struct ath5k_softc *sc)
        }
 
 
-       /* Return on unsuported chips (unsupported eeprom etc) */
-       if ((srev >= AR5K_SREV_AR5416) &&
-       (srev < AR5K_SREV_AR2425)) {
+       /* Return on unsupported chips (unsupported eeprom etc) */
+       if ((srev >= AR5K_SREV_AR5416) && (srev < AR5K_SREV_AR2425)) {
                ATH5K_ERR(sc, "Device not yet supported.\n");
                ret = -ENODEV;
                goto err;
@@ -285,7 +285,7 @@ int ath5k_hw_init(struct ath5k_softc *sc)
                ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
                ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
 
-               /* If serdes programing is enabled, increase PCI-E
+               /* If serdes programming is enabled, increase PCI-E
                 * tx power for systems with long trace from host
                 * to minicard connector. */
                if (ee->ee_serdes)
@@ -334,7 +334,7 @@ int ath5k_hw_init(struct ath5k_softc *sc)
        }
 
        /* MAC address is cleared until add_interface */
-       ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){});
+       ath5k_hw_set_lladdr(ah, zero_mac);
 
        /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
        memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
index fb05bf8..dce848f 100644 (file)
@@ -532,7 +532,7 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc,
        if (iter_data.n_stas > 1) {
                /* If you have multiple STA interfaces connected to
                 * different APs, ARPs are not received (most of the time?)
-                * Enabling PROMISC appears to fix that probem.
+                * Enabling PROMISC appears to fix that problem.
                 */
                sc->filter_flags |= AR5K_RX_FILTER_PROM;
        }
@@ -815,8 +815,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc)
 
        INIT_LIST_HEAD(&sc->txbuf);
        sc->txbuf_len = ATH_TXBUF;
-       for (i = 0; i < ATH_TXBUF; i++, bf++, ds++,
-                       da += sizeof(*ds)) {
+       for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
                bf->desc = ds;
                bf->daddr = da;
                list_add_tail(&bf->list, &sc->txbuf);
@@ -982,7 +981,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
                goto err;
 
        if (sc->opmode == NL80211_IFTYPE_AP ||
-               sc->opmode == NL80211_IFTYPE_MESH_POINT) {
+           sc->opmode == NL80211_IFTYPE_MESH_POINT) {
                /*
                 * Always burst out beacon and CAB traffic
                 * (aifs = cwmin = cwmax = 0)
@@ -1262,16 +1261,15 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
  */
 static int ath5k_common_padpos(struct sk_buff *skb)
 {
-       struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 frame_control = hdr->frame_control;
        int padpos = 24;
 
-       if (ieee80211_has_a4(frame_control)) {
+       if (ieee80211_has_a4(frame_control))
                padpos += ETH_ALEN;
-       }
-       if (ieee80211_is_data_qos(frame_control)) {
+
+       if (ieee80211_is_data_qos(frame_control))
                padpos += IEEE80211_QOS_CTL_LEN;
-       }
 
        return padpos;
 }
@@ -1285,13 +1283,13 @@ static int ath5k_add_padding(struct sk_buff *skb)
        int padpos = ath5k_common_padpos(skb);
        int padsize = padpos & 3;
 
-       if (padsize && skb->len>padpos) {
+       if (padsize && skb->len > padpos) {
 
                if (skb_headroom(skb) < padsize)
                        return -1;
 
                skb_push(skb, padsize);
-               memmove(skb->data, skb->data+padsize, padpos);
+               memmove(skb->data, skb->data + padsize, padpos);
                return padsize;
        }
 
@@ -1316,7 +1314,7 @@ static int ath5k_remove_padding(struct sk_buff *skb)
        int padpos = ath5k_common_padpos(skb);
        int padsize = padpos & 3;
 
-       if (padsize && skb->len>=padpos+padsize) {
+       if (padsize && skb->len >= padpos + padsize) {
                memmove(skb->data + padsize, skb->data, padpos);
                skb_pull(skb, padsize);
                return padsize;
@@ -1352,7 +1350,7 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
         * timestamp (beginning of phy frame, data frame, end of rx?).
         * The only thing we know is that it is hardware specific...
         * On AR5213 it seems the rx timestamp is at the end of the
-        * frame, but i'm not sure.
+        * frame, but I'm not sure.
         *
         * NOTE: mac80211 defines mactime at the beginning of the first
         * data symbol. Since we don't have any time references it's
@@ -1450,10 +1448,11 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
 static void
 ath5k_set_current_imask(struct ath5k_softc *sc)
 {
-       enum ath5k_int imask = sc->imask;
+       enum ath5k_int imask;
        unsigned long flags;
 
        spin_lock_irqsave(&sc->irqlock, flags);
+       imask = sc->imask;
        if (sc->rx_pending)
                imask &= ~AR5K_INT_RX_ALL;
        if (sc->tx_pending)
@@ -1556,7 +1555,8 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
                goto drop_packet;
        }
 
-       if (txq->txq_len >= txq->txq_max)
+       if (txq->txq_len >= txq->txq_max &&
+           txq->qnum <= AR5K_TX_QUEUE_ID_DATA_MAX)
                ieee80211_stop_queue(hw, txq->qnum);
 
        spin_lock_irqsave(&sc->txbuflock, flags);
@@ -1711,7 +1711,7 @@ ath5k_tasklet_tx(unsigned long data)
        int i;
        struct ath5k_softc *sc = (void *)data;
 
-       for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+       for (i = 0; i < AR5K_NUM_TX_QUEUES; i++)
                if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
                        ath5k_tx_processq(sc, &sc->txqs[i]);
 
@@ -1766,7 +1766,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
         * 4 beacons to make sure everybody hears our AP.
         * When a client tries to associate, hw will keep
         * track of the tx antenna to be used for this client
-        * automaticaly, based on ACKed packets.
+        * automatically, based on ACKed packets.
         *
         * Note: AP still listens and transmits RTS on the
         * default antenna which is supposed to be an omni.
@@ -1902,7 +1902,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
        avf = (void *)vif->drv_priv;
        bf = avf->bbuf;
        if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
-                       sc->opmode == NL80211_IFTYPE_MONITOR)) {
+                    sc->opmode == NL80211_IFTYPE_MONITOR)) {
                ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
                return;
        }
@@ -1919,7 +1919,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 
        /* refresh the beacon for AP or MESH mode */
        if (sc->opmode == NL80211_IFTYPE_AP ||
-                       sc->opmode == NL80211_IFTYPE_MESH_POINT)
+           sc->opmode == NL80211_IFTYPE_MESH_POINT)
                ath5k_beacon_update(sc->hw, vif);
 
        trace_ath5k_tx(sc, bf->skb, &sc->txqs[sc->bhalq]);
@@ -1932,6 +1932,10 @@ ath5k_beacon_send(struct ath5k_softc *sc)
        skb = ieee80211_get_buffered_bc(sc->hw, vif);
        while (skb) {
                ath5k_tx_queue(sc->hw, skb, sc->cabq);
+
+               if (sc->cabq->txq_len >= sc->cabq->txq_max)
+                       break;
+
                skb = ieee80211_get_buffered_bc(sc->hw, vif);
        }
 
@@ -1978,7 +1982,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
        hw_tsf = ath5k_hw_get_tsf64(ah);
        hw_tu = TSF_TO_TU(hw_tsf);
 
-#define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3
+#define FUDGE (AR5K_TUNE_SW_BEACON_RESP + 3)
        /* We use FUDGE to make sure the next TBTT is ahead of the current TU.
         * Since we later subtract AR5K_TUNE_SW_BEACON_RESP (10) in the timer
         * configuration we need to make sure it is bigger than that. */
@@ -2101,11 +2105,11 @@ static void ath5k_tasklet_beacon(unsigned long data)
         *
         * In IBSS mode we use this interrupt just to
         * keep track of the next TBTT (target beacon
-        * transmission time) in order to detect wether
+        * transmission time) in order to detect whether
         * automatic TSF updates happened.
         */
        if (sc->opmode == NL80211_IFTYPE_ADHOC) {
-               /* XXX: only if VEOL suppported */
+               /* XXX: only if VEOL supported */
                u64 tsf = ath5k_hw_get_tsf64(sc->ah);
                sc->nexttbtt += sc->bintval;
                ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
@@ -2200,13 +2204,12 @@ ath5k_intr(int irq, void *dev_id)
                                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                                          "rx overrun, resetting\n");
                                ieee80211_queue_work(sc->hw, &sc->reset_work);
-                       }
-                       else
+                       } else
                                ath5k_schedule_rx(sc);
                } else {
-                       if (status & AR5K_INT_SWBA) {
+                       if (status & AR5K_INT_SWBA)
                                tasklet_hi_schedule(&sc->beacontq);
-                       }
+
                        if (status & AR5K_INT_RXEOL) {
                                /*
                                * NB: the hardware should re-read the link when
@@ -2358,7 +2361,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
 * Initialization routines *
 \*************************/
 
-int
+int __devinit
 ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
 {
        struct ieee80211_hw *hw = sc->hw;
@@ -2423,6 +2426,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
        common->ah = sc->ah;
        common->hw = hw;
        common->priv = sc;
+       common->clockrate = 40;
 
        /*
         * Cache line size is used to size and align various
@@ -2469,7 +2473,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
                                                sc->ah->ah_radio_5ghz_revision),
                                                sc->ah->ah_radio_5ghz_revision);
                        /* No 2GHz support (5110 and some
-                        * 5Ghz only cards) -> report 5Ghz radio */
+                        * 5GHz only cards) -> report 5GHz radio */
                        } else if (!test_bit(AR5K_MODE_11B,
                                sc->ah->ah_capabilities.cap_mode)) {
                                ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
@@ -2488,7 +2492,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
                /* Multi chip radio (RF5111 - RF2111) ->
                 * report both 2GHz/5GHz radios */
                else if (sc->ah->ah_radio_5ghz_revision &&
-                               sc->ah->ah_radio_2ghz_revision){
+                               sc->ah->ah_radio_2ghz_revision) {
                        ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
                                ath5k_chip_name(AR5K_VERSION_RAD,
                                        sc->ah->ah_radio_5ghz_revision),
@@ -2713,8 +2717,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
 
        fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
 
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast,
-                                                               skip_pcu);
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast, skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
                goto err;
@@ -2728,7 +2731,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
 
        ath5k_ani_init(ah, ani_mode);
 
-       ah->ah_cal_next_full = jiffies;
+       ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100);
        ah->ah_cal_next_ani = jiffies;
        ah->ah_cal_next_nf = jiffies;
        ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
@@ -2772,7 +2775,7 @@ static void ath5k_reset_work(struct work_struct *work)
        mutex_unlock(&sc->lock);
 }
 
-static int
+static int __devinit
 ath5k_init(struct ieee80211_hw *hw)
 {
 
@@ -2800,7 +2803,7 @@ ath5k_init(struct ieee80211_hw *hw)
 
        /*
         * Collect the channel list.  The 802.11 layer
-        * is resposible for filtering this list based
+        * is responsible for filtering this list based
         * on settings like the phy mode and regulatory
         * domain restrictions.
         */
index b294f33..0a98777 100644 (file)
@@ -96,8 +96,7 @@ struct ath5k_txq {
 /*
  * State for LED triggers
  */
-struct ath5k_led
-{
+struct ath5k_led {
        char name[ATH5K_LED_MAX_NAME_LEN + 1];  /* name of the LED in sysfs */
        struct ath5k_softc *sc;                 /* driver state */
        struct led_classdev led_dev;            /* led classdev */
@@ -122,7 +121,7 @@ struct ath5k_statistics {
        /* frame errors */
        unsigned int rx_all_count;      /* all RX frames, including errors */
        unsigned int tx_all_count;      /* all TX frames, including errors */
-       unsigned int rx_bytes_count;    /* all RX bytes, including errored pks
+       unsigned int rx_bytes_count;    /* all RX bytes, including errored pkts
                                         * and the MAC headers for each packet
                                         */
        unsigned int tx_bytes_count;    /* all TX bytes, including errored pkts
@@ -154,9 +153,9 @@ struct ath5k_statistics {
 };
 
 #if CHAN_DEBUG
-#define ATH_CHAN_MAX   (26+26+26+200+200)
+#define ATH_CHAN_MAX   (26 + 26 + 26 + 200 + 200)
 #else
-#define ATH_CHAN_MAX   (14+14+14+252+20)
+#define ATH_CHAN_MAX   (14 + 14 + 14 + 252 + 20)
 #endif
 
 struct ath5k_vif {
@@ -251,7 +250,7 @@ struct ath5k_softc {
        unsigned int            nexttbtt;       /* next beacon time in TU */
        struct ath5k_txq        *cabq;          /* content after beacon */
 
-       int                     power_level;    /* Requested tx power in dbm */
+       int                     power_level;    /* Requested tx power in dBm */
        bool                    assoc;          /* associate state */
        bool                    enable_beacon;  /* true if beacons are on */
 
index 7dd88e1..c752982 100644 (file)
@@ -52,8 +52,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
                __set_bit(AR5K_MODE_11A, caps->cap_mode);
        } else {
                /*
-                * XXX The tranceiver supports frequencies from 4920 to 6100GHz
-                * XXX and from 2312 to 2732GHz. There are problems with the
+                * XXX The transceiver supports frequencies from 4920 to 6100MHz
+                * XXX and from 2312 to 2732MHz. There are problems with the
                 * XXX current ieee80211 implementation because the IEEE
                 * XXX channel mapping does not support negative channel
                 * XXX numbers (2312MHz is channel -19). Of course, this
index 0bf7313..4edca70 100644 (file)
@@ -205,35 +205,35 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
        u64 tsf;
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
                "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
                (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
 
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n",
                "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP));
 
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\n\n",
                "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT));
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0);
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
                "AR5K_TIMER0 (TBTT)", v, v);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1);
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
                "AR5K_TIMER1 (DMA)", v, v >> 3);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2);
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
                "AR5K_TIMER2 (SWBA)", v, v >> 3);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3);
-       len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "%-24s0x%08x\tTU: %08x\n",
                "AR5K_TIMER3 (ATIM)", v, v);
 
        tsf = ath5k_hw_get_tsf64(sc->ah);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "TSF\t\t0x%016llx\tTU: %08x\n",
                (unsigned long long)tsf, TSF_TO_TU(tsf));
 
@@ -323,16 +323,16 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
        unsigned int len = 0;
        unsigned int i;
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level);
 
        for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "%10s %c 0x%08x - %s\n", dbg_info[i].name,
                        sc->debug.level & dbg_info[i].level ? '+' : ' ',
                        dbg_info[i].level, dbg_info[i].desc);
        }
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "%10s %c 0x%08x - %s\n", dbg_info[i].name,
                sc->debug.level == dbg_info[i].level ? '+' : ' ',
                dbg_info[i].level, dbg_info[i].desc);
@@ -384,60 +384,60 @@ static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
        unsigned int i;
        unsigned int v;
 
-       len += snprintf(buf+len, sizeof(buf)-len, "antenna mode\t%d\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "antenna mode\t%d\n",
                sc->ah->ah_ant_mode);
-       len += snprintf(buf+len, sizeof(buf)-len, "default antenna\t%d\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "default antenna\t%d\n",
                sc->ah->ah_def_ant);
-       len += snprintf(buf+len, sizeof(buf)-len, "tx antenna\t%d\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "tx antenna\t%d\n",
                sc->ah->ah_tx_ant);
 
-       len += snprintf(buf+len, sizeof(buf)-len, "\nANTENNA\t\tRX\tTX\n");
+       len += snprintf(buf + len, sizeof(buf) - len, "\nANTENNA\t\tRX\tTX\n");
        for (i = 1; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) {
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "[antenna %d]\t%d\t%d\n",
                        i, sc->stats.antenna_rx[i], sc->stats.antenna_tx[i]);
        }
-       len += snprintf(buf+len, sizeof(buf)-len, "[invalid]\t%d\t%d\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "[invalid]\t%d\t%d\n",
                        sc->stats.antenna_rx[0], sc->stats.antenna_tx[0]);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_DEFAULT_ANTENNA);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_STA_ID1);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
                (v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
                (v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
                (v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
                (v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_AGCCTL);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
                (v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_RESTART);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
                (v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_FAST_ANT_DIV);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
                (v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
 
        v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_0);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v);
        v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_1);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v);
 
        if (len > sizeof(buf))
@@ -494,36 +494,36 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
        unsigned int len = 0;
        u32 filt = ath5k_hw_get_rx_filter(sc->ah);
 
-       len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "bssid-mask: %pM\n",
                        sc->bssidmask);
-       len += snprintf(buf+len, sizeof(buf)-len, "filter-flags: 0x%x ",
+       len += snprintf(buf + len, sizeof(buf) - len, "filter-flags: 0x%x ",
                        filt);
        if (filt & AR5K_RX_FILTER_UCAST)
-               len += snprintf(buf+len, sizeof(buf)-len, " UCAST");
+               len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
        if (filt & AR5K_RX_FILTER_MCAST)
-               len += snprintf(buf+len, sizeof(buf)-len, " MCAST");
+               len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
        if (filt & AR5K_RX_FILTER_BCAST)
-               len += snprintf(buf+len, sizeof(buf)-len, " BCAST");
+               len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
        if (filt & AR5K_RX_FILTER_CONTROL)
-               len += snprintf(buf+len, sizeof(buf)-len, " CONTROL");
+               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
        if (filt & AR5K_RX_FILTER_BEACON)
-               len += snprintf(buf+len, sizeof(buf)-len, " BEACON");
+               len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
        if (filt & AR5K_RX_FILTER_PROM)
-               len += snprintf(buf+len, sizeof(buf)-len, " PROM");
+               len += snprintf(buf + len, sizeof(buf) - len, " PROM");
        if (filt & AR5K_RX_FILTER_XRPOLL)
-               len += snprintf(buf+len, sizeof(buf)-len, " XRPOLL");
+               len += snprintf(buf + len, sizeof(buf) - len, " XRPOLL");
        if (filt & AR5K_RX_FILTER_PROBEREQ)
-               len += snprintf(buf+len, sizeof(buf)-len, " PROBEREQ");
+               len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
        if (filt & AR5K_RX_FILTER_PHYERR_5212)
-               len += snprintf(buf+len, sizeof(buf)-len, " PHYERR-5212");
+               len += snprintf(buf + len, sizeof(buf) - len, " PHYERR-5212");
        if (filt & AR5K_RX_FILTER_RADARERR_5212)
-               len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5212");
+               len += snprintf(buf + len, sizeof(buf) - len, " RADARERR-5212");
        if (filt & AR5K_RX_FILTER_PHYERR_5211)
-               snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211");
+               snprintf(buf + len, sizeof(buf) - len, " PHYERR-5211");
        if (filt & AR5K_RX_FILTER_RADARERR_5211)
-               len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211");
+               len += snprintf(buf + len, sizeof(buf) - len, " RADARERR-5211");
 
-       len += snprintf(buf+len, sizeof(buf)-len, "\nopmode: %s (%d)\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "\nopmode: %s (%d)\n",
                        ath_opmode_to_string(sc->opmode), sc->opmode);
 
        if (len > sizeof(buf))
@@ -550,65 +550,65 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
        unsigned int len = 0;
        int i;
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "RX\n---------------------\n");
-       len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%u\t(%u%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "CRC\t%u\t(%u%%)\n",
                        st->rxerr_crc,
                        st->rx_all_count > 0 ?
-                               st->rxerr_crc*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%u\t(%u%%)\n",
+                               st->rxerr_crc * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "PHY\t%u\t(%u%%)\n",
                        st->rxerr_phy,
                        st->rx_all_count > 0 ?
-                               st->rxerr_phy*100/st->rx_all_count : 0);
+                               st->rxerr_phy * 100 / st->rx_all_count : 0);
        for (i = 0; i < 32; i++) {
                if (st->rxerr_phy_code[i])
-                       len += snprintf(buf+len, sizeof(buf)-len,
+                       len += snprintf(buf + len, sizeof(buf) - len,
                                " phy_err[%u]\t%u\n",
                                i, st->rxerr_phy_code[i]);
        }
 
-       len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
                        st->rxerr_fifo,
                        st->rx_all_count > 0 ?
-                               st->rxerr_fifo*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%u\t(%u%%)\n",
+                               st->rxerr_fifo * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "decrypt\t%u\t(%u%%)\n",
                        st->rxerr_decrypt,
                        st->rx_all_count > 0 ?
-                               st->rxerr_decrypt*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%u\t(%u%%)\n",
+                               st->rxerr_decrypt * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "MIC\t%u\t(%u%%)\n",
                        st->rxerr_mic,
                        st->rx_all_count > 0 ?
-                               st->rxerr_mic*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "process\t%u\t(%u%%)\n",
+                               st->rxerr_mic * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "process\t%u\t(%u%%)\n",
                        st->rxerr_proc,
                        st->rx_all_count > 0 ?
-                               st->rxerr_proc*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%u\t(%u%%)\n",
+                               st->rxerr_proc * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "jumbo\t%u\t(%u%%)\n",
                        st->rxerr_jumbo,
                        st->rx_all_count > 0 ?
-                               st->rxerr_jumbo*100/st->rx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%u]\n",
+                               st->rxerr_jumbo * 100 / st->rx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "[RX all\t%u]\n",
                        st->rx_all_count);
-       len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%u\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "RX-all-bytes\t%u\n",
                        st->rx_bytes_count);
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "\nTX\n---------------------\n");
-       len += snprintf(buf+len, sizeof(buf)-len, "retry\t%u\t(%u%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "retry\t%u\t(%u%%)\n",
                        st->txerr_retry,
                        st->tx_all_count > 0 ?
-                               st->txerr_retry*100/st->tx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n",
+                               st->txerr_retry * 100 / st->tx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "FIFO\t%u\t(%u%%)\n",
                        st->txerr_fifo,
                        st->tx_all_count > 0 ?
-                               st->txerr_fifo*100/st->tx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "filter\t%u\t(%u%%)\n",
+                               st->txerr_fifo * 100 / st->tx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "filter\t%u\t(%u%%)\n",
                        st->txerr_filt,
                        st->tx_all_count > 0 ?
-                               st->txerr_filt*100/st->tx_all_count : 0);
-       len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%u]\n",
+                               st->txerr_filt * 100 / st->tx_all_count : 0);
+       len += snprintf(buf + len, sizeof(buf) - len, "[TX all\t%u]\n",
                        st->tx_all_count);
-       len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%u\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "TX-all-bytes\t%u\n",
                        st->tx_bytes_count);
 
        if (len > sizeof(buf))
@@ -667,89 +667,93 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
        char buf[700];
        unsigned int len = 0;
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "HW has PHY error counters:\t%s\n",
                        sc->ah->ah_capabilities.cap_has_phyerr_counters ?
                        "yes" : "no");
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "HW max spur immunity level:\t%d\n",
                        as->max_spur_level);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                "\nANI state\n--------------------------------------------\n");
-       len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t");
+       len += snprintf(buf + len, sizeof(buf) - len, "operating mode:\t\t\t");
        switch (as->ani_mode) {
        case ATH5K_ANI_MODE_OFF:
-               len += snprintf(buf+len, sizeof(buf)-len, "OFF\n");
+               len += snprintf(buf + len, sizeof(buf) - len, "OFF\n");
                break;
        case ATH5K_ANI_MODE_MANUAL_LOW:
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "MANUAL LOW\n");
                break;
        case ATH5K_ANI_MODE_MANUAL_HIGH:
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "MANUAL HIGH\n");
                break;
        case ATH5K_ANI_MODE_AUTO:
-               len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n");
+               len += snprintf(buf + len, sizeof(buf) - len, "AUTO\n");
                break;
        default:
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "??? (not good)\n");
                break;
        }
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "noise immunity level:\t\t%d\n",
                        as->noise_imm_level);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "spur immunity level:\t\t%d\n",
                        as->spur_level);
-       len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n",
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "firstep level:\t\t\t%d\n",
                        as->firstep_level);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "OFDM weak signal detection:\t%s\n",
                        as->ofdm_weak_sig ? "on" : "off");
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "CCK weak signal detection:\t%s\n",
                        as->cck_weak_sig ? "on" : "off");
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "\nMIB INTERRUPTS:\t\t%u\n",
                        st->mib_intr);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "beacon RSSI average:\t%d\n",
                        (int)ewma_read(&sc->ah->ah_beacon_rssi_avg));
 
 #define CC_PRINT(_struct, _field) \
        _struct._field, \
        _struct.cycles > 0 ? \
-       _struct._field*100/_struct.cycles : 0
+       _struct._field * 100 / _struct.cycles : 0
 
-       len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "profcnt tx\t\t%u\t(%d%%)\n",
                        CC_PRINT(as->last_cc, tx_frame));
-       len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "profcnt rx\t\t%u\t(%d%%)\n",
                        CC_PRINT(as->last_cc, rx_frame));
-       len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n",
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "profcnt busy\t\t%u\t(%d%%)\n",
                        CC_PRINT(as->last_cc, rx_busy));
 #undef CC_PRINT
-       len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n",
+       len += snprintf(buf + len, sizeof(buf) - len, "profcnt cycles\t\t%u\n",
                        as->last_cc.cycles);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "listen time\t\t%d\tlast: %d\n",
                        as->listen_time, as->last_listen);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
                        as->ofdm_errors, as->last_ofdm_errors,
                        as->sum_ofdm_errors);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "CCK errors\t\t%u\tlast: %u\tsum: %u\n",
                        as->cck_errors, as->last_cck_errors,
                        as->sum_cck_errors);
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
                        ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1),
                        ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
                        ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1)));
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
                        ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2),
                        ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
@@ -827,13 +831,13 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
        struct ath5k_buf *bf, *bf0;
        int i, n;
 
-       len += snprintf(buf+len, sizeof(buf)-len,
+       len += snprintf(buf + len, sizeof(buf) - len,
                        "available txbuffers: %d\n", sc->txbuf_len);
 
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
                txq = &sc->txqs[i];
 
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                        "%02d: %ssetup\n", i, txq->setup ? "" : "not ");
 
                if (!txq->setup)
@@ -845,9 +849,9 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
                        n++;
                spin_unlock_bh(&txq->lock);
 
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                                "  len: %d bufs: %d\n", txq->txq_len, n);
-               len += snprintf(buf+len, sizeof(buf)-len,
+               len += snprintf(buf + len, sizeof(buf) - len,
                                "  stuck: %d\n", txq->txq_stuck);
        }
 
@@ -894,7 +898,7 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
 
        phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
        if (!phydir)
-           return;
+               return;
 
        debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
                            &fops_debug);
@@ -918,6 +922,9 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
 
        debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
                            &fops_queue);
+
+       debugfs_create_bool("32khz_clock", S_IWUSR | S_IRUSR, phydir,
+                           &sc->ah->ah_use_32khz_clock);
 }
 
 /* functions used in other places */
index 2509d0b..cfd529b 100644 (file)
@@ -58,11 +58,11 @@ struct ath5k_hw_rx_status {
 #define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK     0x00000002 /* reception success */
 #define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR            0x00000004 /* CRC error */
 #define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210    0x00000008 /* [5210] FIFO overrun */
-#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR    0x00000010 /* decyption CRC failure */
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR    0x00000010 /* decryption CRC failure */
 #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR            0x000000e0 /* PHY error */
 #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S          5
 #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID      0x00000100 /* key index valid */
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX            0x00007e00 /* decyption key index */
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX            0x00007e00 /* decryption key index */
 #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S          9
 #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP    0x0fff8000 /* 13 bit of TSF */
 #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S  15
index 21091c2..b788ecf 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
  * handle queue setup for 5210 chipset (rest are handled on qcu.c).
- * Also we setup interrupt mask register (IMR) and read the various iterrupt
+ * Also we setup interrupt mask register (IMR) and read the various interrupt
  * status registers (ISR).
  *
  * TODO: Handle SISR on 5211+ and introduce a function to return the queue
@@ -258,7 +258,7 @@ static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
                /* For 2413+ order PCU to drop packets using
                 * QUIET mechanism */
                if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) &&
-               pending){
+                   pending) {
                        /* Set periodicity and duration */
                        ath5k_hw_reg_write(ah,
                                AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
@@ -726,7 +726,7 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
                        int_mask |= AR5K_IMR_RXDOPPLER;
 
                /* Note: Per queue interrupt masks
-                * are set via reset_tx_queue (qcu.c) */
+                * are set via ath5k_hw_reset_tx_queue() (qcu.c) */
                ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
                ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
 
@@ -783,7 +783,7 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
         * for all PCI-E cards to be safe).
         *
         * XXX: need to check 5210 for this
-        * TODO: Check out tx triger level, it's always 64 on dumps but I
+        * TODO: Check out tx trigger level, it's always 64 on dumps but I
         * guess we can tweak it and see how it goes ;-)
         */
        if (ah->ah_version != AR5K_AR5210) {
index 392771f..d9e605e 100644 (file)
@@ -223,14 +223,14 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
        ah->ah_ant_ctl[mode][AR5K_ANT_CTL] =
            (ee->ee_ant_control[mode][0] << 4);
        ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] =
-            ee->ee_ant_control[mode][1]        |
-           (ee->ee_ant_control[mode][2] << 6)  |
+            ee->ee_ant_control[mode][1]        |
+           (ee->ee_ant_control[mode][2] << 6)  |
            (ee->ee_ant_control[mode][3] << 12) |
            (ee->ee_ant_control[mode][4] << 18) |
            (ee->ee_ant_control[mode][5] << 24);
        ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] =
-            ee->ee_ant_control[mode][6]        |
-           (ee->ee_ant_control[mode][7] << 6)  |
+            ee->ee_ant_control[mode][6]        |
+           (ee->ee_ant_control[mode][7] << 6)  |
            (ee->ee_ant_control[mode][8] << 12) |
            (ee->ee_ant_control[mode][9] << 18) |
            (ee->ee_ant_control[mode][10] << 24);
@@ -255,7 +255,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
        ee->ee_n_piers[mode] = 0;
        AR5K_EEPROM_READ(o++, val);
        ee->ee_adc_desired_size[mode]   = (s8)((val >> 8) & 0xff);
-       switch(mode) {
+       switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                ee->ee_ob[mode][3]      = (val >> 5) & 0x7;
                ee->ee_db[mode][3]      = (val >> 2) & 0x7;
@@ -349,7 +349,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
        /* Note: >= v5 have bg freq piers on another location
         * so these freq piers are ignored for >= v5 (should be 0xff
         * anyway) */
-       switch(mode) {
+       switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
                        break;
@@ -422,7 +422,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
        if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
                goto done;
 
-       switch (mode){
+       switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
 
@@ -436,7 +436,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
                ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
                ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
 
-               if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+               if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >= 2)
                        ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
                break;
        case AR5K_EEPROM_MODE_11G:
@@ -516,7 +516,7 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
        u16 val;
 
        ee->ee_n_piers[mode] = 0;
-       while(i < max) {
+       while (i < max) {
                AR5K_EEPROM_READ(o++, val);
 
                freq1 = val & 0xff;
@@ -602,7 +602,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        struct ath5k_chan_pcal_info *pcal;
 
-       switch(mode) {
+       switch (mode) {
        case AR5K_EEPROM_MODE_11B:
                pcal = ee->ee_pwr_cal_b;
                break;
@@ -634,7 +634,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
 /* Used to match PCDAC steps with power values on RF5111 chips
  * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
  * steps that match with the power values we read from eeprom. On
- * older eeprom versions (< 3.2) these steps are equaly spaced at
+ * older eeprom versions (< 3.2) these steps are equally spaced at
  * 10% of the pcdac curve -until the curve reaches its maximum-
  * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
  * these 11 steps are spaced in a different way. This function returns
@@ -644,10 +644,12 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
 static inline void
 ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
 {
-       static const u16 intercepts3[] =
-               { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
-       static const u16 intercepts3_2[] =
-               { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+       static const u16 intercepts3[] = {
+               0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100
+       };
+       static const u16 intercepts3_2[] = {
+               0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
+       };
        const u16 *ip;
        int i;
 
@@ -762,7 +764,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
 
                /* Fill raw dataset
                 * (convert power to 0.25dB units
-                * for RF5112 combatibility) */
+                * for RF5112 compatibility) */
                for (point = 0; point < pd->pd_points; point++) {
 
                        /* Absolute values */
@@ -796,7 +798,7 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
        u16 val;
 
        offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
-       switch(mode) {
+       switch (mode) {
        case AR5K_EEPROM_MODE_11A:
                if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
                        return 0;
@@ -882,7 +884,7 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
  * Read power calibration for RF5112 chips
  *
  * For RF5112 we have 4 XPD -eXternal Power Detector- curves
- * for each calibrated channel on 0, -6, -12 and -18dbm but we only
+ * for each calibrated channel on 0, -6, -12 and -18dBm but we only
  * use the higher (3) and the lower (0) curves. Each curve has 0.5dB
  * power steps on x axis and PCDAC steps on y axis and looks like a
  * linear function. To recreate the curve and pass the power values
@@ -1163,7 +1165,7 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
 {
        u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
 
-       switch(mode) {
+       switch (mode) {
        case AR5K_EEPROM_MODE_11G:
                if (AR5K_EEPROM_HDR_11B(ee->ee_header))
                        offset += ath5k_pdgains_size_2413(ee,
@@ -1239,7 +1241,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
 
                        /* Fill raw dataset
                         * convert all pwr levels to
-                        * quarter dB for RF5112 combatibility */
+                        * quarter dB for RF5112 compatibility */
                        pd->pd_step[0] = pcinfo->pddac_i[pdg];
                        pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
 
@@ -1620,8 +1622,8 @@ ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
                offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
 
        rep = ee->ee_ctl_pwr;
-       for(i = 0; i < ee->ee_ctls; i++) {
-               switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+       for (i = 0; i < ee->ee_ctls; i++) {
+               switch (ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
                case AR5K_CTL_11A:
                case AR5K_CTL_TURBO:
                        ctl_mode = AR5K_EEPROM_MODE_11A;
index 6511c27..dc2bcfe 100644 (file)
@@ -50,7 +50,7 @@
 
 #define AR5K_EEPROM_VERSION            AR5K_EEPROM_INFO(1)     /* EEPROM Version */
 #define AR5K_EEPROM_VERSION_3_0                0x3000  /* No idea what's going on before this version */
-#define AR5K_EEPROM_VERSION_3_1                0x3001  /* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_1                0x3001  /* ob/db values for 2GHz (ar5211_rfregs) */
 #define AR5K_EEPROM_VERSION_3_2                0x3002  /* different frequency representation (eeprom_bin2freq) */
 #define AR5K_EEPROM_VERSION_3_3                0x3003  /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
 #define AR5K_EEPROM_VERSION_3_4                0x3004  /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
 #define AR5K_EEPROM_HDR_11A(_v)                (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
 #define AR5K_EEPROM_HDR_11B(_v)                (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
 #define AR5K_EEPROM_HDR_11G(_v)                (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1)     /* Disable turbo for 2Ghz */
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1)     /* Disable turbo for 2GHz */
 #define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f)    /* Max turbo power for < 2W power consumption */
 #define AR5K_EEPROM_HDR_DEVICE(_v)     (((_v) >> 11) & 0x7)    /* Device type (1 Cardbus, 2 PCI, 3 MiniPCI, 4 AP) */
 #define AR5K_EEPROM_HDR_RFKILL(_v)     (((_v) >> 14) & 0x1)    /* Device has RFKill support */
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1)    /* Disable turbo for 5Ghz */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1)    /* Disable turbo for 5GHz */
 
 /* Newer EEPROMs are using a different offset */
 #define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
 #define AR5K_EEPROM_FF_DIS(_v)         (((_v) >> 2) & 0x1)     /* disable fast frames */
 #define AR5K_EEPROM_BURST_DIS(_v)      (((_v) >> 3) & 0x1)     /* disable bursting */
 #define AR5K_EEPROM_MAX_QCU(_v)                (((_v) >> 4) & 0xf)     /* max number of QCUs. defaults to 10 */
-#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)  (((_v) >> 8) & 0x1)     /* enable heayy clipping */
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)  (((_v) >> 8) & 0x1)     /* enable heavy clipping */
 #define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf)    /* key cache size. defaults to 128 */
 
 #define AR5K_EEPROM_MISC6              AR5K_EEPROM_INFO(10)
 #define AR5K_EEPROM_CCK_OFDM_DELTA     15
 #define AR5K_EEPROM_N_IQ_CAL           2
 /* 5GHz/2GHz */
-enum ath5k_eeprom_freq_bands{
+enum ath5k_eeprom_freq_bands {
        AR5K_EEPROM_BAND_5GHZ = 0,
        AR5K_EEPROM_BAND_2GHZ = 1,
        AR5K_EEPROM_N_FREQ_BANDS,
@@ -270,7 +270,7 @@ enum ath5k_ctl_mode {
 
 /* Per channel calibration data, used for power table setup */
 struct ath5k_chan_pcal_info_rf5111 {
-       /* Power levels in half dbm units
+       /* Power levels in half dBm units
         * for one power curve. */
        u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
        /* PCDAC table steps
index e49340d..855d1af 100644 (file)
@@ -113,8 +113,8 @@ static const struct ath5k_ini ar5210_ini[] = {
        { AR5K_PHY(28), 0x0000000f },
        { AR5K_PHY(29), 0x00000080 },
        { AR5K_PHY(30), 0x00000004 },
-       { AR5K_PHY(31), 0x00000018 },   /* 0x987c */
-       { AR5K_PHY(64), 0x00000000 },   /* 0x9900 */
+       { AR5K_PHY(31), 0x00000018 },   /* 0x987c */
+       { AR5K_PHY(64), 0x00000000 },   /* 0x9900 */
        { AR5K_PHY(65), 0x00000000 },
        { AR5K_PHY(66), 0x00000000 },
        { AR5K_PHY(67), 0x00800000 },
@@ -549,7 +549,7 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
        { AR5K_DIAG_SW_5211,    0x00000000 },
        { AR5K_ADDAC_TEST,      0x00000000 },
        { AR5K_DEFAULT_ANTENNA, 0x00000000 },
-       { AR5K_FRAME_CTL_QOSM,  0x000fc78f },
+       { AR5K_FRAME_CTL_QOSM,  0x000fc78f },
        { AR5K_XRMODE,          0x2a82301a },
        { AR5K_XRDELAY,         0x05dc01e0 },
        { AR5K_XRTIMEOUT,       0x1f402710 },
@@ -760,9 +760,9 @@ static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
 
 static const struct ath5k_ini rf5111_ini_common_end[] = {
        { AR5K_DCU_FP,          0x00000000 },
-       { AR5K_PHY_AGC,         0x00000000 },
-       { AR5K_PHY_ADC_CTL,     0x00022ffe },
-       { 0x983c,               0x00020100 },
+       { AR5K_PHY_AGC,         0x00000000 },
+       { AR5K_PHY_ADC_CTL,     0x00022ffe },
+       { 0x983c,               0x00020100 },
        { AR5K_PHY_GAIN_OFFSET, 0x1284613c },
        { AR5K_PHY_PAPD_PROBE,  0x00004883 },
        { 0x9940,               0x00000004 },
@@ -1409,7 +1409,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
         * Write initial register settings
         */
 
-       /* For AR5212 and combatible */
+       /* For AR5212 and compatible */
        if (ah->ah_version == AR5K_AR5212) {
 
                /* First set of mode-specific settings */
index 576edf2..127bfbd 100644 (file)
 #include "ath5k.h"
 #include "base.h"
 
-#define ATH_SDEVICE(subv,subd) \
+#define ATH_SDEVICE(subv, subd) \
        .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
        .subvendor = (subv), .subdevice = (subd)
 
-#define ATH_LED(pin,polarity) .driver_data = (((pin) << 8) | (polarity))
+#define ATH_LED(pin, polarity) .driver_data = (((pin) << 8) | (polarity))
 #define ATH_PIN(data) ((data) >> 8)
 #define ATH_POLARITY(data) ((data) & 0xff)
 
 /* Devices we match on for LED config info (typically laptops) */
-static const struct pci_device_id ath5k_led_devices[] = {
+static DEFINE_PCI_DEVICE_TABLE(ath5k_led_devices) = {
        /* AR5211 */
        { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) },
        /* HP Compaq nc6xx, nc4000, nx6000 */
@@ -157,7 +157,7 @@ void ath5k_unregister_leds(struct ath5k_softc *sc)
        ath5k_unregister_led(&sc->tx_led);
 }
 
-int ath5k_init_leds(struct ath5k_softc *sc)
+int __devinit ath5k_init_leds(struct ath5k_softc *sc)
 {
        int ret = 0;
        struct ieee80211_hw *hw = sc->hw;
index 4939082..0d5ab34 100644 (file)
@@ -348,7 +348,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw,
                mfilt[pos / 32] |= (1 << (pos % 32));
                /* XXX: we might be able to just do this instead,
                * but not sure, needs testing, if we do use this we'd
-               * neet to inform below to not reset the mcast */
+               * need to inform below not to reset the mcast */
                /* ath5k_hw_set_mcast_filterindex(ah,
                 *      ha->addr[5]); */
        }
@@ -471,7 +471,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
        if (iter_data.n_stas > 1) {
                /* If you have multiple STA interfaces connected to
                 * different APs, ARPs are not received (most of the time?)
-                * Enabling PROMISC appears to fix that probem.
+                * Enabling PROMISC appears to fix that problem.
                 */
                rfilt |= AR5K_RX_FILTER_PROM;
        }
index f2c0c23..aac5b78 100644 (file)
@@ -34,12 +34,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
        { PCI_VDEVICE(3COM_2,  0x0013) }, /* 3com 5212 */
        { PCI_VDEVICE(3COM,    0x0013) }, /* 3com 3CRDAG675 5212 */
        { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
-       { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 compatible */
+       { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 compatible */
+       { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 compatible */
+       { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 compatible */
+       { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 compatible */
+       { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 compatible */
        { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
        { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
        { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
@@ -234,7 +234,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
 
        mem = pci_iomap(pdev, 0, 0);
        if (!mem) {
-               dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+               dev_err(&pdev->dev, "cannot remap PCI memory region\n");
                ret = -EIO;
                goto err_reg;
        }
index 712a9ac..618ee54 100644 (file)
@@ -32,7 +32,7 @@
 #include "base.h"
 
 /*
- * AR5212+ can use higher rates for ack transmition
+ * AR5212+ can use higher rates for ack transmission
  * based on current tx rate instead of the base rate.
  * It does this to better utilize channel usage.
  * This is a mapping between G rates (that cover both
@@ -534,9 +534,9 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
 
        local_irq_restore(flags);
 
-       WARN_ON( i == ATH5K_MAX_TSF_READ );
+       WARN_ON(i == ATH5K_MAX_TSF_READ);
 
-       return (((u64)tsf_upper1 << 32) | tsf_lower);
+       return ((u64)tsf_upper1 << 32) | tsf_lower;
 }
 
 /**
@@ -643,14 +643,14 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
        /* Flush any pending BMISS interrupts on ISR by
         * performing a clear-on-write operation on PISR
         * register for the BMISS bit (writing a bit on
-        * ISR togles a reset for that bit and leaves
-        * the rest bits intact) */
+        * ISR toggles a reset for that bit and leaves
+        * the remaining bits intact) */
        if (ah->ah_version == AR5K_AR5210)
                ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
        else
                ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
 
-       /* TODO: Set enchanced sleep registers on AR5212
+       /* TODO: Set enhanced sleep registers on AR5212
         * based on vif->bss_conf params, until then
         * disable power save reporting.*/
        AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
@@ -738,7 +738,7 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
        dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3;
 
        /* NOTE: SWBA is different. Having a wrong window there does not
-        * stop us from sending data and this condition is catched thru
+        * stop us from sending data and this condition is caught by
         * other means (SWBA interrupt) */
 
        if (ath5k_check_timer_win(nbtt, atim, 1, intval) &&
@@ -896,7 +896,7 @@ void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        /* Set RSSI/BRSSI thresholds
         *
         * Note: If we decide to set this value
-        * dynamicaly, have in mind that when AR5K_RSSI_THR
+        * dynamically, have in mind that when AR5K_RSSI_THR
         * register is read it might return 0x40 if we haven't
         * wrote anything to it plus BMISS RSSI threshold is zeroed.
         * So doing a save/restore procedure here isn't the right
index 5544191..dd2b417 100644 (file)
@@ -105,6 +105,7 @@ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
 
        if ((ah->ah_radio == AR5K_RF5112) ||
        (ah->ah_radio == AR5K_RF5413) ||
+       (ah->ah_radio == AR5K_RF2413) ||
        (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
                refclk_freq = 40;
        else
@@ -173,7 +174,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
                data = ath5k_hw_bitswap(val, num_bits);
 
        for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
-       position = 0, entry++) {
+            position = 0, entry++) {
 
                last_bit = (position + bits_left > 8) ? 8 :
                                        position + bits_left;
@@ -363,7 +364,7 @@ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
        return 0;
 }
 
-/* Schedule a gain probe check on the next transmited packet.
+/* Schedule a gain probe check on the next transmitted packet.
  * That means our next packet is going to be sent with lower
  * tx power and a Peak to Average Power Detector (PAPD) will try
  * to measure the gain.
@@ -472,7 +473,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
                level[0] = 0;
                level[1] = (step == 63) ? 50 : step + 4;
                level[2] = (step != 63) ? 64 : level[0];
-               level[3] = level[2] + 50 ;
+               level[3] = level[2] + 50;
 
                ah->ah_gain.g_high = level[3] -
                        (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
@@ -549,7 +550,7 @@ static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
 
                for (ah->ah_gain.g_target = ah->ah_gain.g_current;
                                ah->ah_gain.g_target <= ah->ah_gain.g_low &&
-                               ah->ah_gain.g_step_idx < go->go_steps_count-1;
+                               ah->ah_gain.g_step_idx < go->go_steps_count - 1;
                                g_step = &go->go_step[ah->ah_gain.g_step_idx])
                        ah->ah_gain.g_target -= 2 *
                            (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
@@ -614,13 +615,13 @@ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
                        ath5k_hw_rf_gainf_corr(ah);
                        ah->ah_gain.g_current =
                                ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
-                               (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+                               (ah->ah_gain.g_current - ah->ah_gain.g_f_corr) :
                                0;
                }
 
                /* Check if measurement is ok and if we need
                 * to adjust gain, schedule a gain adjustment,
-                * else switch back to the acive state */
+                * else switch back to the active state */
                if (ath5k_hw_rf_check_gainf_readback(ah) &&
                AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
                ath5k_hw_rf_gainf_adjust(ah)) {
@@ -807,7 +808,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
                 * use b_OB and b_DB parameters stored
                 * in eeprom on ee->ee_ob[ee_mode][0]
                 *
-                * For all other chips we use OB/DB for 2Ghz
+                * For all other chips we use OB/DB for 2GHz
                 * stored in the b/g modal section just like
                 * 802.11a on ee->ee_ob[ee_mode][1] */
                if ((ah->ah_radio == AR5K_RF5111) ||
@@ -970,17 +971,20 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
                        }
 
                        /* Lower synth voltage on Rev 2 */
-                       ath5k_hw_rfb_op(ah, rf_regs, 2,
-                                       AR5K_RF_HIGH_VC_CP, true);
+                       if (ah->ah_radio == AR5K_RF5112 &&
+                           (ah->ah_radio_5ghz_revision & AR5K_SREV_REV) > 0) {
+                               ath5k_hw_rfb_op(ah, rf_regs, 2,
+                                               AR5K_RF_HIGH_VC_CP, true);
 
-                       ath5k_hw_rfb_op(ah, rf_regs, 2,
-                                       AR5K_RF_MID_VC_CP, true);
+                               ath5k_hw_rfb_op(ah, rf_regs, 2,
+                                               AR5K_RF_MID_VC_CP, true);
 
-                       ath5k_hw_rfb_op(ah, rf_regs, 2,
-                                       AR5K_RF_LOW_VC_CP, true);
+                               ath5k_hw_rfb_op(ah, rf_regs, 2,
+                                               AR5K_RF_LOW_VC_CP, true);
 
-                       ath5k_hw_rfb_op(ah, rf_regs, 2,
-                                       AR5K_RF_PUSH_UP, true);
+                               ath5k_hw_rfb_op(ah, rf_regs, 2,
+                                               AR5K_RF_PUSH_UP, true);
+                       }
 
                        /* Decrease power consumption on 5213+ BaseBand */
                        if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
@@ -1259,7 +1263,7 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
 {
        int ret;
        /*
-        * Check bounds supported by the PHY (we don't care about regultory
+        * Check bounds supported by the PHY (we don't care about regulatory
         * restrictions at this point). Note: hw_value already has the band
         * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
         * of the band by that */
@@ -1331,7 +1335,7 @@ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
 static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
 {
        struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
-       hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
+       hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX - 1);
        hist->nfval[hist->index] = noise_floor;
 }
 
@@ -1344,10 +1348,10 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
        memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
        for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
                for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
-                       if (sort[j] > sort[j-1]) {
+                       if (sort[j] > sort[j - 1]) {
                                tmp = sort[j];
-                               sort[j] = sort[j-1];
-                               sort[j-1] = tmp;
+                               sort[j] = sort[j - 1];
+                               sort[j - 1] = tmp;
                        }
                }
        }
@@ -1355,7 +1359,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
                ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
                        "cal %d:%d\n", i, sort[i]);
        }
-       return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
+       return sort[(ATH5K_NF_CAL_HIST_MAX - 1) / 2];
 }
 
 /*
@@ -1604,11 +1608,13 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
        int ret;
 
        if (ah->ah_radio == AR5K_RF5110)
-               ret = ath5k_hw_rf5110_calibrate(ah, channel);
-       else {
-               ret = ath5k_hw_rf511x_iq_calibrate(ah);
+               return ath5k_hw_rf5110_calibrate(ah, channel);
+
+       ret = ath5k_hw_rf511x_iq_calibrate(ah);
+
+       if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) &&
+           (channel->hw_value & CHANNEL_OFDM))
                ath5k_hw_request_rfgain_probe(ah);
-       }
 
        return ret;
 }
@@ -1815,7 +1821,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
 
        } else if (ath5k_hw_reg_read(ah, AR5K_PHY_IQ) &
        AR5K_PHY_IQ_SPUR_FILT_EN) {
-               /* Clean up spur mitigation settings and disable fliter */
+               /* Clean up spur mitigation settings and disable filter */
                AR5K_REG_WRITE_BITS(ah, AR5K_PHY_BIN_MASK_CTL,
                                        AR5K_PHY_BIN_MASK_CTL_RATE, 0);
                AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_IQ,
@@ -2080,7 +2086,7 @@ ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
         * always 1 instead of 1.25, 1.75 etc). We scale up by 100
         * to have some accuracy both for 0.5 and 0.25 steps.
         */
-       ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
+       ratio = ((100 * y_right - 100 * y_left) / (x_right - x_left));
 
        /* Now scale down to be in range */
        result = y_left + (ratio * (target - x_left) / 100);
@@ -2159,7 +2165,7 @@ ath5k_create_power_curve(s16 pmin, s16 pmax,
                        u8 *vpd_table, u8 type)
 {
        u8 idx[2] = { 0, 1 };
-       s16 pwr_i = 2*pmin;
+       s16 pwr_i = 2 * pmin;
        int i;
 
        if (num_points < 2)
@@ -2437,7 +2443,7 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
        }
 
        if (edge_pwr)
-               ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
+               ah->ah_txpower.txp_max_pwr = 4 * min(edge_pwr, max_chan_pwr);
 }
 
 
@@ -2456,7 +2462,7 @@ static void
 ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
                                                        s16 *table_max)
 {
-       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
+       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
        u8      *pcdac_tmp = ah->ah_txpower.tmpL[0];
        u8      pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
        s16     min_pwr, max_pwr;
@@ -2475,8 +2481,8 @@ ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
 
        /* Copy values from pcdac_tmp */
        pwr_idx = min_pwr;
-       for (i = 0 ; pwr_idx <= max_pwr &&
-       pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
+       for (i = 0; pwr_idx <= max_pwr &&
+                   pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
                pcdac_out[pcdac_i++] = pcdac_tmp[i];
                pwr_idx++;
        }
@@ -2502,7 +2508,7 @@ static void
 ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
                                                s16 *table_max, u8 pdcurves)
 {
-       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
+       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
        u8      *pcdac_low_pwr;
        u8      *pcdac_high_pwr;
        u8      *pcdac_tmp;
@@ -2510,8 +2516,8 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
        s16     max_pwr_idx;
        s16     min_pwr_idx;
        s16     mid_pwr_idx = 0;
-       /* Edge flag turs on the 7nth bit on the PCDAC
-        * to delcare the higher power curve (force values
+       /* Edge flag turns on the 7nth bit on the PCDAC
+        * to declare the higher power curve (force values
         * to be greater than 64). If we only have one curve
         * we don't need to set this, if we have 2 curves and
         * fill the table backwards this can also be used to
@@ -2552,7 +2558,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
        }
 
        /* This is used when setting tx power*/
-       ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
+       ah->ah_txpower.txp_min_idx = min_pwr_idx / 2;
 
        /* Fill Power to PCDAC table backwards */
        pwr = max_pwr_idx;
@@ -2561,14 +2567,14 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
                 * edge flag and set pcdac_tmp to lower
                 * power curve.*/
                if (edge_flag == 0x40 &&
-               (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
+               (2 * pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
                        edge_flag = 0x00;
                        pcdac_tmp = pcdac_low_pwr;
-                       pwr = mid_pwr_idx/2;
+                       pwr = mid_pwr_idx / 2;
                }
 
                /* Don't go below 1, extrapolate below if we have
-                * already swithced to the lower power curve -or
+                * already switched to the lower power curve -or
                 * we only have one curve and edge_flag is zero
                 * anyway */
                if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
@@ -2596,7 +2602,7 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
 static void
 ath5k_write_pcdac_table(struct ath5k_hw *ah)
 {
-       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
+       u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
        int     i;
 
        /*
@@ -2604,8 +2610,8 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah)
         */
        for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
                ath5k_hw_reg_write(ah,
-                       (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
-                       (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
+                       (((pcdac_out[2 * i + 0] << 8 | 0xff) & 0xffff) << 0) |
+                       (((pcdac_out[2 * i + 1] << 8 | 0xff) & 0xffff) << 16),
                        AR5K_PHY_PCDAC_TXPOWER(i));
        }
 }
@@ -2789,10 +2795,10 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
         */
        for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
                ath5k_hw_reg_write(ah,
-                       ((pdadc_out[4*i + 0] & 0xff) << 0) |
-                       ((pdadc_out[4*i + 1] & 0xff) << 8) |
-                       ((pdadc_out[4*i + 2] & 0xff) << 16) |
-                       ((pdadc_out[4*i + 3] & 0xff) << 24),
+                       ((pdadc_out[4 * i + 0] & 0xff) << 0) |
+                       ((pdadc_out[4 * i + 1] & 0xff) << 8) |
+                       ((pdadc_out[4 * i + 2] & 0xff) << 16) |
+                       ((pdadc_out[4 * i + 3] & 0xff) << 24),
                        AR5K_PHY_PDADC_TXPOWER(i));
        }
 }
@@ -2805,7 +2811,7 @@ ath5k_write_pwr_to_pdadc_table(struct ath5k_hw *ah, u8 ee_mode)
 /*
  * This is the main function that uses all of the above
  * to set PCDAC/PDADC table on hw for the current channel.
- * This table is used for tx power calibration on the basband,
+ * This table is used for tx power calibration on the baseband,
  * without it we get weird tx power levels and in some cases
  * distorted spectral mask
  */
index d12b827..f5c1000 100644 (file)
@@ -72,7 +72,7 @@
 #define        AR5K_CFG_SWRD           0x00000004      /* Byte-swap RX descriptor */
 #define        AR5K_CFG_SWRB           0x00000008      /* Byte-swap RX buffer */
 #define        AR5K_CFG_SWRG           0x00000010      /* Byte-swap Register access */
-#define AR5K_CFG_IBSS          0x00000020      /* 0-BSS, 1-IBSS [5211+] */
+#define AR5K_CFG_IBSS          0x00000020      /* 0-BSS, 1-IBSS [5211+] */
 #define AR5K_CFG_PHY_OK                0x00000100      /* [5211+] */
 #define AR5K_CFG_EEBS          0x00000200      /* EEPROM is busy */
 #define        AR5K_CFG_CLKGD          0x00000400      /* Clock gated (Disable dynamic clock) */
 #define AR5K_TXCFG_SDMAMR_S            0
 #define AR5K_TXCFG_B_MODE              0x00000008      /* Set b mode for 5111 (enable 2111) */
 #define AR5K_TXCFG_TXFSTP              0x00000008      /* TX DMA full Stop [5210] */
-#define AR5K_TXCFG_TXFULL              0x000003f0      /* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL              0x000003f0      /* TX Trigger level mask */
 #define AR5K_TXCFG_TXFULL_S            4
 #define AR5K_TXCFG_TXFULL_0B           0x00000000
 #define AR5K_TXCFG_TXFULL_64B          0x00000010
  */
 #define AR5K_ISR               0x001c                  /* Register Address [5210] */
 #define AR5K_PISR              0x0080                  /* Register Address [5211+] */
-#define AR5K_ISR_RXOK          0x00000001      /* Frame successfuly received */
+#define AR5K_ISR_RXOK          0x00000001      /* Frame successfully received */
 #define AR5K_ISR_RXDESC                0x00000002      /* RX descriptor request */
 #define AR5K_ISR_RXERR         0x00000004      /* Receive error */
 #define AR5K_ISR_RXNOFRM       0x00000008      /* No frame received (receive timeout) */
 #define AR5K_ISR_RXEOL         0x00000010      /* Empty RX descriptor */
 #define AR5K_ISR_RXORN         0x00000020      /* Receive FIFO overrun */
-#define AR5K_ISR_TXOK          0x00000040      /* Frame successfuly transmited */
+#define AR5K_ISR_TXOK          0x00000040      /* Frame successfully transmitted */
 #define AR5K_ISR_TXDESC                0x00000080      /* TX descriptor request */
 #define AR5K_ISR_TXERR         0x00000100      /* Transmit error */
-#define AR5K_ISR_TXNOFRM       0x00000200      /* No frame transmited (transmit timeout) */
+#define AR5K_ISR_TXNOFRM       0x00000200      /* No frame transmitted (transmit timeout) */
 #define AR5K_ISR_TXEOL         0x00000400      /* Empty TX descriptor */
 #define AR5K_ISR_TXURN         0x00000800      /* Transmit FIFO underrun */
 #define AR5K_ISR_MIB           0x00001000      /* Update MIB counters */
 #define AR5K_ISR_BRSSI         0x00020000      /* Beacon rssi below threshold (?) */
 #define AR5K_ISR_BMISS         0x00040000      /* Beacon missed */
 #define AR5K_ISR_HIUERR                0x00080000      /* Host Interface Unit error [5211+] */
-#define AR5K_ISR_BNR           0x00100000      /* Beacon not ready [5211+] */
+#define AR5K_ISR_BNR           0x00100000      /* Beacon not ready [5211+] */
 #define AR5K_ISR_MCABT         0x00100000      /* Master Cycle Abort [5210] */
 #define AR5K_ISR_RXCHIRP       0x00200000      /* CHIRP Received [5212+] */
 #define AR5K_ISR_SSERR         0x00200000      /* Signaled System Error [5210] */
  */
 #define        AR5K_IMR                0x0020                  /* Register Address [5210] */
 #define AR5K_PIMR              0x00a0                  /* Register Address [5211+] */
-#define AR5K_IMR_RXOK          0x00000001      /* Frame successfuly received*/
+#define AR5K_IMR_RXOK          0x00000001      /* Frame successfully received*/
 #define AR5K_IMR_RXDESC                0x00000002      /* RX descriptor request*/
 #define AR5K_IMR_RXERR         0x00000004      /* Receive error*/
 #define AR5K_IMR_RXNOFRM       0x00000008      /* No frame received (receive timeout)*/
 #define AR5K_IMR_RXEOL         0x00000010      /* Empty RX descriptor*/
 #define AR5K_IMR_RXORN         0x00000020      /* Receive FIFO overrun*/
-#define AR5K_IMR_TXOK          0x00000040      /* Frame successfuly transmited*/
+#define AR5K_IMR_TXOK          0x00000040      /* Frame successfully transmitted*/
 #define AR5K_IMR_TXDESC                0x00000080      /* TX descriptor request*/
 #define AR5K_IMR_TXERR         0x00000100      /* Transmit error*/
-#define AR5K_IMR_TXNOFRM       0x00000200      /* No frame transmited (transmit timeout)*/
+#define AR5K_IMR_TXNOFRM       0x00000200      /* No frame transmitted (transmit timeout)*/
 #define AR5K_IMR_TXEOL         0x00000400      /* Empty TX descriptor*/
 #define AR5K_IMR_TXURN         0x00000800      /* Transmit FIFO underrun*/
 #define AR5K_IMR_MIB           0x00001000      /* Update MIB counters*/
 #define AR5K_IMR_BRSSI         0x00020000      /* Beacon rssi below threshold (?) */
 #define AR5K_IMR_BMISS         0x00040000      /* Beacon missed*/
 #define AR5K_IMR_HIUERR                0x00080000      /* Host Interface Unit error [5211+] */
-#define AR5K_IMR_BNR           0x00100000      /* Beacon not ready [5211+] */
+#define AR5K_IMR_BNR           0x00100000      /* Beacon not ready [5211+] */
 #define AR5K_IMR_MCABT         0x00100000      /* Master Cycle Abort [5210] */
 #define AR5K_IMR_RXCHIRP       0x00200000      /* CHIRP Received [5212+]*/
 #define AR5K_IMR_SSERR         0x00200000      /* Signaled System Error [5210] */
  * QCU misc registers
  */
 #define AR5K_QCU_MISC_BASE             0x09c0                  /* Register Address -Queue0 MISC */
-#define        AR5K_QCU_MISC_FRSHED_M          0x0000000f      /* Frame sheduling mask */
+#define        AR5K_QCU_MISC_FRSHED_M          0x0000000f      /* Frame scheduling mask */
 #define        AR5K_QCU_MISC_FRSHED_ASAP               0       /* ASAP */
 #define        AR5K_QCU_MISC_FRSHED_CBR                1       /* Constant Bit Rate */
 #define        AR5K_QCU_MISC_FRSHED_DBA_GT             2       /* DMA Beacon alert gated */
  * registers [5211+]
  *
  * These registers control the various characteristics of each queue
- * for 802.11e (WME) combatibility so they go together with
+ * for 802.11e (WME) compatibility so they go together with
  * QCU registers in pairs. For each queue we have a QCU mask register,
  * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
  * a retry limit register (0x1080 - 0x10ac), a channel time register
  * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
  * a sequence number register (0x1140 - 0x116c). It seems that "global"
- * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
+ * registers here affect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
  * We use the same macros here for easier register access.
  *
  */
  * and it's used for generating pseudo-random
  * number sequences.
  *
- * (If i understand corectly, random numbers are
+ * (If i understand correctly, random numbers are
  * used for idle sensing -multiplied with cwmin/max etc-)
  */
 #define AR5K_DCU_GBL_IFS_MISC                  0x10f0                  /* Register Address */
 #define        AR5K_PCIE_WAEN  0x407c
 
 /*
- * PCI-E Serializer/Desirializer
+ * PCI-E Serializer/Deserializer
  * registers
  */
 #define        AR5K_PCIE_SERDES        0x4080
                                        AR5K_USEC_5210 : AR5K_USEC_5211)
 #define AR5K_USEC_1                    0x0000007f      /* clock cycles for 1us */
 #define AR5K_USEC_1_S                  0
-#define AR5K_USEC_32                   0x00003f80      /* clock cycles for 1us while on 32Mhz clock */
+#define AR5K_USEC_32                   0x00003f80      /* clock cycles for 1us while on 32MHz clock */
 #define AR5K_USEC_32_S                 7
 #define AR5K_USEC_TX_LATENCY_5211      0x007fc000
 #define AR5K_USEC_TX_LATENCY_5211_S    14
 #define AR5K_RX_FILTER_5211    0x803c                  /* Register Address [5211+] */
 #define AR5K_RX_FILTER         (ah->ah_version == AR5K_AR5210 ? \
                                AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
-#define        AR5K_RX_FILTER_UCAST    0x00000001      /* Don't filter unicast frames */
-#define        AR5K_RX_FILTER_MCAST    0x00000002      /* Don't filter multicast frames */
-#define        AR5K_RX_FILTER_BCAST    0x00000004      /* Don't filter broadcast frames */
-#define        AR5K_RX_FILTER_CONTROL  0x00000008      /* Don't filter control frames */
-#define        AR5K_RX_FILTER_BEACON   0x00000010      /* Don't filter beacon frames */
-#define        AR5K_RX_FILTER_PROM     0x00000020      /* Set promiscuous mode */
-#define        AR5K_RX_FILTER_XRPOLL   0x00000040      /* Don't filter XR poll frame [5212+] */
+#define        AR5K_RX_FILTER_UCAST    0x00000001      /* Don't filter unicast frames */
+#define        AR5K_RX_FILTER_MCAST    0x00000002      /* Don't filter multicast frames */
+#define        AR5K_RX_FILTER_BCAST    0x00000004      /* Don't filter broadcast frames */
+#define        AR5K_RX_FILTER_CONTROL  0x00000008      /* Don't filter control frames */
+#define        AR5K_RX_FILTER_BEACON   0x00000010      /* Don't filter beacon frames */
+#define        AR5K_RX_FILTER_PROM     0x00000020      /* Set promiscuous mode */
+#define        AR5K_RX_FILTER_XRPOLL   0x00000040      /* Don't filter XR poll frame [5212+] */
 #define        AR5K_RX_FILTER_PROBEREQ 0x00000080      /* Don't filter probe requests [5212+] */
 #define        AR5K_RX_FILTER_PHYERR_5212      0x00000100      /* Don't filter phy errors [5212+] */
-#define        AR5K_RX_FILTER_RADARERR_5212    0x00000200      /* Don't filter phy radar errors [5212+] */
+#define        AR5K_RX_FILTER_RADARERR_5212    0x00000200      /* Don't filter phy radar errors [5212+] */
 #define AR5K_RX_FILTER_PHYERR_5211     0x00000040      /* [5211] */
 #define AR5K_RX_FILTER_RADARERR_5211   0x00000080      /* [5211] */
 #define AR5K_RX_FILTER_PHYERR  \
  * ADDAC test register [5211+]
  */
 #define AR5K_ADDAC_TEST                        0x8054                  /* Register Address */
-#define AR5K_ADDAC_TEST_TXCONT                 0x00000001      /* Test continuous tx */
+#define AR5K_ADDAC_TEST_TXCONT         0x00000001      /* Test continuous tx */
 #define AR5K_ADDAC_TEST_TST_MODE       0x00000002      /* Test mode */
 #define AR5K_ADDAC_TEST_LOOP_EN                0x00000004      /* Enable loop */
 #define AR5K_ADDAC_TEST_LOOP_LEN       0x00000008      /* Loop length (field) */
 #define AR5K_SLEEP0_NEXT_DTIM          0x0007ffff      /* Mask for next DTIM (?) */
 #define AR5K_SLEEP0_NEXT_DTIM_S                0
 #define AR5K_SLEEP0_ASSUME_DTIM                0x00080000      /* Assume DTIM */
-#define AR5K_SLEEP0_ENH_SLEEP_EN       0x00100000      /* Enable enchanced sleep control */
+#define AR5K_SLEEP0_ENH_SLEEP_EN       0x00100000      /* Enable enhanced sleep control */
 #define AR5K_SLEEP0_CABTO              0xff000000      /* Mask for CAB Time Out */
 #define AR5K_SLEEP0_CABTO_S            24
 
 /*
  * TX power control (TPC) register
  *
- * XXX: PCDAC steps (0.5dbm) or DBM ?
+ * XXX: PCDAC steps (0.5dBm) or dBm ?
  *
  */
 #define AR5K_TXPC                      0x80e8                  /* Register Address */
 /*
  * Profile count registers
  *
- * These registers can be cleared and freezed with ATH5K_MIBC, but they do not
+ * These registers can be cleared and frozen with ATH5K_MIBC, but they do not
  * generate a MIB interrupt.
  * Instead of overflowing, they shift by one bit to the right. All registers
  * shift together, i.e. when one reaches the max, all shift at the same time by
 #define AR5K_PHY_TST2_TRIG_SEL         0x00000007      /* Trigger select (?)*/
 #define AR5K_PHY_TST2_TRIG             0x00000010      /* Trigger (?) */
 #define AR5K_PHY_TST2_CBUS_MODE                0x00000060      /* Cardbus mode (?) */
-#define AR5K_PHY_TST2_CLK32            0x00000400      /* CLK_OUT is CLK32 (32Khz external) */
+#define AR5K_PHY_TST2_CLK32            0x00000400      /* CLK_OUT is CLK32 (32kHz external) */
 #define AR5K_PHY_TST2_CHANCOR_DUMP_EN  0x00000800      /* Enable Chancor dump (?) */
 #define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP        0x00001000      /* Even Chancor dump (?) */
 #define AR5K_PHY_TST2_RFSILENT_EN      0x00002000      /* Enable RFSILENT */
 #define        AR5K_PHY_AGCCTL_OFDM_DIV_DIS    0x00000008      /* Disable antenna diversity on OFDM modes */
 #define        AR5K_PHY_AGCCTL_NF_EN           0x00008000      /* Enable nf calibration to happen (?) */
 #define        AR5K_PHY_AGCTL_FLTR_CAL         0x00010000      /* Allow filter calibration (?) */
-#define        AR5K_PHY_AGCCTL_NF_NOUPDATE     0x00020000      /* Don't update nf automaticaly */
+#define        AR5K_PHY_AGCCTL_NF_NOUPDATE     0x00020000      /* Don't update nf automatically */
 
 /*
  * PHY noise floor status register (CCA = Clear Channel Assessment)
 #define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S       24
 
 /* Low thresholds */
-#define AR5K_PHY_WEAK_OFDM_LOW_THR             0x986c
+#define AR5K_PHY_WEAK_OFDM_LOW_THR             0x986c
 #define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN  0x00000001
 #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT    0x00003f00
 #define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S  8
  *
  * It's obvious from the code that 0x989c is the buffer register but
  * for the other special registers that we write to after sending each
- * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
+ * packet, i have no idea. So I'll name them BUFFER_CONTROL_X registers
  * for now. It's interesting that they are also used for some other operations.
  */
 
 #define        AR5K_PHY_FRAME_CTL_ILLLEN_ERR   0x08000000      /* Illegal length */
 #define        AR5K_PHY_FRAME_CTL_SERVICE_ERR  0x20000000
 #define        AR5K_PHY_FRAME_CTL_TXURN_ERR    0x40000000      /* TX underrun */
-#define AR5K_PHY_FRAME_CTL_INI         AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
-                       AR5K_PHY_FRAME_CTL_TXURN_ERR | \
-                       AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
-                       AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
-                       AR5K_PHY_FRAME_CTL_PARITY_ERR | \
-                       AR5K_PHY_FRAME_CTL_TIMING_ERR
+#define AR5K_PHY_FRAME_CTL_INI \
+                       (AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
+                        AR5K_PHY_FRAME_CTL_TXURN_ERR | \
+                        AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
+                        AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
+                        AR5K_PHY_FRAME_CTL_PARITY_ERR | \
+                        AR5K_PHY_FRAME_CTL_TIMING_ERR)
 
 /*
  * PHY Tx Power adjustment register [5212A+]
 #define        AR5K_PHY_RADAR                  0x9954
 #define        AR5K_PHY_RADAR_ENABLE           0x00000001
 #define        AR5K_PHY_RADAR_DISABLE          0x00000000
-#define AR5K_PHY_RADAR_INBANDTHR       0x0000003e      /* Inband threshold
+#define AR5K_PHY_RADAR_INBANDTHR       0x0000003e      /* Inband threshold
                                                        5-bits, units unknown {0..31}
                                                        (? MHz ?) */
 #define AR5K_PHY_RADAR_INBANDTHR_S     1
 
-#define AR5K_PHY_RADAR_PRSSI_THR       0x00000fc0      /* Pulse RSSI/SNR threshold
+#define AR5K_PHY_RADAR_PRSSI_THR       0x00000fc0      /* Pulse RSSI/SNR threshold
                                                        6-bits, dBm range {0..63}
                                                        in dBm units. */
 #define AR5K_PHY_RADAR_PRSSI_THR_S     6
 
-#define AR5K_PHY_RADAR_PHEIGHT_THR     0x0003f000      /* Pulse height threshold
+#define AR5K_PHY_RADAR_PHEIGHT_THR     0x0003f000      /* Pulse height threshold
                                                        6-bits, dBm range {0..63}
                                                        in dBm units. */
 #define AR5K_PHY_RADAR_PHEIGHT_THR_S   12
 
-#define AR5K_PHY_RADAR_RSSI_THR        0x00fc0000      /* Radar RSSI/SNR threshold.
+#define AR5K_PHY_RADAR_RSSI_THR                0x00fc0000      /* Radar RSSI/SNR threshold.
                                                        6-bits, dBm range {0..63}
                                                        in dBm units. */
 #define AR5K_PHY_RADAR_RSSI_THR_S      18
 #define AR5K_PHY_RESTART_DIV_GC_S      18
 
 /*
- * RF Bus access request register (for synth-oly channel switching)
+ * RF Bus access request register (for synth-only channel switching)
  */
 #define AR5K_PHY_RFBUS_REQ             0x997C
 #define AR5K_PHY_RFBUS_REQ_REQUEST     0x00000001
  */
 #define        AR5K_BB_GAIN_BASE               0x9b00  /* BaseBand Amplifier Gain table base address */
 #define AR5K_BB_GAIN(_n)               (AR5K_BB_GAIN_BASE + ((_n) << 2))
-#define        AR5K_RF_GAIN_BASE               0x9a00  /* RF Amplrifier Gain table base address */
+#define        AR5K_RF_GAIN_BASE               0x9a00  /* RF Amplifier Gain table base address */
 #define AR5K_RF_GAIN(_n)               (AR5K_RF_GAIN_BASE + ((_n) << 2))
 
 /*
index 1676a3e..9f9c2ad 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <asm/unaligned.h>
 
-#include <linux/pci.h>                 /* To determine if a card is pci-e */
+#include <linux/pci.h>         /* To determine if a card is pci-e */
 #include <linux/log2.h>
 #include <linux/platform_device.h>
 #include "ath5k.h"
@@ -142,10 +142,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 
        /* Set 32MHz USEC counter */
        if ((ah->ah_radio == AR5K_RF5112) ||
-               (ah->ah_radio == AR5K_RF5413) ||
-               (ah->ah_radio == AR5K_RF2316) ||
-               (ah->ah_radio == AR5K_RF2317))
-       /* Remain on 40MHz clock ? */
+           (ah->ah_radio == AR5K_RF2413) ||
+           (ah->ah_radio == AR5K_RF5413) ||
+           (ah->ah_radio == AR5K_RF2316) ||
+           (ah->ah_radio == AR5K_RF2317))
+               /* Remain on 40MHz clock ? */
                sclock = 40 - 1;
        else
                sclock = 32 - 1;
@@ -213,7 +214,7 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
        usec_reg = (usec | sclock | txlat | rxlat);
        ath5k_hw_reg_write(ah, usec_reg, AR5K_USEC);
 
-       /* On 5112 set tx frane to tx data start delay */
+       /* On 5112 set tx frame to tx data start delay */
        if (ah->ah_radio == AR5K_RF5112) {
                AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL2,
                                        AR5K_PHY_RF_CTL2_TXF2TXD_START,
@@ -233,7 +234,7 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 {
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-       u32 scal, spending;
+       u32 scal, spending, sclock;
 
        /* Only set 32KHz settings if we have an external
         * 32KHz crystal present */
@@ -317,6 +318,15 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 
                /* Set up tsf increment on each cycle */
                AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+                       (ah->ah_radio == AR5K_RF5413) ||
+                       (ah->ah_radio == AR5K_RF2316) ||
+                       (ah->ah_radio == AR5K_RF2317))
+                       sclock = 40 - 1;
+               else
+                       sclock = 32 - 1;
+               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, sclock);
        }
 }
 
@@ -375,7 +385,7 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
 static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
 {
        u32 mask = flags ? flags : ~0U;
-       volatile __iomem u32 *reg;
+       u32 __iomem *reg;
        u32 regval;
        u32 val = 0;
 
@@ -539,7 +549,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
         *
         * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
-        * we ingore that flag for PCI-E cards. On PCI cards
+        * we ignore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
         */
        bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
@@ -596,7 +606,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
         *
         * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
-        * we ingore that flag for PCI-E cards. On PCI cards
+        * we ignore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
         */
        bus_flags = (pdev && pci_is_pcie(pdev)) ? 0 : AR5K_RESET_CTL_PCI;
@@ -627,7 +637,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                return ret;
        }
 
-       /* ...reset configuration regiter on Wisoc ...
+       /* ...reset configuration register on Wisoc ...
         * ...clear reset control register and pull device out of
         * warm reset on others */
        if (ath5k_get_bus_type(ah) == ATH_AHB)
@@ -704,7 +714,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 
                /*XXX: Can bwmode be used with dynamic mode ?
                 * (I don't think it supports 44MHz) */
-               /* On 2425 initvals TURBO_SHORT is not pressent */
+               /* On 2425 initvals TURBO_SHORT is not present */
                if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
                        turbo = AR5K_PHY_TURBO_MODE |
                                (ah->ah_radio == AR5K_RF2425) ? 0 :
@@ -1277,11 +1287,16 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        ath5k_hw_dma_init(ah);
 
 
-       /* Enable 32KHz clock function for AR5212+ chips
+       /*
+        * Enable 32KHz clock function for AR5212+ chips
         * Set clocks to 32KHz operation and use an
         * external 32KHz crystal when sleeping if one
-        * exists */
-       if (ah->ah_version == AR5K_AR5212 &&
+        * exists.
+        * Disabled by default because it is also disabled in
+        * other drivers and it is known to cause stability
+        * issues on some devices
+        */
+       if (ah->ah_use_32khz_clock && ah->ah_version == AR5K_AR5212 &&
            op_mode != NL80211_IFTYPE_AP)
                ath5k_hw_set_sleep_clock(ah, true);
 
index 16b67e8..5d11c23 100644 (file)
@@ -254,7 +254,7 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
 
 /* RFX112 (Derby 1) */
 
-/* BANK 6                              len  pos col */
+/* BANK 6                              len  pos col */
 #define        AR5K_RF5112_OB_2GHZ             { 3, 269, 0 }
 #define        AR5K_RF5112_DB_2GHZ             { 3, 272, 0 }
 
@@ -495,7 +495,7 @@ static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
 /* BANK 2                              len  pos col */
 #define AR5K_RF2413_RF_TURBO           { 1, 1,   2 }
 
-/* BANK 6                              len  pos col */
+/* BANK 6                              len  pos col */
 #define        AR5K_RF2413_OB_2GHZ             { 3, 168, 0 }
 #define        AR5K_RF2413_DB_2GHZ             { 3, 165, 0 }
 
index 1354d8c..ebfae05 100644 (file)
@@ -30,7 +30,7 @@ struct ath5k_ini_rfgain {
 
 /* Initial RF Gain settings for RF5111 */
 static const struct ath5k_ini_rfgain rfgain_5111[] = {
-       /*                            5Ghz      2Ghz    */
+       /*                            5GHz      2GHz    */
        { AR5K_RF_GAIN(0),      { 0x000001a9, 0x00000000 } },
        { AR5K_RF_GAIN(1),      { 0x000001e9, 0x00000040 } },
        { AR5K_RF_GAIN(2),      { 0x00000029, 0x00000080 } },
@@ -99,7 +99,7 @@ static const struct ath5k_ini_rfgain rfgain_5111[] = {
 
 /* Initial RF Gain settings for RF5112 */
 static const struct ath5k_ini_rfgain rfgain_5112[] = {
-       /*                            5Ghz      2Ghz    */
+       /*                            5GHz      2GHz    */
        { AR5K_RF_GAIN(0),      { 0x00000007, 0x00000007 } },
        { AR5K_RF_GAIN(1),      { 0x00000047, 0x00000047 } },
        { AR5K_RF_GAIN(2),      { 0x00000087, 0x00000087 } },
@@ -305,7 +305,7 @@ static const struct ath5k_ini_rfgain rfgain_2316[] = {
 
 /* Initial RF Gain settings for RF5413 */
 static const struct ath5k_ini_rfgain rfgain_5413[] = {
-       /*                            5Ghz      2Ghz    */
+       /*                            5GHz      2GHz    */
        { AR5K_RF_GAIN(0),      { 0x00000000, 0x00000000 } },
        { AR5K_RF_GAIN(1),      { 0x00000040, 0x00000040 } },
        { AR5K_RF_GAIN(2),      { 0x00000080, 0x00000080 } },
@@ -452,7 +452,7 @@ static const struct ath5k_ini_rfgain rfgain_2425[] = {
 
 /* Check if our current measurement is inside our
  * current variable attenuation window */
-#define AR5K_GAIN_CHECK_ADJUST(_g)             \
+#define AR5K_GAIN_CHECK_ADJUST(_g)             \
        ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
 
 struct ath5k_gain_opt_step {
index a073cdc..d8ad0e4 100644 (file)
@@ -12,7 +12,7 @@ static ssize_t ath5k_attr_show_##name(struct device *dev,             \
 {                                                                      \
        struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
        struct ath5k_softc *sc = hw->priv;                              \
-       return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
+       return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
 }                                                                      \
                                                                        \
 static ssize_t ath5k_attr_store_##name(struct device *dev,             \
@@ -21,9 +21,11 @@ static ssize_t ath5k_attr_store_##name(struct device *dev,           \
 {                                                                      \
        struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
        struct ath5k_softc *sc = hw->priv;                              \
-       int val;                                                        \
+       int val, ret;                                                   \
                                                                        \
-       val = (int)simple_strtoul(buf, NULL, 10);                       \
+       ret = kstrtoint(buf, 10, &val);                                 \
+       if (ret < 0)                                                    \
+               return ret;                                             \
        set(sc->ah, val);                                               \
        return count;                                                   \
 }                                                                      \
@@ -37,7 +39,7 @@ static ssize_t ath5k_attr_show_##name(struct device *dev,             \
 {                                                                      \
        struct ieee80211_hw *hw = dev_get_drvdata(dev);                 \
        struct ath5k_softc *sc = hw->priv;                              \
-       return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
+       return snprintf(buf, PAGE_SIZE, "%d\n", get);                   \
 }                                                                      \
 static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
 
index 2de68ad..235e076 100644 (file)
@@ -12,9 +12,6 @@ static inline void trace_ ## name(proto) {}
 
 struct sk_buff;
 
-#define PRIV_ENTRY  __field(struct ath5k_softc *, priv)
-#define PRIV_ASSIGN __entry->priv = priv
-
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM ath5k
 
@@ -22,12 +19,12 @@ TRACE_EVENT(ath5k_rx,
        TP_PROTO(struct ath5k_softc *priv, struct sk_buff *skb),
        TP_ARGS(priv, skb),
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               __field(struct ath5k_softc *, priv)
                __field(unsigned long, skbaddr)
                __dynamic_array(u8, frame, skb->len)
        ),
        TP_fast_assign(
-               PRIV_ASSIGN;
+               __entry->priv = priv;
                __entry->skbaddr = (unsigned long) skb;
                memcpy(__get_dynamic_array(frame), skb->data, skb->len);
        ),
@@ -43,14 +40,14 @@ TRACE_EVENT(ath5k_tx,
        TP_ARGS(priv, skb, q),
 
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               __field(struct ath5k_softc *, priv)
                __field(unsigned long, skbaddr)
                __field(u8, qnum)
                __dynamic_array(u8, frame, skb->len)
        ),
 
        TP_fast_assign(
-               PRIV_ASSIGN;
+               __entry->priv = priv;
                __entry->skbaddr = (unsigned long) skb;
                __entry->qnum = (u8) q->qnum;
                memcpy(__get_dynamic_array(frame), skb->data, skb->len);
@@ -69,7 +66,7 @@ TRACE_EVENT(ath5k_tx_complete,
        TP_ARGS(priv, skb, q, ts),
 
        TP_STRUCT__entry(
-               PRIV_ENTRY
+               __field(struct ath5k_softc *, priv)
                __field(unsigned long, skbaddr)
                __field(u8, qnum)
                __field(u8, ts_status)
@@ -78,7 +75,7 @@ TRACE_EVENT(ath5k_tx_complete,
        ),
 
        TP_fast_assign(
-               PRIV_ASSIGN;
+               __entry->priv = priv;
                __entry->skbaddr = (unsigned long) skb;
                __entry->qnum = (u8) q->qnum;
                __entry->ts_status = ts->ts_status;
index 441bb33..fac2c6d 100644 (file)
@@ -627,6 +627,11 @@ static void ar5008_hw_init_bb(struct ath_hw *ah,
        else
                synthDelay /= 10;
 
+       if (IS_CHAN_HALF_RATE(chan))
+               synthDelay *= 2;
+       else if (IS_CHAN_QUARTER_RATE(chan))
+               synthDelay *= 4;
+
        REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
 
        udelay(synthDelay + BASE_ACTIVATE_DELAY);
index f344cc2..9ff7c30 100644 (file)
@@ -499,45 +499,6 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
        }
 }
 
-/*
- * If Async FIFO is enabled, the following counters change as MAC now runs
- * at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
- *
- * The values below tested for ht40 2 chain.
- * Overwrite the delay/timeouts initialized in process ini.
- */
-void ar9002_hw_update_async_fifo(struct ath_hw *ah)
-{
-       if (AR_SREV_9287_13_OR_LATER(ah)) {
-               REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
-                         AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
-                         AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
-                         AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
-
-               REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
-
-               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
-                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
-               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
-                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
-       }
-}
-
-/*
- * We don't enable WEP aggregation on mac80211 but we keep this
- * around for HAL unification purposes.
- */
-void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
-{
-       if (AR_SREV_9287_13_OR_LATER(ah)) {
-               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
-                           AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
-       }
-}
-
 /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
 void ar9002_hw_attach_ops(struct ath_hw *ah)
 {
index 2fe0a34..3cbbb03 100644 (file)
@@ -111,7 +111,9 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
 
                switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
                case 0:
-                       if ((freq % 20) == 0)
+                       if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
+                               aModeRefSel = 0;
+                       else if ((freq % 20) == 0)
                                aModeRefSel = 3;
                        else if ((freq % 10) == 0)
                                aModeRefSel = 2;
@@ -129,8 +131,9 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                        channelSel = CHANSEL_5G(freq);
 
                        /* RefDivA setting */
-                       REG_RMW_FIELD(ah, AR_AN_SYNTH9,
-                                     AR_AN_SYNTH9_REFDIVA, refDivA);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_SYNTH9,
+                                     AR_AN_SYNTH9_REFDIVA,
+                                     AR_AN_SYNTH9_REFDIVA_S, refDivA);
 
                }
 
@@ -447,26 +450,27 @@ static void ar9002_olc_init(struct ath_hw *ah)
 static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
                                         struct ath9k_channel *chan)
 {
+       int ref_div = 5;
+       int pll_div = 0x2c;
        u32 pll;
 
-       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+       if (chan && IS_CHAN_5GHZ(chan) && !IS_CHAN_A_FAST_CLOCK(ah, chan)) {
+               if (AR_SREV_9280_20(ah)) {
+                       ref_div = 10;
+                       pll_div = 0x50;
+               } else {
+                       pll_div = 0x28;
+               }
+       }
+
+       pll = SM(ref_div, AR_RTC_9160_PLL_REFDIV);
+       pll |= SM(pll_div, AR_RTC_9160_PLL_DIV);
 
        if (chan && IS_CHAN_HALF_RATE(chan))
                pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
        else if (chan && IS_CHAN_QUARTER_RATE(chan))
                pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
 
-       if (chan && IS_CHAN_5GHZ(chan)) {
-               if (IS_CHAN_A_FAST_CLOCK(ah, chan))
-                       pll = 0x142c;
-               else if (AR_SREV_9280_20(ah))
-                       pll = 0x2850;
-               else
-                       pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
-       } else {
-               pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
-       }
-
        return pll;
 }
 
index e8ac70d..2339728 100644 (file)
@@ -653,8 +653,8 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = {
        {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
        {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
        {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
-       {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
-       {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
+       {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
        {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
@@ -761,7 +761,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x0000a3ec, 0x20202020},
        {0x0000a3f0, 0x00000000},
        {0x0000a3f4, 0x00000246},
-       {0x0000a3f8, 0x0cdbd380},
+       {0x0000a3f8, 0x0c9bd380},
        {0x0000a3fc, 0x000f0f01},
        {0x0000a400, 0x8fa91f01},
        {0x0000a404, 0x00000000},
@@ -780,7 +780,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
        {0x0000a43c, 0x00100000},
        {0x0000a440, 0x00000000},
        {0x0000a444, 0x00000000},
-       {0x0000a448, 0x06000080},
+       {0x0000a448, 0x05000080},
        {0x0000a44c, 0x00000001},
        {0x0000a450, 0x00010000},
        {0x0000a458, 0x00000000},
@@ -1500,8 +1500,6 @@ static const u32 ar9300_2p2_mac_core[][2] = {
        {0x0000816c, 0x00000000},
        {0x000081c0, 0x00000000},
        {0x000081c4, 0x33332210},
-       {0x000081c8, 0x00000000},
-       {0x000081cc, 0x00000000},
        {0x000081ec, 0x00000000},
        {0x000081f0, 0x00000000},
        {0x000081f4, 0x00000000},
index 575e185..8ff0b88 100644 (file)
@@ -625,8 +625,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
                        rxs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (rxsp->status11 & AR_MichaelErr)
                        rxs->rs_status |= ATH9K_RXERR_MIC;
-
-               if (rxsp->status11 & AR_KeyMiss)
+               else if (rxsp->status11 & AR_KeyMiss)
                        rxs->rs_status |= ATH9K_RXERR_DECRYPT;
        }
 
index de19723..f80d1d6 100644 (file)
@@ -21,6 +21,36 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val)
 {
        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
        struct ath9k_channel *chan = ah->curchan;
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       /*
+        * 3 bits for modalHeader5G.papdRateMaskHt20
+        * is used for sub-band disabling of PAPRD.
+        * 5G band is divided into 3 sub-bands -- upper,
+        * middle, lower.
+        * if bit 30 of modalHeader5G.papdRateMaskHt20 is set
+        * -- disable PAPRD for upper band 5GHz
+        * if bit 29 of modalHeader5G.papdRateMaskHt20 is set
+        * -- disable PAPRD for middle band 5GHz
+        * if bit 28 of modalHeader5G.papdRateMaskHt20 is set
+        * -- disable PAPRD for lower band 5GHz
+        */
+
+       if (IS_CHAN_5GHZ(chan)) {
+               if (chan->channel >= UPPER_5G_SUB_BAND_START) {
+                       if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20)
+                                                                 & BIT(30))
+                               val = false;
+               } else if (chan->channel >= MID_5G_SUB_BAND_START) {
+                       if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20)
+                                                                 & BIT(29))
+                               val = false;
+               } else {
+                       if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20)
+                                                                 & BIT(28))
+                               val = false;
+               }
+       }
 
        if (val) {
                ah->paprd_table_write_done = true;
index 61e6d39..3bea7ea 100644 (file)
@@ -754,6 +754,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
                IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_PS_NULLFUNC_STACK |
+               IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
 
        hw->wiphy->interface_modes =
index 7b77968..7212acb 100644 (file)
@@ -1294,11 +1294,16 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
        u32 rfilt;
 
        mutex_lock(&priv->mutex);
-       ath9k_htc_ps_wakeup(priv);
-
        changed_flags &= SUPPORTED_FILTERS;
        *total_flags &= SUPPORTED_FILTERS;
 
+       if (priv->op_flags & OP_INVALID) {
+               ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY,
+                       "Unable to configure filter on invalid state\n");
+               return;
+       }
+       ath9k_htc_ps_wakeup(priv);
+
        priv->rxfilter = *total_flags;
        rfilt = ath9k_htc_calcrxfilter(priv);
        ath9k_hw_setrxfilter(priv->ah, rfilt);
index 07827b5..2a5f908 100644 (file)
@@ -87,7 +87,10 @@ static void ath9k_hw_set_clockrate(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        unsigned int clockrate;
 
-       if (!ah->curchan) /* should really check for CCK instead */
+       /* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */
+       if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah))
+               clockrate = 117;
+       else if (!ah->curchan) /* should really check for CCK instead */
                clockrate = ATH9K_CLOCK_RATE_CCK;
        else if (conf->channel->band == IEEE80211_BAND_2GHZ)
                clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
@@ -99,6 +102,13 @@ static void ath9k_hw_set_clockrate(struct ath_hw *ah)
        if (conf_is_ht40(conf))
                clockrate *= 2;
 
+       if (ah->curchan) {
+               if (IS_CHAN_HALF_RATE(ah->curchan))
+                       clockrate /= 2;
+               if (IS_CHAN_QUARTER_RATE(ah->curchan))
+                       clockrate /= 4;
+       }
+
        common->clockrate = clockrate;
 }
 
@@ -895,6 +905,13 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
        }
 }
 
+static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us)
+{
+       u32 val = ath9k_hw_mac_to_clks(ah, us - 2);
+       val = min(val, (u32) 0xFFFF);
+       REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val);
+}
+
 static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
 {
        u32 val = ath9k_hw_mac_to_clks(ah, us);
@@ -932,25 +949,60 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
 
 void ath9k_hw_init_global_settings(struct ath_hw *ah)
 {
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_conf *conf = &common->hw->conf;
+       const struct ath9k_channel *chan = ah->curchan;
        int acktimeout;
        int slottime;
        int sifstime;
+       int rx_lat = 0, tx_lat = 0, eifs = 0;
+       u32 reg;
 
        ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
                ah->misc_mode);
 
+       if (!chan)
+               return;
+
        if (ah->misc_mode != 0)
                REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
 
-       if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
-               sifstime = 16;
-       else
-               sifstime = 10;
+       rx_lat = 37;
+       tx_lat = 54;
+
+       if (IS_CHAN_HALF_RATE(chan)) {
+               eifs = 175;
+               rx_lat *= 2;
+               tx_lat *= 2;
+               if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+                   tx_lat += 11;
+
+               slottime = 13;
+               sifstime = 32;
+       } else if (IS_CHAN_QUARTER_RATE(chan)) {
+               eifs = 340;
+               rx_lat *= 4;
+               tx_lat *= 4;
+               if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+                   tx_lat += 22;
+
+               slottime = 21;
+               sifstime = 64;
+       } else {
+               eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS);
+               reg = REG_READ(ah, AR_USEC);
+               rx_lat = MS(reg, AR_USEC_RX_LAT);
+               tx_lat = MS(reg, AR_USEC_TX_LAT);
+
+               slottime = ah->slottime;
+               if (IS_CHAN_5GHZ(chan))
+                       sifstime = 16;
+               else
+                       sifstime = 10;
+       }
 
        /* As defined by IEEE 802.11-2007 17.3.8.6 */
-       slottime = ah->slottime + 3 * ah->coverage_class;
-       acktimeout = slottime + sifstime;
+       acktimeout = slottime + sifstime + 3 * ah->coverage_class;
 
        /*
         * Workaround for early ACK timeouts, add an offset to match the
@@ -962,11 +1014,20 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
        if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ)
                acktimeout += 64 - sifstime - ah->slottime;
 
-       ath9k_hw_setslottime(ah, ah->slottime);
+       ath9k_hw_set_sifs_time(ah, sifstime);
+       ath9k_hw_setslottime(ah, slottime);
        ath9k_hw_set_ack_timeout(ah, acktimeout);
        ath9k_hw_set_cts_timeout(ah, acktimeout);
        if (ah->globaltxtimeout != (u32) -1)
                ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
+
+       REG_WRITE(ah, AR_D_GBL_IFS_EIFS, ath9k_hw_mac_to_clks(ah, eifs));
+       REG_RMW(ah, AR_USEC,
+               (common->clockrate - 1) |
+               SM(rx_lat, AR_USEC_RX_LAT) |
+               SM(tx_lat, AR_USEC_TX_LAT),
+               AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC);
+
 }
 EXPORT_SYMBOL(ath9k_hw_init_global_settings);
 
@@ -1570,9 +1631,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_global_settings(ah);
 
-       if (!AR_SREV_9300_20_OR_LATER(ah)) {
-               ar9002_hw_update_async_fifo(ah);
-               ar9002_hw_enable_wep_aggregation(ah);
+       if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
+               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                           AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
        }
 
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
@@ -2079,10 +2144,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
        } else {
                pCap->tx_desc_len = sizeof(struct ath_desc);
-               if (AR_SREV_9280_20(ah) &&
-                   ((ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) <=
-                     AR5416_EEP_MINOR_VER_16) ||
-                    ah->eep_ops->get_eeprom(ah, EEP_FSTCLK_5G)))
+               if (AR_SREV_9280_20(ah))
                        pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK;
        }
 
index 818acdd..6acd0f9 100644 (file)
 #define AR_KEYTABLE_SIZE            128
 #define POWER_UP_TIME               10000
 #define SPUR_RSSI_THRESH            40
+#define UPPER_5G_SUB_BAND_START                5700
+#define MID_5G_SUB_BAND_START          5400
 
 #define CAB_TIMEOUT_VAL             10
 #define BEACON_TIMEOUT_VAL          10
@@ -983,8 +985,6 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
 void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
 int ar9002_hw_rf_claim(struct ath_hw *ah);
 void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
-void ar9002_hw_update_async_fifo(struct ath_hw *ah);
-void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
 
 /*
  * Code specific to AR9003, we stuff these here to avoid callbacks
index c2091f1..b6b523a 100644 (file)
@@ -645,8 +645,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (ads.ds_rxstatus8 & AR_MichaelErr)
                        rs->rs_status |= ATH9K_RXERR_MIC;
-
-               if (ads.ds_rxstatus8 & AR_KeyMiss)
+               else if (ads.ds_rxstatus8 & AR_KeyMiss)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
        }
 
index e7fe4d9..c04a6c3 100644 (file)
@@ -379,7 +379,30 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
 };
 
 static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
-                               struct ieee80211_tx_rate *rate);
+                               struct ieee80211_tx_rate *rate)
+{
+       int rix = 0, i = 0;
+       static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
+
+       if (!(rate->flags & IEEE80211_TX_RC_MCS))
+               return rate->idx;
+
+       while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
+               rix++; i++;
+       }
+
+       rix += rate->idx + rate_table->mcs_start;
+
+       if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
+           (rate->flags & IEEE80211_TX_RC_SHORT_GI))
+               rix = rate_table->info[rix].ht_index;
+       else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+               rix = rate_table->info[rix].sgi_index;
+       else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+               rix = rate_table->info[rix].cw40index;
+
+       return rix;
+}
 
 static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
                                   struct ath_rate_priv *ath_rc_priv)
@@ -1080,31 +1103,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 
 }
 
-static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
-                               struct ieee80211_tx_rate *rate)
-{
-       int rix = 0, i = 0;
-       static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
-
-       if (!(rate->flags & IEEE80211_TX_RC_MCS))
-               return rate->idx;
-
-       while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
-               rix++; i++;
-       }
-
-       rix += rate->idx + rate_table->mcs_start;
-
-       if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
-           (rate->flags & IEEE80211_TX_RC_SHORT_GI))
-               rix = rate_table->info[rix].ht_index;
-       else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-               rix = rate_table->info[rix].sgi_index;
-       else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-               rix = rate_table->info[rix].cw40index;
-
-       return rix;
-}
 
 static void ath_rc_tx_status(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
index a483388..759b72c 100644 (file)
 
 #define AR_D_GBL_IFS_SIFS         0x1030
 #define AR_D_GBL_IFS_SIFS_M       0x0000FFFF
-#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
 #define AR_D_GBL_IFS_SIFS_RESV0   0xFFFFFFFF
 
 #define AR_D_TXBLK_BASE            0x1038
 #define AR_D_GBL_IFS_SLOT         0x1070
 #define AR_D_GBL_IFS_SLOT_M       0x0000FFFF
 #define AR_D_GBL_IFS_SLOT_RESV0   0xFFFF0000
-#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR   0x00000420
 
 #define AR_D_GBL_IFS_EIFS         0x10b0
 #define AR_D_GBL_IFS_EIFS_M       0x0000FFFF
 #define AR_D_GBL_IFS_EIFS_RESV0   0xFFFF0000
-#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR   0x0000A5EB
 
 #define AR_D_GBL_IFS_MISC        0x10f0
 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL        0x00000007
@@ -1477,7 +1474,6 @@ enum {
 #define AR_TIME_OUT_ACK_S    0
 #define AR_TIME_OUT_CTS      0x3FFF0000
 #define AR_TIME_OUT_CTS_S    16
-#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR    0x16001D56
 
 #define AR_RSSI_THR          0x8018
 #define AR_RSSI_THR_MASK     0x000000FF
@@ -1493,7 +1489,6 @@ enum {
 #define AR_USEC_TX_LAT_S     14
 #define AR_USEC_RX_LAT       0x1F800000
 #define AR_USEC_RX_LAT_S     23
-#define AR_USEC_ASYNC_FIFO_DUR    0x12e00074
 
 #define AR_RESET_TSF        0x8020
 #define AR_RESET_TSF_ONCE   0x01000000
index d2b9f12..a61cf67 100644 (file)
@@ -1484,6 +1484,13 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw,
        }
 }
 
+static bool carl9170_tx_frames_pending(struct ieee80211_hw *hw)
+{
+       struct ar9170 *ar = hw->priv;
+
+       return !!atomic_read(&ar->tx_total_queued);
+}
+
 static const struct ieee80211_ops carl9170_ops = {
        .start                  = carl9170_op_start,
        .stop                   = carl9170_op_stop,
@@ -1504,6 +1511,7 @@ static const struct ieee80211_ops carl9170_ops = {
        .get_survey             = carl9170_op_get_survey,
        .get_stats              = carl9170_op_get_stats,
        .ampdu_action           = carl9170_op_ampdu_action,
+       .tx_frames_pending      = carl9170_tx_frames_pending,
 };
 
 void *carl9170_alloc(size_t priv_size)
index d5add69..d2293dc 100644 (file)
@@ -90,6 +90,12 @@ config B43_SDIO
 
 #Data transfers to the device via PIO. We want it as a fallback even
 # if we can do DMA.
+config B43_BCMA_PIO
+       bool
+       depends on B43_BCMA
+       select BCMA_BLOCKIO
+       default y
+
 config B43_PIO
        bool
        depends on B43
@@ -125,6 +131,14 @@ config B43_PHY_HT
 
          Say N, this is BROKEN and crashes driver.
 
+config B43_PHY_LCN
+       bool "Support for LCN-PHY devices (BROKEN)"
+       depends on B43 && BROKEN
+       ---help---
+         Support for the LCN-PHY.
+
+         Say N, this is BROKEN and crashes driver.
+
 # This config option automatically enables b43 LEDS support,
 # if it's possible.
 config B43_LEDS
index 1b25604..4648bbf 100644 (file)
@@ -13,6 +13,7 @@ b43-$(CONFIG_B43_PHY_LP)      += tables_lpphy.o
 b43-$(CONFIG_B43_PHY_HT)       += phy_ht.o
 b43-$(CONFIG_B43_PHY_HT)       += tables_phy_ht.o
 b43-$(CONFIG_B43_PHY_HT)       += radio_2059.o
+b43-$(CONFIG_B43_PHY_LCN)      += phy_lcn.o tables_phy_lcn.o
 b43-y                          += sysfs.o
 b43-y                          += xmit.o
 b43-y                          += lo.o
index 666515e..08a2827 100644 (file)
@@ -726,7 +726,6 @@ enum {
 
 /* Data structure for one wireless device (802.11 core) */
 struct b43_wldev {
-       struct ssb_device *sdev; /* TODO: remove when b43_bus_dev is ready */
        struct b43_bus_dev *dev;
        struct b43_wl *wl;
 
index 4200713..a5e61a9 100644 (file)
 #include "b43.h"
 #include "bus.h"
 
+/* BCMA */
+#ifdef CONFIG_B43_BCMA
+static int b43_bus_bcma_bus_may_powerdown(struct b43_bus_dev *dev)
+{
+       return 0; /* bcma_bus_may_powerdown(dev->bdev->bus); */
+}
+static int b43_bus_bcma_bus_powerup(struct b43_bus_dev *dev,
+                                         bool dynamic_pctl)
+{
+       return 0; /* bcma_bus_powerup(dev->sdev->bus, dynamic_pctl); */
+}
+static int b43_bus_bcma_device_is_enabled(struct b43_bus_dev *dev)
+{
+       return bcma_core_is_enabled(dev->bdev);
+}
+static void b43_bus_bcma_device_enable(struct b43_bus_dev *dev,
+                                            u32 core_specific_flags)
+{
+       bcma_core_enable(dev->bdev, core_specific_flags);
+}
+static void b43_bus_bcma_device_disable(struct b43_bus_dev *dev,
+                                             u32 core_specific_flags)
+{
+       bcma_core_disable(dev->bdev, core_specific_flags);
+}
+static u16 b43_bus_bcma_read16(struct b43_bus_dev *dev, u16 offset)
+{
+       return bcma_read16(dev->bdev, offset);
+}
+static u32 b43_bus_bcma_read32(struct b43_bus_dev *dev, u16 offset)
+{
+       return bcma_read32(dev->bdev, offset);
+}
+static
+void b43_bus_bcma_write16(struct b43_bus_dev *dev, u16 offset, u16 value)
+{
+       bcma_write16(dev->bdev, offset, value);
+}
+static
+void b43_bus_bcma_write32(struct b43_bus_dev *dev, u16 offset, u32 value)
+{
+       bcma_write32(dev->bdev, offset, value);
+}
+static
+void b43_bus_bcma_block_read(struct b43_bus_dev *dev, void *buffer,
+                            size_t count, u16 offset, u8 reg_width)
+{
+       bcma_block_read(dev->bdev, buffer, count, offset, reg_width);
+}
+static
+void b43_bus_bcma_block_write(struct b43_bus_dev *dev, const void *buffer,
+                             size_t count, u16 offset, u8 reg_width)
+{
+       bcma_block_write(dev->bdev, buffer, count, offset, reg_width);
+}
+
+struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
+{
+       struct b43_bus_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       dev->bus_type = B43_BUS_BCMA;
+       dev->bdev = core;
+
+       dev->bus_may_powerdown = b43_bus_bcma_bus_may_powerdown;
+       dev->bus_powerup = b43_bus_bcma_bus_powerup;
+       dev->device_is_enabled = b43_bus_bcma_device_is_enabled;
+       dev->device_enable = b43_bus_bcma_device_enable;
+       dev->device_disable = b43_bus_bcma_device_disable;
+
+       dev->read16 = b43_bus_bcma_read16;
+       dev->read32 = b43_bus_bcma_read32;
+       dev->write16 = b43_bus_bcma_write16;
+       dev->write32 = b43_bus_bcma_write32;
+       dev->block_read = b43_bus_bcma_block_read;
+       dev->block_write = b43_bus_bcma_block_write;
+
+       dev->dev = &core->dev;
+       dev->dma_dev = core->dma_dev;
+       dev->irq = core->irq;
+
+       /*
+       dev->board_vendor = core->bus->boardinfo.vendor;
+       dev->board_type = core->bus->boardinfo.type;
+       dev->board_rev = core->bus->boardinfo.rev;
+       */
+
+       dev->chip_id = core->bus->chipinfo.id;
+       dev->chip_rev = core->bus->chipinfo.rev;
+       dev->chip_pkg = core->bus->chipinfo.pkg;
+
+       dev->bus_sprom = &core->bus->sprom;
+
+       dev->core_id = core->id.id;
+       dev->core_rev = core->id.rev;
+
+       return dev;
+}
+#endif /* CONFIG_B43_BCMA */
 
 /* SSB */
 #ifdef CONFIG_B43_SSB
@@ -125,3 +225,32 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev)
        return dev;
 }
 #endif /* CONFIG_B43_SSB */
+
+void *b43_bus_get_wldev(struct b43_bus_dev *dev)
+{
+       switch (dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               return bcma_get_drvdata(dev->bdev);
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               return ssb_get_drvdata(dev->sdev);
+#endif
+       }
+       return NULL;
+}
+
+void b43_bus_set_wldev(struct b43_bus_dev *dev, void *wldev)
+{
+       switch (dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_set_drvdata(dev->bdev, wldev);
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               ssb_set_drvdata(dev->sdev, wldev);
+#endif
+       }
+}
index 79a5ab4..184c956 100644 (file)
@@ -2,12 +2,16 @@
 #define B43_BUS_H_
 
 enum b43_bus_type {
+#ifdef CONFIG_B43_BCMA
+       B43_BUS_BCMA,
+#endif
        B43_BUS_SSB,
 };
 
 struct b43_bus_dev {
        enum b43_bus_type bus_type;
        union {
+               struct bcma_device *bdev;
                struct ssb_device *sdev;
        };
 
@@ -57,6 +61,10 @@ static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
                dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO);
 }
 
+struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core);
 struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev);
 
+void *b43_bus_get_wldev(struct b43_bus_dev *dev);
+void b43_bus_set_wldev(struct b43_bus_dev *dev, void *data);
+
 #endif /* B43_BUS_H_ */
index 7a09a46..ce572ae 100644 (file)
@@ -1055,7 +1055,14 @@ int b43_dma_init(struct b43_wldev *dev)
        err = b43_dma_set_mask(dev, dmamask);
        if (err)
                return err;
-       dma->translation = ssb_dma_translation(dev->sdev);
+
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               dma->translation = ssb_dma_translation(dev->dev->sdev);
+               break;
+#endif
+       }
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
index e9a01e3..092dd93 100644 (file)
@@ -1155,6 +1155,21 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
+#ifdef CONFIG_B43_BCMA
+static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
+{
+       u32 flags = 0;
+
+       if (gmode)
+               flags = B43_BCMA_IOCTL_GMODE;
+       flags |= B43_BCMA_IOCTL_PHY_CLKEN;
+       flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */
+       b43_device_enable(dev, flags);
+
+       /* TODO: reset PHY */
+}
+#endif
+
 static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
        struct ssb_device *sdev = dev->dev->sdev;
@@ -1187,7 +1202,18 @@ void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
        u32 macctl;
 
-       b43_ssb_wireless_core_reset(dev, gmode);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43_bcma_wireless_core_reset(dev, gmode);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_ssb_wireless_core_reset(dev, gmode);
+               break;
+#endif
+       }
 
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@ -1938,7 +1964,7 @@ static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
                return IRQ_NONE;
        reason &= dev->irq_mask;
        if (!reason)
-               return IRQ_HANDLED;
+               return IRQ_NONE;
 
        dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
            & 0x0001DC00;
@@ -2133,21 +2159,43 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        u32 tmshigh;
        int err;
 
+       /* Files for HT and LCN were found by trying one by one */
+
        /* Get microcode */
-       if ((rev >= 5) && (rev <= 10))
+       if ((rev >= 5) && (rev <= 10)) {
                filename = "ucode5";
-       else if ((rev >= 11) && (rev <= 12))
+       } else if ((rev >= 11) && (rev <= 12)) {
                filename = "ucode11";
-       else if (rev == 13)
+       } else if (rev == 13) {
                filename = "ucode13";
-       else if (rev == 14)
+       } else if (rev == 14) {
                filename = "ucode14";
-       else if (rev == 15)
+       } else if (rev == 15) {
                filename = "ucode15";
-       else if ((rev >= 16) && (rev <= 20))
-               filename = "ucode16_mimo";
-       else
-               goto err_no_ucode;
+       } else {
+               switch (dev->phy.type) {
+               case B43_PHYTYPE_N:
+                       if (rev >= 16)
+                               filename = "ucode16_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_HT:
+                       if (rev == 29)
+                               filename = "ucode29_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               case B43_PHYTYPE_LCN:
+                       if (rev == 24)
+                               filename = "ucode24_mimo";
+                       else
+                               goto err_no_ucode;
+                       break;
+               default:
+                       goto err_no_ucode;
+               }
+       }
        err = b43_do_request_fw(ctx, filename, &fw->ucode);
        if (err)
                goto err_load;
@@ -2206,6 +2254,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0initvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0initvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
@@ -2253,6 +2313,18 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
                else
                        goto err_no_initvals;
                break;
+       case B43_PHYTYPE_HT:
+               if (rev == 29)
+                       filename = "ht0bsinitvals29";
+               else
+                       goto err_no_initvals;
+               break;
+       case B43_PHYTYPE_LCN:
+               if (rev == 24)
+                       filename = "lcn0bsinitvals24";
+               else
+                       goto err_no_initvals;
+               break;
        default:
                goto err_no_initvals;
        }
@@ -2624,11 +2696,24 @@ static int b43_gpio_init(struct b43_wldev *dev)
        if (dev->dev->core_rev >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
 
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL,
-                           (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                            & mask) | set);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
+                                       BCMA_CC_GPIOCTL) & mask) | set);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL,
+                                   (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+                                   & mask) | set);
+               break;
+#endif
+       }
 
        return 0;
 }
@@ -2638,9 +2723,21 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
 {
        struct ssb_device *gpiodev;
 
-       gpiodev = b43_ssb_gpio_dev(dev);
-       if (gpiodev)
-               ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
+                               0);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               gpiodev = b43_ssb_gpio_dev(dev);
+               if (gpiodev)
+                       ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+               break;
+#endif
+       }
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
@@ -2712,12 +2809,30 @@ out:
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
 void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
 {
-       u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
-       if (on)
-               tmslow |= B43_TMSLOW_MACPHYCLKEN;
-       else
-               tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       u32 tmp;
+
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_read32(dev->dev->bdev, BCMA_IOCTL);
+               if (on)
+                       tmp |= B43_BCMA_IOCTL_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_BCMA_IOCTL_MACPHYCLKEN;
+               bcma_write32(dev->dev->bdev, BCMA_IOCTL, tmp);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               if (on)
+                       tmp |= B43_TMSLOW_MACPHYCLKEN;
+               else
+                       tmp &= ~B43_TMSLOW_MACPHYCLKEN;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               break;
+#endif
+       }
 }
 
 static void b43_adjust_opmode(struct b43_wldev *dev)
@@ -2956,8 +3071,20 @@ static int b43_chip_init(struct b43_wldev *dev)
 
        b43_mac_phy_clock_set(dev, true);
 
-       b43_write16(dev, B43_MMIO_POWERUP_DELAY,
-                   dev->sdev->bus->chipco.fast_pwrup_delay);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               /* FIXME: 0xE74 is quite common, but should be read from CC */
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY, 0xE74);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+                           dev->dev->sdev->bus->chipco.fast_pwrup_delay);
+               break;
+#endif
+       }
 
        err = 0;
        b43dbg(dev->wl, "Chip initialized\n");
@@ -3473,21 +3600,33 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 static void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
-       struct ssb_device *sdev = dev->sdev;
-       u32 tmslow;
+       u32 tmp;
 
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~B43_TMSLOW_GMODE;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       tmslow |= SSB_TMSLOW_FGC;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               b43err(dev->wl,
+                      "Putting PHY into reset not supported on BCMA\n");
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~B43_TMSLOW_GMODE;
+               tmp |= B43_TMSLOW_PHYRESET;
+               tmp |= SSB_TMSLOW_FGC;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
+
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               tmp &= ~SSB_TMSLOW_FGC;
+               tmp |= B43_TMSLOW_PHYRESET;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               msleep(1);
 
-       tmslow = ssb_read32(sdev, SSB_TMSLOW);
-       tmslow &= ~SSB_TMSLOW_FGC;
-       tmslow |= B43_TMSLOW_PHYRESET;
-       ssb_write32(sdev, SSB_TMSLOW, tmslow);
-       msleep(1);
+               break;
+#endif
+       }
 }
 
 static const char *band_to_string(enum ieee80211_band band)
@@ -4103,6 +4242,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (phy_rev > 1)
                        unsupported = 1;
                break;
+#endif
+#ifdef CONFIG_B43_PHY_LCN
+       case B43_PHYTYPE_LCN:
+               if (phy_rev > 1)
+                       unsupported = 1;
+               break;
 #endif
        default:
                unsupported = 1;
@@ -4117,22 +4262,42 @@ static int b43_phy_versioning(struct b43_wldev *dev)
               analog_type, phy_type, phy_rev);
 
        /* Get RADIO versioning */
-       if (dev->dev->chip_id == 0x4317) {
-               if (dev->dev->chip_rev == 0)
-                       tmp = 0x3205017F;
-               else if (dev->dev->chip_rev == 1)
-                       tmp = 0x4205017F;
-               else
-                       tmp = 0x5205017F;
+       if (dev->dev->core_rev >= 24) {
+               u16 radio24[3];
+
+               for (tmp = 0; tmp < 3; tmp++) {
+                       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+                       radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
+               }
+
+               /* Broadcom uses "id" for our "ver" and has separated "ver" */
+               /* radio_ver = (radio24[0] & 0xF0) >> 4; */
+
+               radio_manuf = 0x17F;
+               radio_ver = (radio24[2] << 8) | radio24[1];
+               radio_rev = (radio24[0] & 0xF);
        } else {
-               b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-               b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-               tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
-       }
-       radio_manuf = (tmp & 0x00000FFF);
-       radio_ver = (tmp & 0x0FFFF000) >> 12;
-       radio_rev = (tmp & 0xF0000000) >> 28;
+               if (dev->dev->chip_id == 0x4317) {
+                       if (dev->dev->chip_rev == 0)
+                               tmp = 0x3205017F;
+                       else if (dev->dev->chip_rev == 1)
+                               tmp = 0x4205017F;
+                       else
+                               tmp = 0x5205017F;
+               } else {
+                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
+                                   B43_RADIOCTL_ID);
+                       tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
+                                   B43_RADIOCTL_ID);
+                       tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
+                               << 16;
+               }
+               radio_manuf = (tmp & 0x00000FFF);
+               radio_ver = (tmp & 0x0FFFF000) >> 12;
+               radio_rev = (tmp & 0xF0000000) >> 28;
+       }
+
        if (radio_manuf != 0x17F /* Broadcom */)
                unsupported = 1;
        switch (phy_type) {
@@ -4164,6 +4329,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                if (radio_ver != 0x2059)
                        unsupported = 1;
                break;
+       case B43_PHYTYPE_LCN:
+               if (radio_ver != 0x2064)
+                       unsupported = 1;
+               break;
        default:
                B43_WARN_ON(1);
        }
@@ -4347,7 +4516,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
@@ -4366,7 +4534,20 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        phy->ops->prepare_structs(dev);
 
        /* Enable IRQ routing to this device. */
-       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
+                                     dev->dev->bdev, true);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               ssb_pcicore_dev_irqvecs_enable(&dev->dev->sdev->bus->pcicore,
+                                              dev->dev->sdev);
+               break;
+#endif
+       }
 
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
@@ -4397,8 +4578,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
                hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
 #ifdef CONFIG_SSB_DRIVER_PCICORE
-       if ((bus->bustype == SSB_BUSTYPE_PCI) &&
-           (bus->pcicore.dev->id.revision <= 10))
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+           dev->dev->sdev->bus->pcicore.dev->id.revision <= 10)
                hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
 #endif
        hf &= ~B43_HF_SKCFPUP;
@@ -4764,8 +4946,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
 static int b43_wireless_core_attach(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
-       struct ssb_bus *bus = dev->sdev->bus;
-       struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
+       struct pci_dev *pdev = NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
 
@@ -4776,20 +4957,38 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
         * that in core_init(), too.
         */
 
+#ifdef CONFIG_B43_SSB
+       if (dev->dev->bus_type == B43_BUS_SSB &&
+           dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI)
+               pdev = dev->dev->sdev->bus->host_pci;
+#endif
+
        err = b43_bus_powerup(dev, 0);
        if (err) {
                b43err(wl, "Bus powerup failed\n");
                goto out;
        }
-       /* Get the PHY type. */
-       if (dev->dev->core_rev >= 5) {
-               u32 tmshigh;
 
-               tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
-               have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
-               have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
-       } else
-               B43_WARN_ON(1);
+       /* Get the PHY type. */
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               /* FIXME */
+               have_2ghz_phy = 1;
+               have_5ghz_phy = 0;
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               if (dev->dev->core_rev >= 5) {
+                       u32 tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
+                       have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+                       have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
+               } else
+                       B43_WARN_ON(1);
+               break;
+#endif
+       }
 
        dev->phy.gmode = have_2ghz_phy;
        dev->phy.radio_on = 1;
@@ -4815,6 +5014,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 #endif
                case B43_PHYTYPE_G:
                case B43_PHYTYPE_N:
+               case B43_PHYTYPE_HT:
+               case B43_PHYTYPE_LCN:
                        have_2ghz_phy = 1;
                        break;
                default:
@@ -4877,13 +5078,13 @@ static void b43_one_core_detach(struct b43_bus_dev *dev)
        /* Do not cancel ieee80211-workqueue based work here.
         * See comment in b43_remove(). */
 
-       wldev = ssb_get_drvdata(dev->sdev);
+       wldev = b43_bus_get_wldev(dev);
        wl = wldev->wl;
        b43_debugfs_remove_device(wldev);
        b43_wireless_core_detach(wldev);
        list_del(&wldev->list);
        wl->nr_devs--;
-       ssb_set_drvdata(dev->sdev, NULL);
+       b43_bus_set_wldev(dev, NULL);
        kfree(wldev);
 }
 
@@ -4898,7 +5099,6 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
 
        wldev->use_pio = b43_modparam_pio;
        wldev->dev = dev;
-       wldev->sdev = dev->sdev; /* TODO: Remove when not needed */
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4910,7 +5110,7 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
 
        list_add(&wldev->list, &wl->devlist);
        wl->nr_devs++;
-       ssb_set_drvdata(dev->sdev, wldev);
+       b43_bus_set_wldev(dev, wldev);
        b43_debugfs_add_device(wldev);
 
       out:
@@ -4959,9 +5159,9 @@ static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl)
        ieee80211_free_hw(hw);
 }
 
-static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
+static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
 {
-       struct ssb_sprom *sprom = &dev->bus->sprom;
+       struct ssb_sprom *sprom = dev->bus_sprom;
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
 
@@ -5003,14 +5203,21 @@ static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
        skb_queue_head_init(&wl->tx_queue);
 
        b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
-               dev->bus->chip_id, dev->id.revision);
+               dev->chip_id, dev->core_rev);
        return wl;
 }
 
 #ifdef CONFIG_B43_BCMA
 static int b43_bcma_probe(struct bcma_device *core)
 {
+       struct b43_bus_dev *dev;
+
+       dev = b43_bus_dev_bcma_init(core);
+       if (!dev)
+               return -ENODEV;
+
        b43err(NULL, "BCMA is not supported yet!");
+       kfree(dev);
        return -EOPNOTSUPP;
 }
 
@@ -5045,7 +5252,7 @@ int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
                b43_sprom_fixup(sdev->bus);
-               wl = b43_wireless_init(sdev);
+               wl = b43_wireless_init(dev);
                if (IS_ERR(wl)) {
                        err = PTR_ERR(wl);
                        goto out;
index 9705950..1019575 100644 (file)
@@ -32,6 +32,7 @@
 #include "phy_n.h"
 #include "phy_lp.h"
 #include "phy_ht.h"
+#include "phy_lcn.h"
 #include "b43.h"
 #include "main.h"
 
@@ -63,6 +64,11 @@ int b43_phy_allocate(struct b43_wldev *dev)
        case B43_PHYTYPE_HT:
 #ifdef CONFIG_B43_PHY_HT
                phy->ops = &b43_phyops_ht;
+#endif
+               break;
+       case B43_PHYTYPE_LCN:
+#ifdef CONFIG_B43_PHY_LCN
+               phy->ops = &b43_phyops_lcn;
 #endif
                break;
        }
index 47dcb80..aa77ba6 100644 (file)
@@ -195,6 +195,7 @@ struct b43_phy_g;
 struct b43_phy_n;
 struct b43_phy_lp;
 struct b43_phy_ht;
+struct b43_phy_lcn;
 
 struct b43_phy {
        /* Hardware operation callbacks. */
@@ -219,6 +220,8 @@ struct b43_phy {
                struct b43_phy_lp *lp;
                /* HT-PHY specific information */
                struct b43_phy_ht *ht;
+               /* LCN-PHY specific information */
+               struct b43_phy_lcn *lcn;
        };
 
        /* Band support flags. */
index 30b19c6..2982103 100644 (file)
@@ -373,6 +373,16 @@ static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
        b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
 }
 
+static enum b43_txpwr_result
+b43_phy_ht_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
+{
+       return B43_TXPWR_RES_DONE;
+}
+
+static void b43_phy_ht_op_adjust_txpower(struct b43_wldev *dev)
+{
+}
+
 /**************************************************
  * PHY ops struct.
  **************************************************/
@@ -391,8 +401,6 @@ const struct b43_phy_operations b43_phyops_ht = {
        .switch_analog          = b43_phy_ht_op_switch_analog,
        .switch_channel         = b43_phy_ht_op_switch_channel,
        .get_default_chan       = b43_phy_ht_op_get_default_chan,
-       /*
        .recalc_txpower         = b43_phy_ht_op_recalc_txpower,
        .adjust_txpower         = b43_phy_ht_op_adjust_txpower,
-       */
 };
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
new file mode 100644 (file)
index 0000000..9f7dbbd
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n LCN-PHY support
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/slab.h>
+
+#include "b43.h"
+#include "phy_lcn.h"
+#include "tables_phy_lcn.h"
+#include "main.h"
+
+/**************************************************
+ * PHY ops struct.
+ **************************************************/
+
+const struct b43_phy_operations b43_phyops_lcn = {
+       /*
+       .allocate               = b43_phy_lcn_op_allocate,
+       .free                   = b43_phy_lcn_op_free,
+       .prepare_structs        = b43_phy_lcn_op_prepare_structs,
+       .init                   = b43_phy_lcn_op_init,
+       .phy_read               = b43_phy_lcn_op_read,
+       .phy_write              = b43_phy_lcn_op_write,
+       .phy_maskset            = b43_phy_lcn_op_maskset,
+       .radio_read             = b43_phy_lcn_op_radio_read,
+       .radio_write            = b43_phy_lcn_op_radio_write,
+       .software_rfkill        = b43_phy_lcn_op_software_rfkill,
+       .switch_analog          = b43_phy_lcn_op_switch_analog,
+       .switch_channel         = b43_phy_lcn_op_switch_channel,
+       .get_default_chan       = b43_phy_lcn_op_get_default_chan,
+       .recalc_txpower         = b43_phy_lcn_op_recalc_txpower,
+       .adjust_txpower         = b43_phy_lcn_op_adjust_txpower,
+       */
+};
diff --git a/drivers/net/wireless/b43/phy_lcn.h b/drivers/net/wireless/b43/phy_lcn.h
new file mode 100644 (file)
index 0000000..c046c2a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef B43_PHY_LCN_H_
+#define B43_PHY_LCN_H_
+
+#include "phy_common.h"
+
+
+struct b43_phy_lcn {
+};
+
+
+struct b43_phy_operations;
+extern const struct b43_phy_operations b43_phyops_lcn;
+
+#endif /* B43_PHY_LCN_H_ */
\ No newline at end of file
index e7dfdac..95c28f5 100644 (file)
@@ -603,17 +603,33 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
 static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
 {
-       u32 tmslow;
+       u32 tmp;
 
        if (dev->phy.type != B43_PHYTYPE_N)
                return;
 
-       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
-       if (force)
-               tmslow |= SSB_TMSLOW_FGC;
-       else
-               tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_read32(dev->dev->bdev, BCMA_IOCTL);
+               if (force)
+                       tmp |= BCMA_IOCTL_FGC;
+               else
+                       tmp &= ~BCMA_IOCTL_FGC;
+               bcma_write32(dev->dev->bdev, BCMA_IOCTL, tmp);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
+               if (force)
+                       tmp |= SSB_TMSLOW_FGC;
+               else
+                       tmp &= ~SSB_TMSLOW_FGC;
+               ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
+               break;
+#endif
+       }
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
@@ -958,8 +974,21 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
                b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
                b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
 
-               ssb_chipco_gpio_control(&dev->sdev->bus->chipco, 0xFC00,
-                                       0xFC00);
+               switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+               case B43_BUS_BCMA:
+                       bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc,
+                                                0xFC00, 0xFC00);
+                       break;
+#endif
+#ifdef CONFIG_B43_SSB
+               case B43_BUS_SSB:
+                       ssb_chipco_gpio_control(&dev->dev->sdev->bus->chipco,
+                                               0xFC00, 0xFC00);
+                       break;
+#endif
+               }
+
                b43_write32(dev, B43_MMIO_MACCTL,
                        b43_read32(dev, B43_MMIO_MACCTL) &
                        ~B43_MACCTL_GPOUTSMSK);
@@ -3600,7 +3629,20 @@ int b43_phy_initn(struct b43_wldev *dev)
        if ((dev->phy.rev >= 3) &&
           (sprom->boardflags_lo & B43_BFL_EXTLNA) &&
           (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
-               chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+               switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+               case B43_BUS_BCMA:
+                       bcma_cc_set32(&dev->dev->bdev->bus->drv_cc,
+                                     BCMA_CC_CHIPCTL, 0x40);
+                       break;
+#endif
+#ifdef CONFIG_B43_SSB
+               case B43_BUS_SSB:
+                       chipco_set32(&dev->dev->sdev->bus->chipco,
+                                    SSB_CHIPCO_CHIPCTL, 0x40);
+                       break;
+#endif
+               }
        }
        nphy->deaf_count = 0;
        b43_nphy_tables_init(dev);
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c
new file mode 100644 (file)
index 0000000..40c1d09
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n LCN-PHY data tables
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables_phy_lcn.h"
+#include "phy_common.h"
+#include "phy_lcn.h"
+
+/**************************************************
+ * Tables ops.
+ **************************************************/
+
+void b43_phy_lcn_tables_init(struct b43_wldev *dev)
+{
+}
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.h b/drivers/net/wireless/b43/tables_phy_lcn.h
new file mode 100644 (file)
index 0000000..5e31b15
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef B43_TABLES_PHY_LCN_H_
+#define B43_TABLES_PHY_LCN_H_
+
+void b43_phy_lcn_tables_init(struct b43_wldev *dev);
+
+#endif /* B43_TABLES_PHY_LCN_H_ */
index 488b898..82bcf75 100644 (file)
@@ -323,8 +323,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                        /* we give the phase1key and iv16 here, the key is stored in
                         * shm. With that the hardware can do phase 2 and encryption.
                         */
-                       ieee80211_get_tkip_key(info->control.hw_key, skb_frag,
-                                       IEEE80211_TKIP_P1_KEY, (u8*)phase1key);
+                       ieee80211_get_tkip_p1k(info->control.hw_key, skb_frag, phase1key);
                        /* phase1key is in host endian. Copy to little-endian txhdr->iv. */
                        for (i = 0; i < 5; i++) {
                                txhdr->iv[i * 2 + 0] = phase1key[i];
index 79ac081..ac4f64d 100644 (file)
@@ -240,8 +240,7 @@ static void iwl4965_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
 
        case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_key(keyconf, skb_frag,
-                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+               ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
                IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
                break;
 
index 46242d2..1433466 100644 (file)
@@ -1484,7 +1484,7 @@ static const char * const desc_lookup_text[] = {
        "NMI_INTERRUPT_DATA_ACTION_PT",
        "NMI_TRM_HW_ER",
        "NMI_INTERRUPT_TRM",
-       "NMI_INTERRUPT_BREAK_POINT"
+       "NMI_INTERRUPT_BREAK_POINT",
        "DEBUG_0",
        "DEBUG_1",
        "DEBUG_2",
index cf1449d..2f56b34 100644 (file)
@@ -125,7 +125,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
                        iwlagn_mod_params.num_of_queues;
 
        priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
@@ -172,11 +171,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl1000_nic_config,
-       },
+       .nic_config = iwl1000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -187,16 +182,12 @@ static struct iwl_lib_ops iwl1000_lib = {
                        EEPROM_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REGULATORY_BAND_NO_HT40,
                },
-               .query_addr = iwlagn_eeprom_query_addr,
        },
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-        },
+       .temperature = iwlagn_temperature,
 };
 
 static const struct iwl_ops iwl1000_ops = {
        .lib = &iwl1000_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static struct iwl_base_params iwl1000_base_params = {
index a401113..32ac865 100644 (file)
@@ -123,7 +123,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
                        iwlagn_mod_params.num_of_queues;
 
        priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                priv->cfg->base_params->num_of_queues *
                sizeof(struct iwlagn_scd_bc_tbl);
@@ -169,14 +168,31 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
 static struct iwl_lib_ops iwl2000_lib = {
        .set_hw_params = iwl2000_hw_set_hw_params,
        .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .nic_config = iwl2000_nic_config,
+       .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REGULATORY_BAND_NO_HT40,
+               },
+               .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+       },
+       .temperature = iwlagn_temperature,
+};
+
+static struct iwl_lib_ops iwl2030_lib = {
+       .set_hw_params = iwl2000_hw_set_hw_params,
+       .rx_handler_setup = iwlagn_bt_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl2000_nic_config,
-       },
+       .nic_config = iwl2000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -187,32 +203,25 @@ static struct iwl_lib_ops iwl2000_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REGULATORY_BAND_NO_HT40,
                },
-               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-       },
+       .temperature = iwlagn_temperature,
 };
 
 static const struct iwl_ops iwl2000_ops = {
        .lib = &iwl2000_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static const struct iwl_ops iwl2030_ops = {
-       .lib = &iwl2000_lib,
-       .utils = &iwlagn_hcmd_utils,
+       .lib = &iwl2030_lib,
 };
 
 static const struct iwl_ops iwl105_ops = {
        .lib = &iwl2000_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static const struct iwl_ops iwl135_ops = {
-       .lib = &iwl2000_lib,
-       .utils = &iwlagn_hcmd_utils,
+       .lib = &iwl2030_lib,
 };
 
 static struct iwl_base_params iwl2000_base_params = {
index c55cec8..5564893 100644 (file)
@@ -46,6 +46,7 @@
 #include "iwl-agn.h"
 #include "iwl-agn-hw.h"
 #include "iwl-5000-hw.h"
+#include "iwl-trans.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 5
@@ -156,7 +157,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                        iwlagn_mod_params.num_of_queues;
 
        priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
@@ -200,7 +200,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
                        iwlagn_mod_params.num_of_queues;
 
        priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
@@ -316,7 +315,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                return -EFAULT;
        }
 
-       return iwl_send_cmd_sync(priv, &hcmd);
+       return trans_send_cmd(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl5000_lib = {
@@ -324,12 +323,8 @@ static struct iwl_lib_ops iwl5000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl5000_nic_config,
-       },
+       .nic_config = iwl5000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -340,11 +335,8 @@ static struct iwl_lib_ops iwl5000_lib = {
                        EEPROM_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .query_addr = iwlagn_eeprom_query_addr,
        },
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-        },
+       .temperature = iwlagn_temperature,
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -352,12 +344,8 @@ static struct iwl_lib_ops iwl5150_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl5000_nic_config,
-       },
+       .nic_config = iwl5000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -368,21 +356,16 @@ static struct iwl_lib_ops iwl5150_lib = {
                        EEPROM_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .query_addr = iwlagn_eeprom_query_addr,
        },
-       .temp_ops = {
-               .temperature = iwl5150_temperature,
-        },
+       .temperature = iwl5150_temperature,
 };
 
 static const struct iwl_ops iwl5000_ops = {
        .lib = &iwl5000_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static const struct iwl_ops iwl5150_ops = {
        .lib = &iwl5150_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static struct iwl_base_params iwl5000_base_params = {
index 965d010..80f1ef6 100644 (file)
@@ -45,6 +45,7 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
+#include "iwl-trans.h"
 
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
@@ -144,7 +145,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
                        iwlagn_mod_params.num_of_queues;
 
        priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
-       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->base_params->num_of_queues *
                        sizeof(struct iwlagn_scd_bc_tbl);
@@ -255,7 +255,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                return -EFAULT;
        }
 
-       return iwl_send_cmd_sync(priv, &hcmd);
+       return trans_send_cmd(priv, &hcmd);
 }
 
 static struct iwl_lib_ops iwl6000_lib = {
@@ -263,12 +263,8 @@ static struct iwl_lib_ops iwl6000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl6000_nic_config,
-       },
+       .nic_config = iwl6000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -279,12 +275,9 @@ static struct iwl_lib_ops iwl6000_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-        },
+       .temperature = iwlagn_temperature,
 };
 
 static struct iwl_lib_ops iwl6030_lib = {
@@ -293,12 +286,8 @@ static struct iwl_lib_ops iwl6030_lib = {
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
-       .apm_ops = {
-               .init = iwl_apm_init,
-               .config = iwl6000_nic_config,
-       },
+       .nic_config = iwl6000_nic_config,
        .eeprom_ops = {
                .regulatory_bands = {
                        EEPROM_REG_BAND_1_CHANNELS,
@@ -309,12 +298,9 @@ static struct iwl_lib_ops iwl6030_lib = {
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
                        EEPROM_REG_BAND_52_HT40_CHANNELS
                },
-               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
-       .temp_ops = {
-               .temperature = iwlagn_temperature,
-        },
+       .temperature = iwlagn_temperature,
 };
 
 static struct iwl_nic_ops iwl6050_nic_ops = {
@@ -327,24 +313,20 @@ static struct iwl_nic_ops iwl6150_nic_ops = {
 
 static const struct iwl_ops iwl6000_ops = {
        .lib = &iwl6000_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static const struct iwl_ops iwl6050_ops = {
        .lib = &iwl6000_lib,
-       .utils = &iwlagn_hcmd_utils,
        .nic = &iwl6050_nic_ops,
 };
 
 static const struct iwl_ops iwl6150_ops = {
        .lib = &iwl6000_lib,
-       .utils = &iwlagn_hcmd_utils,
        .nic = &iwl6150_nic_ops,
 };
 
 static const struct iwl_ops iwl6030_ops = {
        .lib = &iwl6030_lib,
-       .utils = &iwlagn_hcmd_utils,
 };
 
 static struct iwl_base_params iwl6000_base_params = {
index c9255de..02c7c65 100644 (file)
@@ -66,6 +66,8 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-agn-calib.h"
+#include "iwl-trans.h"
+#include "iwl-agn.h"
 
 /*****************************************************************************
  * INIT calibrations framework
@@ -87,6 +89,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
 
        struct iwl_host_cmd hcmd = {
                .id = REPLY_PHY_CALIBRATION_CMD,
+               .flags = CMD_SYNC,
        };
 
        for (i = 0; i < IWL_CALIB_MAX; i++) {
@@ -95,7 +98,7 @@ int iwl_send_calib_results(struct iwl_priv *priv)
                        hcmd.len[0] = priv->calib_results[i].buf_len;
                        hcmd.data[0] = priv->calib_results[i].buf;
                        hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-                       ret = iwl_send_cmd_sync(priv, &hcmd);
+                       ret = trans_send_cmd(priv, &hcmd);
                        if (ret) {
                                IWL_ERR(priv, "Error %d iteration %d\n",
                                        ret, i);
@@ -481,7 +484,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
               sizeof(u16)*HD_TABLE_SIZE);
 
-       return iwl_send_cmd(priv, &cmd_out);
+       return trans_send_cmd(priv, &cmd_out);
 }
 
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
@@ -545,7 +548,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
               &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]),
               sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
 
-       return iwl_send_cmd(priv, &cmd_out);
+       return trans_send_cmd(priv, &cmd_out);
 }
 
 void iwl_init_sensitivity(struct iwl_priv *priv)
@@ -991,16 +994,14 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
        IWL_DEBUG_CALIB(priv, "min_average_noise = %d, antenna %d\n",
                        min_average_noise, min_average_noise_antenna_i);
 
-       if (priv->cfg->ops->utils->gain_computation)
-               priv->cfg->ops->utils->gain_computation(priv, average_noise,
+       iwlagn_gain_computation(priv, average_noise,
                                min_average_noise_antenna_i, min_average_noise,
                                find_first_chain(priv->cfg->valid_rx_ant));
 
        /* Some power changes may have been made during the calibration.
         * Update and commit the RXON
         */
-       if (priv->cfg->ops->lib->update_chain_flags)
-               priv->cfg->ops->lib->update_chain_flags(priv);
+       iwl_update_chain_flags(priv);
 
        data->state = IWL_CHAIN_NOISE_DONE;
        iwl_power_update_mode(priv, false);
index 4ef4dd9..a869fc9 100644 (file)
@@ -71,13 +71,6 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv);
 
 void iwl_init_sensitivity(struct iwl_priv *priv);
 void iwl_reset_run_time_calib(struct iwl_priv *priv);
-static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
-{
-
-       if (!priv->disable_chain_noise_cal &&
-           priv->cfg->ops->utils->chain_noise_reset)
-               priv->cfg->ops->utils->chain_noise_reset(priv);
-}
 
 int iwl_send_calib_results(struct iwl_priv *priv);
 int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
index 7745816..b8347db 100644 (file)
@@ -150,7 +150,7 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
 
 void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
 {
-       const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv,
+       const u8 *addr = iwl_eeprom_query_addr(priv,
                                        EEPROM_MAC_ADDRESS);
        memcpy(mac, addr, ETH_ALEN);
 }
@@ -245,10 +245,10 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv)
        BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
 
        /* the length is in 16-bit words, but we want entries */
-       txp_len = (__le16 *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
+       txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
        entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
 
-       txp_array = (void *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
+       txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
 
        for (idx = 0; idx < entries; idx++) {
                txp = &txp_array[idx];
index ce7d4b5..f0f5f5e 100644 (file)
@@ -36,6 +36,7 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-agn.h"
+#include "iwl-trans.h"
 
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
 {
@@ -45,7 +46,9 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
 
        if (IWL_UCODE_API(priv->ucode_ver) > 1) {
                IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+               return trans_send_cmd_pdu(priv,
+                                       TX_ANT_CONFIGURATION_CMD,
+                                       CMD_SYNC,
                                        sizeof(struct iwl_tx_ant_config_cmd),
                                        &tx_ant_cmd);
        } else {
@@ -54,17 +57,7 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
        }
 }
 
-static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
-{
-       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
-       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
-       memcpy(addsta, cmd, size);
-       /* resrved in 5000 */
-       addsta->rate_n_flags = cpu_to_le16(0);
-       return size;
-}
-
-static void iwlagn_gain_computation(struct iwl_priv *priv,
+void iwlagn_gain_computation(struct iwl_priv *priv,
                u32 average_noise[NUM_RX_CHAINS],
                u16 min_average_noise_antenna_i,
                u32 min_average_noise,
@@ -115,96 +108,14 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
                        priv->_agn.phy_calib_chain_noise_gain_cmd);
                cmd.delta_gain_1 = data->delta_gain_code[1];
                cmd.delta_gain_2 = data->delta_gain_code[2];
-               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
-                       sizeof(cmd), &cmd, NULL);
+               trans_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                       CMD_ASYNC, sizeof(cmd), &cmd);
 
                data->radio_write = 1;
                data->state = IWL_CHAIN_NOISE_CALIBRATED;
        }
 }
 
-static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
-{
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-       int ret;
-
-       if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-           iwl_is_any_associated(priv)) {
-               struct iwl_calib_chain_noise_reset_cmd cmd;
-
-               /* clear data for chain noise calibration algorithm */
-               data->chain_noise_a = 0;
-               data->chain_noise_b = 0;
-               data->chain_noise_c = 0;
-               data->chain_signal_a = 0;
-               data->chain_signal_b = 0;
-               data->chain_signal_c = 0;
-               data->beacon_count = 0;
-
-               memset(&cmd, 0, sizeof(cmd));
-               iwl_set_calib_hdr(&cmd.hdr,
-                       priv->_agn.phy_calib_chain_noise_reset_cmd);
-               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-                                       sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv,
-                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
-               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
-       }
-}
-
-static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
-                                    struct ieee80211_tx_info *info,
-                                    __le16 fc, __le32 *tx_flags)
-{
-       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
-           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
-           info->flags & IEEE80211_TX_CTL_AMPDU)
-               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-}
-
-/* Calc max signal level (dBm) among 3 possible receivers */
-static int iwlagn_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp)
-{
-       /* data from PHY/DSP regarding signal strength, etc.,
-        *   contents are always there, not configurable by host
-        */
-       struct iwlagn_non_cfg_phy *ncphy =
-               (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
-       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
-       u8 agc;
-
-       val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
-       agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
-
-       /* Find max rssi among 3 possible receivers.
-        * These values are measured by the digital signal processor (DSP).
-        * They should stay fairly constant even as the signal strength varies,
-        *   if the radio's automatic gain control (AGC) is working right.
-        * AGC value (see below) will provide the "interesting" info.
-        */
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
-       rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
-               IWLAGN_OFDM_RSSI_A_BIT_POS;
-       rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
-               IWLAGN_OFDM_RSSI_B_BIT_POS;
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
-       rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
-               IWLAGN_OFDM_RSSI_C_BIT_POS;
-
-       max_rssi = max_t(u32, rssi_a, rssi_b);
-       max_rssi = max_t(u32, max_rssi, rssi_c);
-
-       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
-               rssi_a, rssi_b, rssi_c, max_rssi, agc);
-
-       /* dBm = max_rssi dB - agc dB - constant.
-        * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
-}
-
 int iwlagn_set_pan_params(struct iwl_priv *priv)
 {
        struct iwl_wipan_params_cmd cmd;
@@ -290,18 +201,10 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
        cmd.slots[0].width = cpu_to_le16(slot0);
        cmd.slots[1].width = cpu_to_le16(slot1);
 
-       ret = iwl_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, sizeof(cmd), &cmd);
+       ret = trans_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, CMD_SYNC,
+                       sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
 
        return ret;
 }
-
-struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
-       .build_addsta_hcmd = iwlagn_build_addsta_hcmd,
-       .gain_computation = iwlagn_gain_computation,
-       .chain_noise_reset = iwlagn_chain_noise_reset,
-       .tx_cmd_protection = iwlagn_tx_cmd_protection,
-       .calc_rssi = iwlagn_calc_rssi,
-       .request_scan = iwlagn_request_scan,
-};
index 90d366e..eb2be0d 100644 (file)
@@ -39,6 +39,7 @@
 #include "iwl-agn-hw.h"
 #include "iwl-agn.h"
 #include "iwl-sta.h"
+#include "iwl-trans.h"
 
 static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
 {
@@ -540,8 +541,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
        else
                tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
 
-       return iwl_send_cmd_pdu(priv, tx_ant_cfg_cmd, sizeof(tx_power_cmd),
-                               &tx_power_cmd);
+       return trans_send_cmd_pdu(priv, tx_ant_cfg_cmd, CMD_SYNC,
+                       sizeof(tx_power_cmd), &tx_power_cmd);
 }
 
 void iwlagn_temperature(struct iwl_priv *priv)
@@ -610,8 +611,7 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
        return (address & ADDRESS_MSK) + (offset << 1);
 }
 
-const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
-                                          size_t offset)
+const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
 {
        u32 address = eeprom_indirect_address(priv, offset);
        BUG_ON(address >= priv->cfg->base_params->eeprom_size);
@@ -702,7 +702,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
 
        /* nic_init */
        spin_lock_irqsave(&priv->lock, flags);
-       priv->cfg->ops->lib->apm_ops.init(priv);
+       iwl_apm_init(priv);
 
        /* Set interrupt coalescing calibration timer to default (512 usecs) */
        iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
@@ -711,10 +711,10 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
 
        iwlagn_set_pwr_vmain(priv);
 
-       priv->cfg->ops->lib->apm_ops.config(priv);
+       priv->cfg->ops->lib->nic_config(priv);
 
        /* Allocate the RX queue, or reset if it is already allocated */
-       priv->trans.ops->rx_init(priv);
+       trans_rx_init(priv);
 
        iwlagn_rx_replenish(priv);
 
@@ -728,7 +728,7 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* Allocate or reset and init all Tx and Command queues */
-       if (priv->trans.ops->tx_init(priv))
+       if (trans_tx_init(priv))
                return -ENOMEM;
 
        if (priv->cfg->base_params->shadow_reg_enable) {
@@ -905,17 +905,6 @@ void iwlagn_rx_replenish_now(struct iwl_priv *priv)
        iwlagn_rx_queue_restock(priv);
 }
 
-int iwlagn_rxq_stop(struct iwl_priv *priv)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
-                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-
-       return 0;
-}
-
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
 {
        int idx = 0;
@@ -1074,6 +1063,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
                .len = { sizeof(struct iwl_scan_cmd), },
+               .flags = CMD_SYNC,
        };
        struct iwl_scan_cmd *scan;
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -1370,7 +1360,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        if (ret)
                return ret;
 
-       ret = iwl_send_cmd_sync(priv, &cmd);
+       ret = trans_send_cmd(priv, &cmd);
        if (ret) {
                clear_bit(STATUS_SCAN_HW, &priv->status);
                iwlagn_set_pan_params(priv);
@@ -1476,7 +1466,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
                       flush_cmd.fifo_control);
        flush_cmd.flush_control = cpu_to_le16(flush_control);
 
-       return iwl_send_cmd(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
@@ -1644,9 +1634,11 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
        } else {
                basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
                                        IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
-               if (priv->cfg->bt_params &&
-                   priv->cfg->bt_params->bt_sco_disable)
+
+               if (!priv->bt_enable_pspoll)
                        basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
+               else
+                       basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
 
                if (priv->bt_ch_announce)
                        basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
@@ -1668,19 +1660,97 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
        if (priv->cfg->bt_params->bt_session_2) {
                memcpy(&bt_cmd_2000.basic, &basic,
                        sizeof(basic));
-               ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                       sizeof(bt_cmd_2000), &bt_cmd_2000);
+               ret = trans_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                       CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000);
        } else {
                memcpy(&bt_cmd_6000.basic, &basic,
                        sizeof(basic));
-               ret = iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                       sizeof(bt_cmd_6000), &bt_cmd_6000);
+               ret = trans_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                       CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000);
        }
        if (ret)
                IWL_ERR(priv, "failed to send BT Coex Config\n");
 
 }
 
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
+{
+       struct iwl_rxon_context *ctx, *found_ctx = NULL;
+       bool found_ap = false;
+
+       lockdep_assert_held(&priv->mutex);
+
+       /* Check whether AP or GO mode is active. */
+       if (rssi_ena) {
+               for_each_context(priv, ctx) {
+                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
+                           iwl_is_associated_ctx(ctx)) {
+                               found_ap = true;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If disable was received or If GO/AP mode, disable RSSI
+        * measurements.
+        */
+       if (!rssi_ena || found_ap) {
+               if (priv->cur_rssi_ctx) {
+                       ctx = priv->cur_rssi_ctx;
+                       ieee80211_disable_rssi_reports(ctx->vif);
+                       priv->cur_rssi_ctx = NULL;
+               }
+               return;
+       }
+
+       /*
+        * If rssi measurements need to be enabled, consider all cases now.
+        * Figure out how many contexts are active.
+        */
+       for_each_context(priv, ctx) {
+               if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
+                   iwl_is_associated_ctx(ctx)) {
+                       found_ctx = ctx;
+                       break;
+               }
+       }
+
+       /*
+        * rssi monitor already enabled for the correct interface...nothing
+        * to do.
+        */
+       if (found_ctx == priv->cur_rssi_ctx)
+               return;
+
+       /*
+        * Figure out if rssi monitor is currently enabled, and needs
+        * to be changed. If rssi monitor is already enabled, disable
+        * it first else just enable rssi measurements on the
+        * interface found above.
+        */
+       if (priv->cur_rssi_ctx) {
+               ctx = priv->cur_rssi_ctx;
+               if (ctx->vif)
+                       ieee80211_disable_rssi_reports(ctx->vif);
+       }
+
+       priv->cur_rssi_ctx = found_ctx;
+
+       if (!found_ctx)
+               return;
+
+       ieee80211_enable_rssi_reports(found_ctx->vif,
+                       IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
+                       IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
+}
+
+static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
+{
+       return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
+                       BT_UART_MSG_FRAME3SCOESCO_POS;
+}
+
 static void iwlagn_bt_traffic_change_work(struct work_struct *work)
 {
        struct iwl_priv *priv =
@@ -1733,8 +1803,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
        if (test_bit(STATUS_SCAN_HW, &priv->status))
                goto out;
 
-       if (priv->cfg->ops->lib->update_chain_flags)
-               priv->cfg->ops->lib->update_chain_flags(priv);
+       iwl_update_chain_flags(priv);
 
        if (smps_request != -1) {
                priv->current_ht_config.smps = smps_request;
@@ -1743,10 +1812,30 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
                                ieee80211_request_smps(ctx->vif, smps_request);
                }
        }
+
+       /*
+        * Dynamic PS poll related functionality. Adjust RSSI measurements if
+        * necessary.
+        */
+       iwlagn_bt_coex_rssi_monitor(priv);
 out:
        mutex_unlock(&priv->mutex);
 }
 
+/*
+ * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
+ * correct interface or disable it if this is the last interface to be
+ * removed.
+ */
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
+{
+       if (priv->bt_is_sco &&
+           priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
+               iwlagn_bt_adjust_rssi_monitor(priv, true);
+       else
+               iwlagn_bt_adjust_rssi_monitor(priv, false);
+}
+
 static void iwlagn_print_uartmsg(struct iwl_priv *priv,
                                struct iwl_bt_uart_msg *uart_msg)
 {
@@ -1862,6 +1951,8 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
        iwlagn_print_uartmsg(priv, uart_msg);
 
        priv->last_bt_traffic_load = priv->bt_traffic_load;
+       priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
+
        if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
                if (priv->bt_status != coex->bt_status ||
                    priv->last_bt_traffic_load != coex->bt_traffic_load) {
@@ -2321,13 +2412,14 @@ void iwlagn_stop_device(struct iwl_priv *priv)
         * already dead.
         */
        if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) {
-                iwlagn_txq_ctx_stop(priv);
-                iwlagn_rxq_stop(priv);
+               trans_tx_stop(priv);
+               trans_rx_stop(priv);
 
-                /* Power-down device's busmaster DMA clocks */
-                iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-                udelay(5);
-        }
+               /* Power-down device's busmaster DMA clocks */
+               iwl_write_prph(priv, APMG_CLK_DIS_REG,
+                              APMG_CLK_VAL_DMA_CLK_RQT);
+               udelay(5);
+       }
 
        /* Make sure (redundant) we've released our request to stay awake */
        iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
index 85e0828..ebcd13b 100644 (file)
@@ -336,6 +336,12 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
 static void rs_program_fix_rate(struct iwl_priv *priv,
                                struct iwl_lq_sta *lq_sta)
 {
@@ -348,13 +354,15 @@ static void rs_program_fix_rate(struct iwl_priv *priv,
        lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
        lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
 
-       lq_sta->dbg_fixed_rate = priv->dbg_fixed_rate;
+       /* testmode has higher priority to overwirte the fixed rate */
+       if (priv->tm_fixed_rate)
+               lq_sta->dbg_fixed_rate = priv->tm_fixed_rate;
 
        IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
-               lq_sta->lq.sta_id, priv->dbg_fixed_rate);
+               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
 
-       if (priv->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, lq_sta, priv->dbg_fixed_rate);
+       if (lq_sta->dbg_fixed_rate) {
+               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
                iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
                                false);
        }
@@ -1073,7 +1081,8 @@ done:
        if (sta && sta->supp_rates[sband->band])
                rs_rate_scale_perform(priv, skb, sta, lq_sta);
 #ifdef CONFIG_MAC80211_DEBUGFS
-       if (priv->dbg_fixed_rate != lq_sta->dbg_fixed_rate)
+       if ((priv->tm_fixed_rate) &&
+           (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate))
                rs_program_fix_rate(priv, lq_sta);
 #endif
        if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
@@ -2896,7 +2905,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
                lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
        lq_sta->is_agg = 0;
 
-       priv->dbg_fixed_rate = 0;
+       priv->tm_fixed_rate = 0;
 #ifdef CONFIG_MAC80211_DEBUGFS
        lq_sta->dbg_fixed_rate = 0;
 #endif
@@ -3095,7 +3104,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
                        IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
                } else {
                        lq_sta->dbg_fixed_rate = 0;
-                       priv->dbg_fixed_rate = 0;
                        IWL_ERR(priv,
                            "Invalid antenna selection 0x%X, Valid is 0x%X\n",
                            ant_sel_tx, valid_tx_ant);
@@ -3123,9 +3131,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
                return -EFAULT;
 
        if (sscanf(buf, "%x", &parsed_rate) == 1)
-               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = parsed_rate;
+               lq_sta->dbg_fixed_rate = parsed_rate;
        else
-               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = 0;
+               lq_sta->dbg_fixed_rate = 0;
 
        rs_program_fix_rate(priv, lq_sta);
 
@@ -3155,7 +3163,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->total_failed, lq_sta->total_success,
                        lq_sta->active_legacy_rate);
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-                       priv->dbg_fixed_rate);
+                       lq_sta->dbg_fixed_rate);
        desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
            (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
            (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
index c6bb73a..dc64f25 100644 (file)
@@ -30,6 +30,7 @@
 #include "iwl-core.h"
 #include "iwl-agn-calib.h"
 #include "iwl-helpers.h"
+#include "iwl-trans.h"
 
 static int iwlagn_disable_bss(struct iwl_priv *priv,
                              struct iwl_rxon_context *ctx,
@@ -39,7 +40,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
        int ret;
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+       ret = trans_send_cmd_pdu(priv, ctx->rxon_cmd,
+                               CMD_SYNC, sizeof(*send), send);
 
        send->filter_flags = old_filter;
 
@@ -64,7 +66,8 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        send->dev_type = RXON_DEV_TYPE_P2P;
-       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+       ret = trans_send_cmd_pdu(priv, ctx->rxon_cmd,
+                               CMD_SYNC, sizeof(*send), send);
 
        send->filter_flags = old_filter;
        send->dev_type = old_dev_type;
@@ -89,7 +92,8 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv,
        int ret;
 
        send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+       ret = trans_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
+                               sizeof(*send), send);
 
        send->filter_flags = old_filter;
 
@@ -117,7 +121,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
 
-       ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd,
+       ret = trans_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC,
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
@@ -176,8 +180,8 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
                 ctx->staging.ofdm_ht_triple_stream_basic_rates;
        rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
 
-       ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
-                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
+       ret = trans_send_cmd_pdu(priv, ctx->rxon_assoc_cmd,
+                               CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
        return ret;
 }
 
@@ -262,7 +266,7 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
         * Associated RXON doesn't clear the station table in uCode,
         * so we don't need to restore stations etc. after this.
         */
-       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+       ret = trans_send_cmd_pdu(priv, ctx->rxon_cmd, CMD_SYNC,
                      sizeof(struct iwl_rxon_cmd), &ctx->staging);
        if (ret) {
                IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
@@ -670,6 +674,38 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
        ht_conf->single_chain_sufficient = !need_multiple;
 }
 
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+       int ret;
+
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+           iwl_is_any_associated(priv)) {
+               struct iwl_calib_chain_noise_reset_cmd cmd;
+
+               /* clear data for chain noise calibration algorithm */
+               data->chain_noise_a = 0;
+               data->chain_noise_b = 0;
+               data->chain_noise_c = 0;
+               data->chain_signal_a = 0;
+               data->chain_signal_b = 0;
+               data->chain_signal_c = 0;
+               data->beacon_count = 0;
+
+               memset(&cmd, 0, sizeof(cmd));
+               iwl_set_calib_hdr(&cmd.hdr,
+                       priv->_agn.phy_calib_chain_noise_reset_cmd);
+               ret = trans_send_cmd_pdu(priv,
+                                       REPLY_PHY_CALIBRATION_CMD,
+                                       CMD_SYNC, sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv,
+                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+       }
+}
+
 void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
                             struct ieee80211_bss_conf *bss_conf,
@@ -727,6 +763,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
                }
+
+               iwlagn_bt_coex_rssi_monitor(priv);
        }
 
        if (ctx->ht.enabled) {
@@ -776,7 +814,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        iwl_power_update_mode(priv, false);
 
                /* Enable RX differential gain and sensitivity calibrations */
-               iwl_chain_noise_reset(priv);
+               if (!priv->disable_chain_noise_cal)
+                       iwlagn_chain_noise_reset(priv);
                priv->start_calib = 1;
        }
 
index 9b32f83..001622c 100644 (file)
@@ -33,6 +33,7 @@
 #include "iwl-core.h"
 #include "iwl-sta.h"
 #include "iwl-agn.h"
+#include "iwl-trans.h"
 
 static struct iwl_link_quality_cmd *
 iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id)
@@ -180,7 +181,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
        cmd.len[0] = cmd_size;
 
        if (not_empty || send_if_empty)
-               return iwl_send_cmd(priv, &cmd);
+               return trans_send_cmd(priv, &cmd);
        else
                return 0;
 }
index c05a8d9..7d3aad8 100644 (file)
@@ -339,6 +339,16 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
        iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
 }
 
+static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
+                                    struct ieee80211_tx_info *info,
+                                    __le16 fc, __le32 *tx_flags)
+{
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
+           info->flags & IEEE80211_TX_CTL_AMPDU)
+               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
+}
+
 /*
  * handle build REPLY_TX command notification.
  */
@@ -388,7 +398,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
-       priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags);
+       iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags);
 
        tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
        if (ieee80211_is_mgmt(fc)) {
@@ -436,6 +446,16 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
        if (ieee80211_is_data(fc)) {
                tx_cmd->initial_rate_index = 0;
                tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+               if (priv->tm_fixed_rate) {
+                       /*
+                        * rate overwrite by testmode
+                        * we not only send lq command to change rate
+                        * we also re-enforce per data pkt base.
+                        */
+                       tx_cmd->tx_flags &= ~TX_CMD_FLG_STA_RATE_MSK;
+                       memcpy(&tx_cmd->rate_n_flags, &priv->tm_fixed_rate,
+                              sizeof(tx_cmd->rate_n_flags));
+               }
                return;
        }
 
@@ -497,8 +517,7 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
 
        case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_key(keyconf, skb_frag,
-                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+               ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
                IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
                break;
 
@@ -831,88 +850,6 @@ drop_unlock_priv:
        return -1;
 }
 
-static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr, size_t size)
-{
-       ptr->addr = dma_alloc_coherent(priv->bus.dev, size,
-                                      &ptr->dma, GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(priv->bus.dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
-/**
- * iwlagn_hw_txq_ctx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       /* Tx queues */
-       if (priv->txq) {
-               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-                       if (txq_id == priv->cmd_queue)
-                               iwl_cmd_queue_free(priv);
-                       else
-                               iwl_tx_queue_free(priv, txq_id);
-       }
-       iwlagn_free_dma_ptr(priv, &priv->kw);
-
-       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
-
-       /* free tx queue structure */
-       iwl_free_txq_mem(priv);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
-{
-       int ch, txq_id;
-       unsigned long flags;
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       iwlagn_txq_set_sched(priv, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
-               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000))
-                       IWL_ERR(priv, "Failing on timeout while stopping"
-                           " DMA channel %d [0x%08x]", ch,
-                           iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (!priv->txq)
-               return;
-
-       /* Unmap DMA from host system and free skb's */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (txq_id == priv->cmd_queue)
-                       iwl_cmd_queue_unmap(priv);
-               else
-                       iwl_tx_queue_unmap(priv, txq_id);
-}
-
 /*
  * Find first available (lowest unused) Tx Queue, mark it "active".
  * Called only when finding queue for aggregation.
@@ -1171,7 +1108,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 
                iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
 
-               iwlagn_txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq, txq->q.read_ptr);
        }
        return nfreed;
 }
index 2043c8b..06304a6 100644 (file)
@@ -39,6 +39,7 @@
 #include "iwl-agn-hw.h"
 #include "iwl-agn.h"
 #include "iwl-agn-calib.h"
+#include "iwl-trans.h"
 
 #define IWL_AC_UNSET -1
 
@@ -223,7 +224,7 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
        calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
        calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
 
-       return iwl_send_cmd(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 void iwlagn_rx_calib_result(struct iwl_priv *priv,
@@ -321,7 +322,8 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
                /* coexistence is disabled */
                memset(&coex_cmd, 0, sizeof(coex_cmd));
        }
-       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
+       return trans_send_cmd_pdu(priv,
+                               COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
                                sizeof(coex_cmd), &coex_cmd);
 }
 
@@ -353,7 +355,8 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
 
        memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
                sizeof(iwlagn_bt_prio_tbl));
-       if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PRIO_TABLE,
+       if (trans_send_cmd_pdu(priv,
+                               REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
                                sizeof(prio_tbl_cmd), &prio_tbl_cmd))
                IWL_ERR(priv, "failed to send BT prio tbl command\n");
 }
@@ -365,7 +368,8 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
 
        env_cmd.action = action;
        env_cmd.type = type;
-       ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+       ret = trans_send_cmd_pdu(priv,
+                              REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
                               sizeof(env_cmd), &env_cmd);
        if (ret)
                IWL_ERR(priv, "failed to send BT env command\n");
@@ -403,7 +407,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
                       priv->scd_bc_tbls.dma >> 10);
 
        /* Enable DMA channel */
-       for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
                iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
                                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
                                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
index 7e6c463..38a1e4f 100644 (file)
@@ -129,6 +129,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        struct iwl_tx_beacon_cmd *tx_beacon_cmd;
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_BEACON,
+               .flags = CMD_SYNC,
        };
        struct ieee80211_tx_info *info;
        u32 frame_size;
@@ -205,7 +206,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        cmd.data[1] = priv->beacon_skb->data;
        cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
 
-       return iwl_send_cmd_sync(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 static void iwl_bg_beacon_update(struct work_struct *work)
@@ -578,7 +579,8 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 
                if (reclaim) {
                        /* Invoke any callbacks, transfer the buffer to caller,
-                        * and fire off the (possibly) blocking iwl_send_cmd()
+                        * and fire off the (possibly) blocking
+                        * trans_send_cmd()
                         * as we reclaim the driver command queue */
                        if (rxb->page)
                                iwl_tx_cmd_complete(priv, rxb);
@@ -1563,7 +1565,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        release_firmware(ucode_raw);
 }
 
-static const char *desc_lookup_text[] = {
+static const char * const desc_lookup_text[] = {
        "OK",
        "FAIL",
        "BAD_PARAM",
@@ -1587,7 +1589,7 @@ static const char *desc_lookup_text[] = {
        "NMI_INTERRUPT_DATA_ACTION_PT",
        "NMI_TRM_HW_ER",
        "NMI_INTERRUPT_TRM",
-       "NMI_INTERRUPT_BREAK_POINT"
+       "NMI_INTERRUPT_BREAK_POINT",
        "DEBUG_0",
        "DEBUG_1",
        "DEBUG_2",
@@ -1940,8 +1942,9 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                adv_cmd.critical_temperature_exit =
                        cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
 
-               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                                      sizeof(adv_cmd), &adv_cmd);
+               ret = trans_send_cmd_pdu(priv,
+                                      REPLY_CT_KILL_CONFIG_CMD,
+                                      CMD_SYNC, sizeof(adv_cmd), &adv_cmd);
                if (ret)
                        IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
                else
@@ -1955,8 +1958,9 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
                cmd.critical_temperature_R =
                        cpu_to_le32(priv->hw_params.ct_kill_threshold);
 
-               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                                      sizeof(cmd), &cmd);
+               ret = trans_send_cmd_pdu(priv,
+                                      REPLY_CT_KILL_CONFIG_CMD,
+                                      CMD_SYNC, sizeof(cmd), &cmd);
                if (ret)
                        IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
                else
@@ -1980,7 +1984,7 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
        calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
        calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg);
 
-       return iwl_send_cmd(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 
@@ -2011,11 +2015,18 @@ int iwl_alive_start(struct iwl_priv *priv)
        if (priv->cfg->bt_params &&
            priv->cfg->bt_params->advanced_bt_coexist) {
                /* Configure Bluetooth device coexistence support */
+               if (priv->cfg->bt_params->bt_sco_disable)
+                       priv->bt_enable_pspoll = false;
+               else
+                       priv->bt_enable_pspoll = true;
+
                priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
                priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
                priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
                iwlagn_send_advance_bt_config(priv);
                priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+               priv->cur_rssi_ctx = NULL;
+
                iwlagn_send_prio_tbl(priv);
 
                /* FIXME: w/a to force change uCode BT state machine */
@@ -2098,6 +2109,8 @@ static void __iwl_down(struct iwl_priv *priv)
 
        /* reset BT coex data */
        priv->bt_status = 0;
+       priv->cur_rssi_ctx = NULL;
+       priv->bt_is_sco = 0;
        if (priv->cfg->bt_params)
                priv->bt_traffic_load =
                         priv->cfg->bt_params->bt_init_traffic_load;
@@ -2273,6 +2286,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
        u8 bt_ci_compliance;
        u8 bt_load;
        u8 bt_status;
+       bool bt_is_sco;
 
        lockdep_assert_held(&priv->mutex);
 
@@ -2293,6 +2307,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
        bt_ci_compliance = priv->bt_ci_compliance;
        bt_load = priv->bt_traffic_load;
        bt_status = priv->bt_status;
+       bt_is_sco = priv->bt_is_sco;
 
        __iwl_down(priv);
 
@@ -2300,6 +2315,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
        priv->bt_ci_compliance = bt_ci_compliance;
        priv->bt_traffic_load = bt_load;
        priv->bt_status = bt_status;
+       priv->bt_is_sco = bt_is_sco;
 }
 
 static void iwl_bg_restart(struct work_struct *data)
@@ -3326,6 +3342,29 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
        kfree(priv->beacon_cmd);
 }
 
+static void iwl_mac_rssi_callback(struct ieee80211_hw *hw,
+                          enum ieee80211_rssi_event rssi_event)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+
+       if (priv->cfg->bt_params &&
+                       priv->cfg->bt_params->advanced_bt_coexist) {
+               if (rssi_event == RSSI_EVENT_LOW)
+                       priv->bt_enable_pspoll = true;
+               else if (rssi_event == RSSI_EVENT_HIGH)
+                       priv->bt_enable_pspoll = false;
+
+               iwlagn_send_advance_bt_config(priv);
+       } else {
+               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+                               "ignoring RSSI callback\n");
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
 struct ieee80211_ops iwlagn_hw_ops = {
        .tx = iwlagn_mac_tx,
        .start = iwlagn_mac_start,
@@ -3351,6 +3390,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
        .offchannel_tx = iwl_mac_offchannel_tx,
        .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
+       .rssi_callback = iwl_mac_rssi_callback,
        CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
        CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
 };
@@ -3709,8 +3749,8 @@ void __devexit iwl_remove(struct iwl_priv * priv)
 
        iwl_dealloc_ucode(priv);
 
-       priv->trans.ops->rx_free(priv);
-       iwlagn_hw_txq_ctx_free(priv);
+       trans_rx_free(priv);
+       trans_tx_free(priv);
 
        iwl_eeprom_free(priv);
 
index 4351151..5f58b44 100644 (file)
@@ -109,9 +109,6 @@ extern struct iwl_cfg iwl135_bg_cfg;
 extern struct iwl_cfg iwl135_bgn_cfg;
 
 extern struct iwl_mod_params iwlagn_mod_params;
-extern struct iwl_hcmd_ops iwlagn_hcmd;
-extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
-extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
 
 extern struct ieee80211_ops iwlagn_hw_ops;
 
@@ -180,8 +177,6 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
 int iwlagn_send_tx_power(struct iwl_priv *priv);
 void iwlagn_temperature(struct iwl_priv *priv);
 u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
-const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
-                                  size_t offset);
 int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_hw_nic_init(struct iwl_priv *priv);
 int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
@@ -193,12 +188,12 @@ void iwlagn_rx_queue_restock(struct iwl_priv *priv);
 void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwlagn_rx_replenish(struct iwl_priv *priv);
 void iwlagn_rx_replenish_now(struct iwl_priv *priv);
-int iwlagn_rxq_stop(struct iwl_priv *priv);
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 void iwl_setup_rx_handlers(struct iwl_priv *priv);
 
 /* tx */
-void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+                               int index);
 int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
                                 struct iwl_tx_queue *txq,
                                 dma_addr_t addr, u16 len, u8 reset);
@@ -217,8 +212,6 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
 void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb);
 int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
-void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
-void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
 
 static inline u32 iwl_tx_status_to_mac80211(u32 status)
 {
@@ -257,6 +250,12 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
 int iwlagn_set_pan_params(struct iwl_priv *priv);
+void iwlagn_gain_computation(struct iwl_priv *priv,
+                u32 average_noise[NUM_RX_CHAINS],
+                u16 min_average_noise_antenna_i,
+                u32 min_average_noise,
+                u8 default_chain);
+
 
 /* bt coex */
 void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
@@ -265,6 +264,8 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
 void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
 void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
 void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
+void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 const char *iwl_get_tx_fail_reason(u32 status);
index 8a2edf8..ee25637 100644 (file)
@@ -1931,6 +1931,9 @@ struct iwl_bt_cmd {
 /* Disable Sync PSPoll on SCO/eSCO */
 #define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE       BIT(7)
 
+#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD       -75 /* dBm */
+#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD       -65 /* dBm */
+
 #define IWLAGN_BT_PRIO_BOOST_MAX       0xFF
 #define IWLAGN_BT_PRIO_BOOST_MIN       0x00
 #define IWLAGN_BT_PRIO_BOOST_DEFAULT   0xF0
index f91e306..fa3d5ba 100644 (file)
@@ -42,6 +42,7 @@
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
 #include "iwl-agn.h"
+#include "iwl-trans.h"
 
 u32 iwl_debug_level;
 
@@ -375,8 +376,8 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        le32_to_cpu(ctx->timing.beacon_init_val),
                        le16_to_cpu(ctx->timing.atim_window));
 
-       return iwl_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
-                               sizeof(ctx->timing), &ctx->timing);
+       return trans_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+                               CMD_SYNC, sizeof(ctx->timing), &ctx->timing);
 }
 
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
@@ -1131,8 +1132,8 @@ void iwl_send_bt_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "BT coex %s\n",
                (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
 
-       if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                            sizeof(struct iwl_bt_cmd), &bt_cmd))
+       if (trans_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                            CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
                IWL_ERR(priv, "failed to send BT Coex Config\n");
 }
 
@@ -1144,11 +1145,13 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
        };
 
        if (flags & CMD_ASYNC)
-               return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD,
+               return trans_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                             CMD_ASYNC,
                                               sizeof(struct iwl_statistics_cmd),
-                                              &statistics_cmd, NULL);
+                                              &statistics_cmd);
        else
-               return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+               return trans_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
+                                       CMD_SYNC,
                                        sizeof(struct iwl_statistics_cmd),
                                        &statistics_cmd);
 }
@@ -1370,12 +1373,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
 }
 
-void iwl_free_txq_mem(struct iwl_priv *priv)
-{
-       kfree(priv->txq);
-       priv->txq = NULL;
-}
-
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
 #define IWL_TRAFFIC_DUMP_SIZE  (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
index 6c21de9..692c30c 100644 (file)
@@ -80,31 +80,6 @@ struct iwl_cmd;
 
 #define IWL_CMD(x) case x: return #x
 
-struct iwl_hcmd_utils_ops {
-       u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
-       void (*gain_computation)(struct iwl_priv *priv,
-                       u32 *average_noise,
-                       u16 min_average_noise_antennat_i,
-                       u32 min_average_noise,
-                       u8 default_chain);
-       void (*chain_noise_reset)(struct iwl_priv *priv);
-       void (*tx_cmd_protection)(struct iwl_priv *priv,
-                                 struct ieee80211_tx_info *info,
-                                 __le16 fc, __le32 *tx_flags);
-       int  (*calc_rssi)(struct iwl_priv *priv,
-                         struct iwl_rx_phy_res *rx_resp);
-       int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
-};
-
-struct iwl_apm_ops {
-       int (*init)(struct iwl_priv *priv);
-       void (*config)(struct iwl_priv *priv);
-};
-
-struct iwl_temp_ops {
-       void (*temperature)(struct iwl_priv *priv);
-};
-
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
@@ -118,17 +93,14 @@ struct iwl_lib_ops {
        int (*is_valid_rtc_data_addr)(u32 addr);
        int (*set_channel_switch)(struct iwl_priv *priv,
                                  struct ieee80211_channel_switch *ch_switch);
-       /* power management */
-       struct iwl_apm_ops apm_ops;
-
-       /* power */
-       void (*update_chain_flags)(struct iwl_priv *priv);
+       /* device specific configuration */
+       void (*nic_config)(struct iwl_priv *priv);
 
        /* eeprom operations (as defined in iwl-eeprom.h) */
        struct iwl_eeprom_ops eeprom_ops;
 
        /* temperature */
-       struct iwl_temp_ops temp_ops;
+       void (*temperature)(struct iwl_priv *priv);
 };
 
 /* NIC specific ops */
@@ -138,7 +110,6 @@ struct iwl_nic_ops {
 
 struct iwl_ops {
        const struct iwl_lib_ops *lib;
-       const struct iwl_hcmd_utils_ops *utils;
        const struct iwl_nic_ops *nic;
 };
 
@@ -328,8 +299,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 int iwl_mac_change_interface(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
                             enum nl80211_iftype newtype, bool newp2p);
-void iwl_free_txq_mem(struct iwl_priv *priv);
-
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
 void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -371,8 +340,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
 /*****************************************************
 * RX
 ******************************************************/
-void iwl_cmd_queue_free(struct iwl_priv *priv);
-void iwl_cmd_queue_unmap(struct iwl_priv *priv);
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
                                  struct iwl_rx_queue *q);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
@@ -386,10 +353,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
 * TX
 ******************************************************/
 void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
 int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
                          int count, int slots_num, u32 id);
-void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
 void iwl_setup_watchdog(struct iwl_priv *priv);
 /*****************************************************
  * TX power
@@ -440,16 +405,9 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
  *****************************************************/
 
 const char *get_cmd_string(u8 cmd);
-int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
-                                  struct iwl_host_cmd *cmd);
 int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id,
+int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags,
                                  u16 len, const void *data);
-int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
-                          const void *data,
-                          void (*callback)(struct iwl_priv *priv,
-                                           struct iwl_device_cmd *cmd,
-                                           struct iwl_rx_packet *pkt));
 
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
 
index c6560e9..424c45c 100644 (file)
@@ -260,11 +260,9 @@ struct iwl_channel_info {
 
 enum {
        CMD_SYNC = 0,
-       CMD_SIZE_NORMAL = 0,
-       CMD_NO_SKB = 0,
-       CMD_ASYNC = (1 << 1),
-       CMD_WANT_SKB = (1 << 2),
-       CMD_MAPPED = (1 << 3),
+       CMD_ASYNC = BIT(0),
+       CMD_WANT_SKB = BIT(1),
+       CMD_ON_DEMAND = BIT(2),
 };
 
 #define DEF_CMD_PAYLOAD_SIZE 320
@@ -297,6 +295,16 @@ enum iwl_hcmd_dataflag {
        IWL_HCMD_DFL_NOCOPY     = BIT(0),
 };
 
+/**
+ * struct iwl_host_cmd - Host command to the uCode
+ * @data: array of chunks that composes the data of the host command
+ * @reply_page: pointer to the page that holds the response to the host command
+ * @callback:
+ * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
+ * @len: array of the lenths of the chunks in data
+ * @dataflags:
+ * @id: id of the host command
+ */
 struct iwl_host_cmd {
        const void *data[IWL_MAX_CMD_TFDS];
        unsigned long reply_page;
@@ -634,7 +642,6 @@ struct iwl_sensitivity_ranges {
 /**
  * struct iwl_hw_params
  * @max_txq_num: Max # Tx queues supported
- * @dma_chnl_num: Number of Tx DMA/FIFO channels
  * @scd_bc_tbls_size: size of scheduler byte count tables
  * @tfd_size: TFD size
  * @tx/rx_chains_num: Number of TX/RX chains
@@ -656,7 +663,6 @@ struct iwl_sensitivity_ranges {
  */
 struct iwl_hw_params {
        u8 max_txq_num;
-       u8 dma_chnl_num;
        u16 scd_bc_tbls_size;
        u32 tfd_size;
        u8  tx_chains_num;
@@ -696,8 +702,6 @@ struct iwl_hw_params {
  ****************************************************************************/
 extern void iwl_update_chain_flags(struct iwl_priv *priv);
 extern const u8 iwl_bcast_addr[ETH_ALEN];
-extern int iwl_rxq_stop(struct iwl_priv *priv);
-extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
 extern int iwl_queue_space(const struct iwl_queue *q);
 static inline int iwl_queue_used(const struct iwl_queue *q, int i)
 {
@@ -1233,19 +1237,37 @@ struct iwl_trans;
  * struct iwl_trans_ops - transport specific operations
 
  * @rx_init: inits the rx memory, allocate it if needed
+ * @rx_stop: stop the rx
  * @rx_free: frees the rx memory
  * @tx_init:inits the tx memory, allocate if needed
+ * @tx_stop: stop the tx
+ * @tx_free: frees the tx memory
+ * @send_cmd:send a host command
+ * @send_cmd_pdu:send a host command: flags can be CMD_*
  */
 struct iwl_trans_ops {
        int (*rx_init)(struct iwl_priv *priv);
+       int (*rx_stop)(struct iwl_priv *priv);
        void (*rx_free)(struct iwl_priv *priv);
+
        int (*tx_init)(struct iwl_priv *priv);
+       int (*tx_stop)(struct iwl_priv *priv);
+       void (*tx_free)(struct iwl_priv *priv);
+
+       int (*send_cmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+
+       int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
+                    const void *data);
 };
 
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
 };
 
+/* uCode ownership */
+#define IWL_OWNERSHIP_DRIVER   0
+#define IWL_OWNERSHIP_TM       1
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1334,6 +1356,10 @@ struct iwl_priv {
        int fw_index;                   /* firmware we're trying to load */
        u32 ucode_ver;                  /* version of ucode, copy of
                                           iwl_ucode.ver */
+
+       /* uCode owner: default: IWL_OWNERSHIP_DRIVER */
+       u8 ucode_owner;
+
        struct fw_img ucode_rt;
        struct fw_img ucode_init;
 
@@ -1509,6 +1535,9 @@ struct iwl_priv {
        u16 dynamic_frag_thresh;
        u8 bt_ci_compliance;
        struct work_struct bt_traffic_change_work;
+       bool bt_enable_pspoll;
+       struct iwl_rxon_context *cur_rssi_ctx;
+       bool bt_is_sco;
 
        struct iwl_hw_params hw_params;
 
@@ -1577,7 +1606,7 @@ struct iwl_priv {
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
        struct iwl_testmode_trace testmode_trace;
 #endif
-       u32 dbg_fixed_rate;
+       u32 tm_fixed_rate;
 
 }; /*iwl_priv */
 
index 768d0ee..eee97bc 100644 (file)
@@ -407,11 +407,6 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
        return -EINVAL;
 }
 
-const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
-{
-       return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset);
-}
-
 u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
 {
        if (!priv->eeprom)
@@ -449,7 +444,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
        e = (__le16 *)priv->eeprom;
 
-       priv->cfg->ops->lib->apm_ops.init(priv);
+       iwl_apm_init(priv);
 
        ret = iwl_eeprom_verify_signature(priv);
        if (ret < 0) {
index 804f910..e4bf8ac 100644 (file)
@@ -292,7 +292,6 @@ extern const u8 iwl_eeprom_band_1[14];
 
 struct iwl_eeprom_ops {
        const u32 regulatory_bands[7];
-       const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
        void (*update_enhanced_txpower) (struct iwl_priv *priv);
 };
 
index 6dfa806..0ad60b3 100644 (file)
 #define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
 
 /* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH50_TCSR_CHNL_NUM                            (8)
+#define FH_TCSR_CHNL_NUM                            (8)
 
 /* TCSR: tx_config register values */
 #define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl)      \
index 107b38e..6cff8c1 100644 (file)
@@ -143,9 +143,6 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
        int ret;
 
-       if (WARN_ON(!(cmd->flags & CMD_ASYNC)))
-               return -EINVAL;
-
        /* An asynchronous command can not expect an SKB to be set. */
        if (WARN_ON(cmd->flags & CMD_WANT_SKB))
                return -EINVAL;
@@ -166,16 +163,13 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        return 0;
 }
 
-int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
        int cmd_idx;
        int ret;
 
        lockdep_assert_held(&priv->mutex);
 
-       if (WARN_ON(cmd->flags & CMD_ASYNC))
-               return -EINVAL;
-
         /* A synchronous command can not have a callback set. */
        if (WARN_ON(cmd->callback))
                return -EINVAL;
@@ -263,31 +257,15 @@ int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        return iwl_send_cmd_sync(priv, cmd);
 }
 
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
-{
-       struct iwl_host_cmd cmd = {
-               .id = id,
-               .len = { len, },
-               .data = { data, },
-       };
-
-       return iwl_send_cmd_sync(priv, &cmd);
-}
-
-int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
-                          u8 id, u16 len, const void *data,
-                          void (*callback)(struct iwl_priv *priv,
-                                           struct iwl_device_cmd *cmd,
-                                           struct iwl_rx_packet *pkt))
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len,
+                    const void *data)
 {
        struct iwl_host_cmd cmd = {
                .id = id,
                .len = { len, },
                .data = { data, },
+               .flags = flags,
        };
 
-       cmd.flags |= CMD_ASYNC;
-       cmd.callback = callback;
-
-       return iwl_send_cmd_async(priv, &cmd);
+       return iwl_send_cmd(priv, &cmd);
 }
index ff08da0..60e4169 100644 (file)
@@ -40,6 +40,7 @@
 #include "iwl-core.h"
 #include "iwl-agn.h"
 #include "iwl-io.h"
+#include "iwl-trans.h"
 
 /* Throughput          OFF time(ms)    ON time (ms)
  *     >300                    25              25
@@ -111,7 +112,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
        if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
                iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
 
-       return iwl_send_cmd(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 /* Set led pattern command */
index 565e57e..64ff40a 100644 (file)
@@ -42,6 +42,7 @@
 #include "iwl-commands.h"
 #include "iwl-debug.h"
 #include "iwl-power.h"
+#include "iwl-trans.h"
 
 /*
  * Setting power level allows the card to go to sleep when not busy.
@@ -334,7 +335,7 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
                        le32_to_cpu(cmd->sleep_interval[3]),
                        le32_to_cpu(cmd->sleep_interval[4]));
 
-       return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
+       return trans_send_cmd_pdu(priv, POWER_TABLE_CMD, CMD_SYNC,
                                sizeof(struct iwl_powertable_cmd), cmd);
 }
 
@@ -405,9 +406,9 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
                if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK))
                        clear_bit(STATUS_POWER_PMI, &priv->status);
 
-               if (priv->cfg->ops->lib->update_chain_flags && update_chains)
-                       priv->cfg->ops->lib->update_chain_flags(priv);
-               else if (priv->cfg->ops->lib->update_chain_flags)
+               if (update_chains)
+                       iwl_update_chain_flags(priv);
+               else
                        IWL_DEBUG_POWER(priv,
                                        "Cannot update the power, chain noise "
                                        "calibration running: %d\n",
index 87148bb..f3f3efe 100644 (file)
@@ -624,8 +624,8 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
                iwl_rx_calc_noise(priv);
                queue_work(priv->workqueue, &priv->run_time_calib_work);
        }
-       if (priv->cfg->ops->lib->temp_ops.temperature && change)
-               priv->cfg->ops->lib->temp_ops.temperature(priv);
+       if (priv->cfg->ops->lib->temperature && change)
+               priv->cfg->ops->lib->temperature(priv);
 }
 
 static void iwl_rx_reply_statistics(struct iwl_priv *priv,
@@ -902,6 +902,47 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
        return decrypt_out;
 }
 
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwlagn_calc_rssi(struct iwl_priv *priv,
+                            struct iwl_rx_phy_res *rx_resp)
+{
+       /* data from PHY/DSP regarding signal strength, etc.,
+        *   contents are always there, not configurable by host
+        */
+       struct iwlagn_non_cfg_phy *ncphy =
+               (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+       u8 agc;
+
+       val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
+       agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
+
+       /* Find max rssi among 3 possible receivers.
+        * These values are measured by the digital signal processor (DSP).
+        * They should stay fairly constant even as the signal strength varies,
+        *   if the radio's automatic gain control (AGC) is working right.
+        * AGC value (see below) will provide the "interesting" info.
+        */
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
+       rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
+               IWLAGN_OFDM_RSSI_A_BIT_POS;
+       rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
+               IWLAGN_OFDM_RSSI_B_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
+       rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
+               IWLAGN_OFDM_RSSI_C_BIT_POS;
+
+       max_rssi = max_t(u32, rssi_a, rssi_b);
+       max_rssi = max_t(u32, max_rssi, rssi_c);
+
+       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+               rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+       /* dBm = max_rssi dB - agc dB - constant.
+        * Higher AGC (higher radio gain) means lower signal. */
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
+}
+
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
 static void iwl_rx_reply_rx(struct iwl_priv *priv,
@@ -983,7 +1024,7 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
        priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
 
        /* Find max signal strength (dBm) among 3 antenna/receiver chains */
-       rx_status.signal = priv->cfg->ops->utils->calc_rssi(priv, phy_res);
+       rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
 
        iwl_dbg_log_rx_data_frame(priv, len, header);
        IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
index 438eecd..f6ebe29 100644 (file)
@@ -37,6 +37,7 @@
 #include "iwl-io.h"
 #include "iwl-helpers.h"
 #include "iwl-agn.h"
+#include "iwl-trans.h"
 
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
@@ -61,7 +62,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
        struct iwl_rx_packet *pkt;
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_ABORT_CMD,
-               .flags = CMD_WANT_SKB,
+               .flags = CMD_SYNC | CMD_WANT_SKB,
        };
 
        /* Exit instantly with error when device is not ready
@@ -74,7 +75,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
            test_bit(STATUS_EXIT_PENDING, &priv->status))
                return -EIO;
 
-       ret = iwl_send_cmd_sync(priv, &cmd);
+       ret = trans_send_cmd(priv, &cmd);
        if (ret)
                return ret;
 
@@ -349,9 +350,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
 
        lockdep_assert_held(&priv->mutex);
 
-       if (WARN_ON(!priv->cfg->ops->utils->request_scan))
-               return -EOPNOTSUPP;
-
        cancel_delayed_work(&priv->scan_check);
 
        if (!iwl_is_ready_rf(priv)) {
@@ -380,7 +378,7 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
        priv->scan_start = jiffies;
        priv->scan_band = band;
 
-       ret = priv->cfg->ops->utils->request_scan(priv, vif);
+       ret = iwlagn_request_scan(priv, vif);
        if (ret) {
                clear_bit(STATUS_SCANNING, &priv->status);
                priv->scan_type = IWL_SCAN_NORMAL;
index 7df2814..65386e5 100644 (file)
@@ -35,6 +35,8 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
+#include "iwl-trans.h"
+#include "iwl-agn.h"
 
 /* priv->sta_lock must be held */
 static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
@@ -132,6 +134,16 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
 
 }
 
+static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
+       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+       memcpy(addsta, cmd, size);
+       /* resrved in 5000 */
+       addsta->rate_n_flags = cpu_to_le16(0);
+       return size;
+}
+
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags)
 {
@@ -155,8 +167,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                might_sleep();
        }
 
-       cmd.len[0] = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
-       ret = iwl_send_cmd(priv, &cmd);
+       cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data);
+       ret = trans_send_cmd(priv, &cmd);
 
        if (ret || (flags & CMD_ASYNC))
                return ret;
@@ -412,7 +424,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 
        cmd.flags |= CMD_WANT_SKB;
 
-       ret = iwl_send_cmd(priv, &cmd);
+       ret = trans_send_cmd(priv, &cmd);
 
        if (ret)
                return ret;
@@ -781,7 +793,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                return -EINVAL;
 
        if (is_lq_table_valid(priv, ctx, lq))
-               ret = iwl_send_cmd(priv, &cmd);
+               ret = trans_send_cmd(priv, &cmd);
        else
                ret = -EINVAL;
 
index c00aa5a..77ed1c2 100644 (file)
@@ -76,7 +76,7 @@
 #include "iwl-io.h"
 #include "iwl-agn.h"
 #include "iwl-testmode.h"
-
+#include "iwl-trans.h"
 
 /* The TLVs used in the gnl message policy between the kernel module and
  * user space application. iwl_testmode_gnl_msg_policy is to be carried
@@ -105,6 +105,7 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
 
        [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
 
+       [IWL_TM_ATTR_UCODE_OWNER] = { .type = NLA_U8, },
 };
 
 /*
@@ -232,6 +233,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
                return -ENOMSG;
        }
 
+       cmd.flags = CMD_ON_DEMAND;
        cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
        cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
        cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
@@ -239,7 +241,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
        IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
                                " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
        /* ok, let's submit the command to ucode */
-       return iwl_send_cmd(priv, &cmd);
+       return trans_send_cmd(priv, &cmd);
 }
 
 
@@ -452,7 +454,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                                       "Error finding fixrate setting\n");
                        return -ENOMSG;
                }
-               priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+               priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
                break;
 
        default:
@@ -586,6 +588,42 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
        return -ENOBUFS;
 }
 
+/*
+ * This function handles the user application switch ucode ownership.
+ *
+ * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and
+ * decide who the current owner of the uCode
+ *
+ * If the current owner is OWNERSHIP_TM, then the only host command
+ * can deliver to uCode is from testmode, all the other host commands
+ * will dropped.
+ *
+ * default driver is the owner of uCode in normal operational mode
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+       struct iwl_priv *priv = hw->priv;
+       u8 owner;
+
+       if (!tb[IWL_TM_ATTR_UCODE_OWNER]) {
+               IWL_DEBUG_INFO(priv, "Error finding ucode owner\n");
+               return -ENOMSG;
+       }
+
+       owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]);
+       if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM))
+               priv->ucode_owner = owner;
+       else {
+               IWL_DEBUG_INFO(priv, "Invalid owner\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
 /* The testmode gnl message handler that takes the gnl message from the
  * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
  * invoke the corresponding handlers.
@@ -607,7 +645,7 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, struct nlattr **tb,
  */
 int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
 {
-       struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
+       struct nlattr *tb[IWL_TM_ATTR_MAX];
        struct iwl_priv *priv = hw->priv;
        int result;
 
@@ -655,6 +693,11 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
                result = iwl_testmode_trace(hw, tb);
                break;
 
+       case IWL_TM_CMD_APP2DEV_OWNERSHIP:
+               IWL_DEBUG_INFO(priv, "testmode change uCode ownership\n");
+               result = iwl_testmode_ownership(hw, tb);
+               break;
+
        default:
                IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
                result = -ENOSYS;
index d825188..b980bda 100644 (file)
  * @IWL_TM_CMD_DEV2APP_EEPROM_RSP:
  *     commands from kernel space to carry the eeprom response
  *     to user application
+ * @IWL_TM_CMD_APP2DEV_OWNERSHIP:
+ *     commands from user application to own change the ownership of the uCode
+ *     if application has the ownership, the only host command from
+ *     testmode will deliver to uCode. Default owner is driver
  */
 enum iwl_tm_cmd_t {
        IWL_TM_CMD_APP2DEV_UCODE                = 1,
@@ -121,7 +125,8 @@ enum iwl_tm_cmd_t {
        IWL_TM_CMD_DEV2APP_SYNC_RSP             = 14,
        IWL_TM_CMD_DEV2APP_UCODE_RX_PKT         = 15,
        IWL_TM_CMD_DEV2APP_EEPROM_RSP           = 16,
-       IWL_TM_CMD_MAX                          = 17,
+       IWL_TM_CMD_APP2DEV_OWNERSHIP            = 17,
+       IWL_TM_CMD_MAX                          = 18,
 };
 
 /*
@@ -187,6 +192,10 @@ enum iwl_tm_cmd_t {
  *     The mandatory fields are:
  *     IWL_TM_ATTR_FIXRATE for the fixed rate
  *
+ * @IWL_TM_ATTR_UCODE_OWNER:
+ *     When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_OWNERSHIP,
+ *     The mandatory fields are:
+ *     IWL_TM_ATTR_UCODE_OWNER for the new owner
  */
 enum iwl_tm_attr_t {
        IWL_TM_ATTR_NOT_APPLICABLE              = 0,
@@ -203,7 +212,8 @@ enum iwl_tm_attr_t {
        IWL_TM_ATTR_TRACE_SIZE                  = 11,
        IWL_TM_ATTR_TRACE_DUMP                  = 12,
        IWL_TM_ATTR_FIXRATE                     = 13,
-       IWL_TM_ATTR_MAX                         = 14,
+       IWL_TM_ATTR_UCODE_OWNER                 = 14,
+       IWL_TM_ATTR_MAX                         = 15,
 };
 
 /* uCode trace buffer */
index 7b7b97d..d760857 100644 (file)
@@ -66,6 +66,7 @@
 #include "iwl-helpers.h"
 /*TODO remove uneeded includes when the transport layer tx_free will be here */
 #include "iwl-agn.h"
+#include "iwl-core.h"
 
 static int iwl_trans_rx_alloc(struct iwl_priv *priv)
 {
@@ -188,7 +189,15 @@ static void iwl_trans_rx_free(struct iwl_priv *priv)
        rxq->rb_stts = NULL;
 }
 
-/* TODO:remove this code duplication */
+static int iwl_trans_rx_stop(struct iwl_priv *priv)
+{
+
+       /* stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       return iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
 static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
                                    struct iwl_dma_ptr *ptr, size_t size)
 {
@@ -203,6 +212,16 @@ static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
        return 0;
 }
 
+static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(priv->bus.dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
 static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                      int slots_num, u32 txq_id)
 {
@@ -212,6 +231,8 @@ static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
        if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds))
                return -EINVAL;
 
+       txq->q.n_window = slots_num;
+
        txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num,
                            GFP_KERNEL);
        txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num,
@@ -306,6 +327,90 @@ static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
        return 0;
 }
 
+/**
+ * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+
+       if (!q->n_bd)
+               return;
+
+       while (q->write_ptr != q->read_ptr) {
+               /* The read_ptr needs to bound by q->n_window */
+               iwlagn_txq_free_tfd(priv, txq, get_cmd_index(q, q->read_ptr));
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+       }
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct device *dev = priv->bus.dev;
+       int i;
+       if (WARN_ON(!txq))
+               return;
+
+       iwl_tx_queue_unmap(priv, txq_id);
+
+       /* De-alloc array of command/tx buffers */
+       for (i = 0; i < txq->q.n_window; i++)
+               kfree(txq->cmd[i]);
+
+       /* De-alloc circular buffer of TFDs */
+       if (txq->q.n_bd) {
+               dma_free_coherent(dev, priv->hw_params.tfd_size *
+                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+       }
+
+       /* De-alloc array of per-TFD driver data */
+       kfree(txq->txb);
+       txq->txb = NULL;
+
+       /* deallocate arrays */
+       kfree(txq->cmd);
+       kfree(txq->meta);
+       txq->cmd = NULL;
+       txq->meta = NULL;
+
+       /* 0-fill queue descriptor structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+static void iwl_trans_tx_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       /* Tx queues */
+       if (priv->txq) {
+               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+                       iwl_tx_queue_free(priv, txq_id);
+       }
+
+       kfree(priv->txq);
+       priv->txq = NULL;
+
+       iwlagn_free_dma_ptr(priv, &priv->kw);
+
+       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
+}
+
 /**
  * iwl_trans_tx_alloc - allocate TX context
  * Allocate all Tx DMA structures and initialize them
@@ -362,7 +467,7 @@ static int iwl_trans_tx_alloc(struct iwl_priv *priv)
        return 0;
 
 error:
-       iwlagn_hw_txq_ctx_free(priv);
+       trans_tx_free(priv);
 
        return ret;
 }
@@ -406,15 +511,58 @@ static int iwl_trans_tx_init(struct iwl_priv *priv)
 error:
        /*Upon error, free only if we allocated something */
        if (alloc)
-               iwlagn_hw_txq_ctx_free(priv);
+               trans_tx_free(priv);
        return ret;
 }
 
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+static int iwl_trans_tx_stop(struct iwl_priv *priv)
+{
+       int ch, txq_id;
+       unsigned long flags;
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       iwlagn_txq_set_sched(priv, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                   1000))
+                       IWL_ERR(priv, "Failing on timeout while stopping"
+                           " DMA channel %d [0x%08x]", ch,
+                           iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG));
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (!priv->txq) {
+               IWL_WARN(priv, "Stopping tx queues that aren't allocated...");
+               return 0;
+       }
+
+       /* Unmap DMA from host system and free skb's */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+               iwl_tx_queue_unmap(priv, txq_id);
+
+       return 0;
+}
+
 static const struct iwl_trans_ops trans_ops = {
        .rx_init = iwl_trans_rx_init,
+       .rx_stop = iwl_trans_rx_stop,
        .rx_free = iwl_trans_rx_free,
 
        .tx_init = iwl_trans_tx_init,
+       .tx_stop = iwl_trans_tx_stop,
+       .tx_free = iwl_trans_tx_free,
+
+       .send_cmd = iwl_send_cmd,
+       .send_cmd_pdu = iwl_send_cmd_pdu,
 };
 
 void iwl_trans_register(struct iwl_trans *trans)
index bec494c..111acca 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+static inline int trans_rx_init(struct iwl_priv *priv)
+{
+       return priv->trans.ops->rx_init(priv);
+}
+
+static inline int trans_rx_stop(struct iwl_priv *priv)
+{
+       return priv->trans.ops->rx_stop(priv);
+}
+
+static inline void trans_rx_free(struct iwl_priv *priv)
+{
+       priv->trans.ops->rx_free(priv);
+}
+
+static inline int trans_tx_init(struct iwl_priv *priv)
+{
+       return priv->trans.ops->tx_init(priv);
+}
+
+static inline int trans_tx_stop(struct iwl_priv *priv)
+{
+       return priv->trans.ops->tx_stop(priv);
+}
+
+static inline void trans_tx_free(struct iwl_priv *priv)
+{
+       priv->trans.ops->tx_free(priv);
+}
+
+static inline int trans_send_cmd(struct iwl_priv *priv,
+                               struct iwl_host_cmd *cmd)
+{
+       return priv->trans.ops->send_cmd(priv, cmd);
+}
+
+static inline int trans_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags,
+                                       u16 len, const void *data)
+{
+       return priv->trans.ops->send_cmd_pdu(priv, id, flags, len, data);
+}
 
 void iwl_trans_register(struct iwl_trans *trans);
index db5abaa..9b07e07 100644 (file)
@@ -157,14 +157,15 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
  * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
  * @priv - driver private data
  * @txq - tx queue
+ * @index - the index of the TFD to be freed
  *
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
-void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+       int index)
 {
        struct iwl_tfd *tfd_tmp = txq->tfds;
-       int index = txq->q.read_ptr;
 
        iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index],
                         DMA_TO_DEVICE);
@@ -173,12 +174,12 @@ void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
        if (txq->txb) {
                struct sk_buff *skb;
 
-               skb = txq->txb[txq->q.read_ptr].skb;
+               skb = txq->txb[index].skb;
 
                /* can be called from irqs-disabled context */
                if (skb) {
                        dev_kfree_skb_any(skb);
-                       txq->txb[txq->q.read_ptr].skb = NULL;
+                       txq->txb[index].skb = NULL;
                }
        }
 }
@@ -220,122 +221,6 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
        return 0;
 }
 
-/**
- * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
- */
-void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
-{
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-
-       if (q->n_bd == 0)
-               return;
-
-        while (q->write_ptr != q->read_ptr) {
-               iwlagn_txq_free_tfd(priv, txq);
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
-{
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct device *dev = priv->bus.dev;
-       int i;
-
-       iwl_tx_queue_unmap(priv, txq_id);
-
-       /* De-alloc array of command/tx buffers */
-       for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
-               kfree(txq->cmd[i]);
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd)
-               dma_free_coherent(dev, priv->hw_params.tfd_size *
-                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-
-       /* De-alloc array of per-TFD driver data */
-       kfree(txq->txb);
-       txq->txb = NULL;
-
-       /* deallocate arrays */
-       kfree(txq->cmd);
-       kfree(txq->meta);
-       txq->cmd = NULL;
-       txq->meta = NULL;
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
- */
-void iwl_cmd_queue_unmap(struct iwl_priv *priv)
-{
-       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
-       struct iwl_queue *q = &txq->q;
-       int i;
-
-       if (q->n_bd == 0)
-               return;
-
-       while (q->read_ptr != q->write_ptr) {
-               i = get_cmd_index(q, q->read_ptr);
-
-               if (txq->meta[i].flags & CMD_MAPPED) {
-                       iwlagn_unmap_tfd(priv, &txq->meta[i], &txq->tfds[i],
-                                        DMA_BIDIRECTIONAL);
-                       txq->meta[i].flags = 0;
-               }
-
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-}
-
-/**
- * iwl_cmd_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-void iwl_cmd_queue_free(struct iwl_priv *priv)
-{
-       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
-       struct device *dev = priv->bus.dev;
-       int i;
-
-       iwl_cmd_queue_unmap(priv);
-
-       /* De-alloc array of command/tx buffers */
-       for (i = 0; i < TFD_CMD_SLOTS; i++)
-               kfree(txq->cmd[i]);
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd)
-               dma_free_coherent(dev, priv->hw_params.tfd_size * txq->q.n_bd,
-                                 txq->tfds, txq->q.dma_addr);
-
-       /* deallocate arrays */
-       kfree(txq->cmd);
-       kfree(txq->meta);
-       txq->cmd = NULL;
-       txq->meta = NULL;
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
 /*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
  * DMA services
  *
@@ -443,6 +328,12 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -EIO;
        }
 
+       if ((priv->ucode_owner == IWL_OWNERSHIP_TM) &&
+           !(cmd->flags & CMD_ON_DEMAND)) {
+               IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n");
+               return -EIO;
+       }
+
        copy_size = sizeof(out_cmd->hdr);
        cmd_size = sizeof(out_cmd->hdr);
 
@@ -496,11 +387,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        out_cmd = txq->cmd[idx];
        out_meta = &txq->meta[idx];
 
-       if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
-               spin_unlock_irqrestore(&priv->hcmd_lock, flags);
-               return -ENOSPC;
-       }
-
        memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
        if (cmd->flags & CMD_WANT_SKB)
                out_meta->source = cmd;
@@ -574,7 +460,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 #endif
        }
 
-       out_meta->flags = cmd->flags | CMD_MAPPED;
+       out_meta->flags = cmd->flags;
 
        txq->need_update = 1;
 
@@ -684,7 +570,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                wake_up_interruptible(&priv->wait_command_queue);
        }
 
-       /* Mark as unmapped */
        meta->flags = 0;
 
        spin_unlock_irqrestore(&priv->hcmd_lock, flags);
index 9dcf967..dbd24a4 100644 (file)
@@ -874,6 +874,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_GET);
+       cmd.offset = cpu_to_le16(offset);
 
        if (reg != CMD_MAC_REG_ACCESS &&
            reg != CMD_BBP_REG_ACCESS &&
@@ -883,7 +884,7 @@ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
        }
 
        ret = lbs_cmd_with_response(priv, reg, &cmd);
-       if (ret) {
+       if (!ret) {
                if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
                        *value = cmd.value.bbp_rf;
                else if (reg == CMD_MAC_REG_ACCESS)
@@ -916,6 +917,7 @@ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
+       cmd.offset = cpu_to_le16(offset);
 
        if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
                cmd.value.bbp_rf = (u8) (value & 0xFF);
@@ -1068,16 +1070,34 @@ static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 }
 
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
-                         int result)
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result)
 {
+       /*
+        * Normally, commands are removed from cmdpendingq before being
+        * submitted. However, we can arrive here on alternative codepaths
+        * where the command is still pending. Make sure the command really
+        * isn't part of a list at this point.
+        */
+       list_del_init(&cmd->list);
+
        cmd->result = result;
        cmd->cmdwaitqwoken = 1;
-       wake_up_interruptible(&cmd->cmdwait_q);
+       wake_up(&cmd->cmdwait_q);
 
        if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
                __lbs_cleanup_and_insert_cmd(priv, cmd);
        priv->cur_cmd = NULL;
+       wake_up_interruptible(&priv->waitq);
+}
+
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                         int result)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&priv->driver_lock, flags);
+       __lbs_complete_command(priv, cmd, result);
+       spin_unlock_irqrestore(&priv->driver_lock, flags);
 }
 
 int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
@@ -1249,7 +1269,7 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
        if (!list_empty(&priv->cmdfreeq)) {
                tempnode = list_first_entry(&priv->cmdfreeq,
                                            struct cmd_ctrl_node, list);
-               list_del(&tempnode->list);
+               list_del_init(&tempnode->list);
        } else {
                lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
                tempnode = NULL;
@@ -1357,10 +1377,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                                        ret = 0;
                                        goto done;
@@ -1370,10 +1387,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                    (priv->psstate == PS_STATE_PRE_SLEEP)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-                                       spin_lock_irqsave(&priv->driver_lock, flags);
-                                       list_del(&cmdnode->list);
                                        lbs_complete_command(priv, cmdnode, 0);
-                                       spin_unlock_irqrestore(&priv->driver_lock, flags);
                                        priv->needtowakeup = 1;
 
                                        ret = 0;
@@ -1385,7 +1399,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                        }
                }
                spin_lock_irqsave(&priv->driver_lock, flags);
-               list_del(&cmdnode->list);
+               list_del_init(&cmdnode->list);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
                            le16_to_cpu(cmd->command));
@@ -1668,7 +1682,13 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
        }
 
        might_sleep();
-       wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+
+       /*
+        * Be careful with signals here. A signal may be received as the system
+        * goes into suspend or resume. We do not want this to interrupt the
+        * command, so we perform an uninterruptible sleep.
+        */
+       wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        ret = cmdnode->result;
index 7109d6b..b280ef7 100644 (file)
@@ -59,6 +59,8 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv);
 int lbs_free_cmd_buffer(struct lbs_private *priv);
 
 int lbs_execute_next_command(struct lbs_private *priv);
+void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+                           int result);
 void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
                          int result);
 int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
index 2ffe5a1..178b222 100644 (file)
@@ -166,7 +166,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
                        lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
                }
 
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                ret = 0;
@@ -187,7 +187,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
                        break;
 
                }
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
                spin_unlock_irqrestore(&priv->driver_lock, flags);
 
                ret = -1;
@@ -205,7 +205,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
 
        if (priv->cur_cmd) {
                /* Clean up and Put current command back to cmdfreeq */
-               lbs_complete_command(priv, priv->cur_cmd, result);
+               __lbs_complete_command(priv, priv->cur_cmd, result);
        }
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
index cf3d2c8..c79aac4 100644 (file)
@@ -639,6 +639,14 @@ static void lbs_cmd_timeout_handler(unsigned long data)
                    le16_to_cpu(priv->cur_cmd->cmdbuf->command));
 
        priv->cmd_timed_out = 1;
+
+       /*
+        * If the device didn't even acknowledge the command, reset the state
+        * so that we don't block all future commands due to this one timeout.
+        */
+       if (priv->dnld_sent == DNLD_CMD_SENT)
+               priv->dnld_sent = DNLD_RES_RECEIVED;
+
        wake_up_interruptible(&priv->waitq);
 out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -995,7 +1003,7 @@ void lbs_stop_card(struct lbs_private *priv)
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
                cmdnode->result = -ENOENT;
                cmdnode->cmdwaitqwoken = 1;
-               wake_up_interruptible(&cmdnode->cmdwait_q);
+               wake_up(&cmdnode->cmdwait_q);
        }
 
        /* Flush the command the card is currently processing */
@@ -1003,7 +1011,7 @@ void lbs_stop_card(struct lbs_private *priv)
                lbs_deb_main("clearing current command\n");
                priv->cur_cmd->result = -ENOENT;
                priv->cur_cmd->cmdwaitqwoken = 1;
-               wake_up_interruptible(&priv->cur_cmd->cmdwait_q);
+               wake_up(&priv->cur_cmd->cmdwait_q);
        }
        lbs_deb_main("done clearing commands\n");
        spin_unlock_irqrestore(&priv->driver_lock, flags);
index 687c1f2..352d2c5 100644 (file)
@@ -671,6 +671,59 @@ static const u32 mwifiex_cipher_suites[] = {
        WLAN_CIPHER_SUITE_CCMP,
 };
 
+/*
+ * CFG802.11 operation handler for setting bit rates.
+ *
+ * Function selects legacy bang B/G/BG from corresponding bitrates selection.
+ * Currently only 2.4GHz band is supported.
+ */
+static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
+                               struct net_device *dev,
+                               const u8 *peer,
+                               const struct cfg80211_bitrate_mask *mask)
+{
+       struct mwifiex_ds_band_cfg band_cfg;
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       int index = 0, mode = 0, i;
+
+       /* Currently only 2.4GHz is supported */
+       for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) {
+               /*
+                * Rates below 6 Mbps in the table are CCK rates; 802.11b
+                * and from 6 they are OFDM; 802.11G
+                */
+               if (mwifiex_rates[i].bitrate == 60) {
+                       index = 1 << i;
+                       break;
+               }
+       }
+
+       if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) {
+               mode = BAND_B;
+       } else {
+               mode = BAND_G;
+               if (mask->control[IEEE80211_BAND_2GHZ].legacy % index)
+                       mode |=  BAND_B;
+       }
+
+       memset(&band_cfg, 0, sizeof(band_cfg));
+       band_cfg.config_bands = mode;
+
+       if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
+               band_cfg.adhoc_start_band = mode;
+
+       band_cfg.sec_chan_offset = NO_SEC_CHANNEL;
+
+       if (mwifiex_set_radio_band_cfg(priv, &band_cfg))
+               return -EFAULT;
+
+       wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n",
+                               (mode & BAND_B) ? "b" : "",
+                               (mode & BAND_G) ? "g" : "");
+
+       return 0;
+}
+
 /*
  * CFG802.11 operation handler for disconnection request.
  *
@@ -960,7 +1013,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
                ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
 
        if (sme->key) {
-               if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) {
+               if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
                        dev_dbg(priv->adapter->dev,
                                "info: setting wep encryption"
                                " with key len %d\n", sme->key_len);
@@ -1225,6 +1278,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_default_key = mwifiex_cfg80211_set_default_key,
        .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
        .set_tx_power = mwifiex_cfg80211_set_tx_power,
+       .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
 };
 
 /*
index 46d65e0..1bcf9ea 100644 (file)
@@ -27,8 +27,8 @@ static struct dentry *mwifiex_dfs_dir;
 
 static char *bss_modes[] = {
        "Unknown",
-       "Managed",
        "Ad-hoc",
+       "Managed",
        "Auto"
 };
 
index 0e90b09..94ddc90 100644 (file)
@@ -30,7 +30,9 @@
 
 #define MWIFIEX_MAX_BSS_NUM         (1)
 
-#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */
+#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
+                                        *   + 4 byte alignment
+                                        */
 
 #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED      2
 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED      16
index afdd145..4fee099 100644 (file)
@@ -157,6 +157,17 @@ enum MWIFIEX_802_11_WEP_STATUS {
 #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26))
 #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
 
+/* httxcfg bitmap
+ * 0           reserved
+ * 1           20/40 Mhz enable(1)/disable(0)
+ * 2-3         reserved
+ * 4           green field enable(1)/disable(0)
+ * 5           short GI in 20 Mhz enable(1)/disable(0)
+ * 6           short GI in 40 Mhz enable(1)/disable(0)
+ * 7-15                reserved
+ */
+#define MWIFIEX_FW_DEF_HTTXCFG (BIT(1) | BIT(4) | BIT(5) | BIT(6))
+
 #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
 #define SETHT_MCS32(x) (x[4] |= 1)
 
index 49b9c13..c54ee28 100644 (file)
@@ -1113,6 +1113,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
        struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
        struct mwifiex_ds_auto_ds auto_ds;
        enum state_11d_t state_11d;
+       struct mwifiex_ds_11n_tx_cfg tx_cfg;
 
        if (first_sta) {
 
@@ -1198,8 +1199,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
        if (ret)
                dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
 
+       /* Send cmd to FW to configure 11n specific configuration
+        * (Short GI, Channel BW, Green field support etc.) for transmit
+        */
+       tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG;
+       ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_CFG,
+                                    HostCmd_ACT_GEN_SET, 0, &tx_cfg);
+
        /* set last_init_cmd */
-       priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
+       priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
        ret = -EINPROGRESS;
 
        return ret;
index fa6221b..1822bfa 100644 (file)
@@ -47,6 +47,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
        struct mwifiex_adapter *adapter = priv->adapter;
        struct txpd *local_tx_pd;
        struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+       u8 pad;
 
        if (!skb->len) {
                dev_err(adapter->dev, "Tx: bad packet length: %d\n",
@@ -55,15 +56,19 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
                return skb->data;
        }
 
-       BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN));
-       skb_push(skb, sizeof(*local_tx_pd));
+       /* If skb->data is not aligned; add padding */
+       pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
+
+       BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN
+                                                               + pad));
+       skb_push(skb, sizeof(*local_tx_pd) + pad);
 
        local_tx_pd = (struct txpd *) skb->data;
        memset(local_tx_pd, 0, sizeof(struct txpd));
        local_tx_pd->bss_num = priv->bss_num;
        local_tx_pd->bss_type = priv->bss_type;
        local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len -
-                                                       sizeof(struct txpd)));
+                                               (sizeof(struct txpd) + pad)));
 
        local_tx_pd->priority = (u8) skb->priority;
        local_tx_pd->pkt_delay_2ms =
@@ -88,7 +93,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
        }
 
        /* Offset of actual data */
-       local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+       local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) + pad);
 
        /* make space for INTF_HEADER_LEN */
        skb_push(skb, INTF_HEADER_LEN);
index 59e7779..5075593 100644 (file)
@@ -1054,6 +1054,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0586, 0x341e) },
        { USB_DEVICE(0x0586, 0x343e) },
 #ifdef CONFIG_RT2800USB_RT33XX
+       /* Belkin */
+       { USB_DEVICE(0x050d, 0x945b) },
        /* Ralink */
        { USB_DEVICE(0x148f, 0x3370) },
        { USB_DEVICE(0x148f, 0x8070) },
index 1e851aa..17a8e96 100644 (file)
@@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
                        tx_agc[RF90_PATH_A] = 0x10101010;
                        tx_agc[RF90_PATH_B] = 0x10101010;
                } else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
-                          TXHIGHPWRLEVEL_LEVEL1) {
+                          TXHIGHPWRLEVEL_LEVEL2) {
                        tx_agc[RF90_PATH_A] = 0x00000000;
                        tx_agc[RF90_PATH_B] = 0x00000000;
                } else{
index 87caa94..7e33f1f 100644 (file)
@@ -90,7 +90,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
        struct acx_current_tx_power *acx;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+       wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power);
 
        if (power < 0 || power > 25)
                return -EINVAL;
@@ -1624,22 +1624,22 @@ out:
        return ret;
 }
 
-int wl1271_acx_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
 {
-       struct wl1271_acx_max_tx_retry *acx = NULL;
+       struct wl1271_acx_ap_max_tx_retry *acx = NULL;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx max tx retry");
+       wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
        if (!acx)
                return -ENOMEM;
 
-       acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
+       acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
 
        ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
        if (ret < 0) {
-               wl1271_warning("acx max tx retry failed: %d", ret);
+               wl1271_warning("acx ap max tx retry failed: %d", ret);
                goto out;
        }
 
index d303265..d2eb86e 100644 (file)
@@ -1168,7 +1168,7 @@ struct wl1271_acx_ps_rx_streaming {
        u8 timeout;
 } __packed;
 
-struct wl1271_acx_max_tx_retry {
+struct wl1271_acx_ap_max_tx_retry {
        struct acx_header header;
 
        /*
@@ -1400,7 +1400,7 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
                                       bool enable);
 int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
 int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
-int wl1271_acx_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
 int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
 int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
index 101f7e0..5ebc64d 100644 (file)
@@ -513,7 +513,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
                PERIODIC_SCAN_COMPLETE_EVENT_ID;
 
        if (wl->bss_type == BSS_TYPE_AP_BSS)
-               wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
+               wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
+                                 INACTIVE_STA_EVENT_ID |
+                                 MAX_TX_RETRY_EVENT_ID;
        else
                wl->event_mask |= DUMMY_PACKET_EVENT_ID |
                        BA_SESSION_RX_CONSTRAINT_EVENT_ID;
index 68972cb..97dd237 100644 (file)
@@ -400,10 +400,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
 
        join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
 
-       /* reset TX security counters */
-       wl->tx_security_last_seq = 0;
-       wl->tx_security_seq = 0;
-
        wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
                join->basic_rate_set, join->supported_rate_set);
 
@@ -1084,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
 
        memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
 
-       cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
+       cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
        cmd->bss_index = WL1271_AP_BSS_INDEX;
        cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
        cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
index b5a7b30..6080e01 100644 (file)
@@ -713,8 +713,16 @@ struct conf_tx_settings {
        /*
         * AP-mode - allow this number of TX retries to a station before an
         * event is triggered from FW.
+        * In AP-mode the hlids of unreachable stations are given in the
+        * "sta_tx_retry_exceeded" member in the event mailbox.
         */
-       u16 ap_max_tx_retries;
+       u8 max_tx_retries;
+
+       /*
+        * AP-mode - after this number of seconds a connected station is
+        * considered inactive.
+        */
+       u16 ap_aging_period;
 
        /*
         * Configuration for TID parameters.
index da21270..37934b5 100644 (file)
@@ -30,6 +30,7 @@
 #include "acx.h"
 #include "ps.h"
 #include "io.h"
+#include "tx.h"
 
 /* ms */
 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
@@ -233,7 +234,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
        char buf[20];
        int res;
 
-       queue_len = wl->tx_queue_count;
+       queue_len = wl1271_tx_total_queue_count(wl);
 
        res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
@@ -338,10 +339,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 #define DRIVER_STATE_PRINT_HEX(x)  DRIVER_STATE_PRINT(x, "0x%x")
 
        DRIVER_STATE_PRINT_INT(tx_blocks_available);
-       DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+       DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]);
+       DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
        DRIVER_STATE_PRINT_INT(tx_frames_cnt);
        DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
-       DRIVER_STATE_PRINT_INT(tx_queue_count);
+       DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
+       DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
+       DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
+       DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
        DRIVER_STATE_PRINT_INT(tx_packets_count);
        DRIVER_STATE_PRINT_INT(tx_results_count);
        DRIVER_STATE_PRINT_LHEX(flags);
@@ -349,7 +356,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
        DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
-       DRIVER_STATE_PRINT_INT(tx_security_last_seq);
+       DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
        DRIVER_STATE_PRINT_INT(rx_counter);
        DRIVER_STATE_PRINT_INT(session_counter);
        DRIVER_STATE_PRINT_INT(state);
index a16dee5..304aaa2 100644 (file)
@@ -214,6 +214,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
        u32 vector;
        bool beacon_loss = false;
        bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
+       bool disconnect_sta = false;
+       unsigned long sta_bitmap = 0;
 
        wl1271_event_mbox_dump(mbox);
 
@@ -295,6 +297,46 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        wl1271_tx_dummy_packet(wl);
        }
 
+       /*
+        * "TX retries exceeded" has a different meaning according to mode.
+        * In AP mode the offending station is disconnected.
+        */
+       if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
+               wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
+               sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
+               disconnect_sta = true;
+       }
+
+       if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
+               wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
+               sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
+               disconnect_sta = true;
+       }
+
+       if (is_ap && disconnect_sta) {
+               u32 num_packets = wl->conf.tx.max_tx_retries;
+               struct ieee80211_sta *sta;
+               const u8 *addr;
+               int h;
+
+               for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
+                    h < AP_MAX_LINKS;
+                    h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
+                       if (!wl1271_is_active_sta(wl, h))
+                               continue;
+
+                       addr = wl->links[h].addr;
+
+                       rcu_read_lock();
+                       sta = ieee80211_find_sta(wl->vif, addr);
+                       if (sta) {
+                               wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
+                               ieee80211_report_low_ack(sta, num_packets);
+                       }
+                       rcu_read_unlock();
+               }
+       }
+
        if (wl->vif && beacon_loss)
                ieee80211_connection_loss(wl->vif);
 
index ce99adf..e524ad6 100644 (file)
@@ -58,13 +58,16 @@ enum {
        CHANNEL_SWITCH_COMPLETE_EVENT_ID         = BIT(17),
        BSS_LOSE_EVENT_ID                        = BIT(18),
        REGAINED_BSS_EVENT_ID                    = BIT(19),
-       ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID    = BIT(20),
+       MAX_TX_RETRY_EVENT_ID                    = BIT(20),
        /* STA: dummy paket for dynamic mem blocks */
        DUMMY_PACKET_EVENT_ID                    = BIT(21),
        /* AP: STA remove complete */
        STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21),
        SOFT_GEMINI_SENSE_EVENT_ID               = BIT(22),
+       /* STA: SG prediction */
        SOFT_GEMINI_PREDICTION_EVENT_ID          = BIT(23),
+       /* AP: Inactive STA */
+       INACTIVE_STA_EVENT_ID                    = BIT(23),
        SOFT_GEMINI_AVALANCHE_EVENT_ID           = BIT(24),
        PLT_RX_CALIBRATION_COMPLETE_EVENT_ID     = BIT(25),
        DBG_EVENT_ID                             = BIT(26),
@@ -119,7 +122,11 @@ struct event_mailbox {
 
        /* AP FW only */
        u8 hlid_removed;
+
+       /* a bitmap of hlids for stations that have been inactive too long */
        __le16 sta_aging_status;
+
+       /* a bitmap of hlids for stations which didn't respond to TX */
        __le16 sta_tx_retry_exceeded;
 
        /*
@@ -143,4 +150,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl);
 int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
 void wl1271_pspoll_work(struct work_struct *work);
 
+/* Functions from main.c */
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
+
 #endif
index cf40ac9..c3e9a2e 100644 (file)
@@ -447,7 +447,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
-       ret = wl1271_acx_max_tx_retry(wl);
+       ret = wl1271_acx_ap_max_tx_retry(wl);
        if (ret < 0)
                return ret;
 
@@ -455,6 +455,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
+       /* initialize Tx power */
+       ret = wl1271_acx_tx_power(wl, wl->power_level);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
index a3734bd..e58c22d 100644 (file)
@@ -210,7 +210,8 @@ static struct conf_drv_settings default_conf = {
                                .tx_op_limit = 1504,
                        },
                },
-               .ap_max_tx_retries = 100,
+               .max_tx_retries = 100,
+               .ap_aging_period = 300,
                .tid_conf_count = 4,
                .tid_conf = {
                        [CONF_TX_AC_BE] = {
@@ -823,13 +824,24 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
        }
 }
 
+static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl)
+{
+       int i;
+       u32 total_alloc_blocks = 0;
+
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               total_alloc_blocks += wl->tx_allocated_blocks[i];
+
+       return total_alloc_blocks;
+}
+
 static void wl1271_fw_status(struct wl1271 *wl,
                             struct wl1271_fw_full_status *full_status)
 {
        struct wl1271_fw_common_status *status = &full_status->common;
        struct timespec ts;
        u32 old_tx_blk_count = wl->tx_blocks_available;
-       u32 freed_blocks = 0;
+       u32 freed_blocks = 0, ac_freed_blocks;
        int i;
 
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
@@ -849,21 +861,23 @@ static void wl1271_fw_status(struct wl1271 *wl,
 
        /* update number of available TX blocks */
        for (i = 0; i < NUM_TX_QUEUES; i++) {
-               freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
-                               wl->tx_blocks_freed[i];
+               ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) -
+                                 wl->tx_blocks_freed[i];
+               freed_blocks += ac_freed_blocks;
+
+               wl->tx_allocated_blocks[i] -= ac_freed_blocks;
 
                wl->tx_blocks_freed[i] =
                        le32_to_cpu(status->tx_released_blks[i]);
        }
 
-       wl->tx_allocated_blocks -= freed_blocks;
-
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
                /* Update num of allocated TX blocks per link and ps status */
                wl1271_irq_update_links_status(wl, &full_status->ap);
                wl->tx_blocks_available += freed_blocks;
        } else {
-               int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
+               int avail = full_status->sta.tx_total -
+                           wl1271_tx_allocated_blocks(wl);
 
                /*
                 * The FW might change the total number of TX memblocks before
@@ -978,7 +992,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
                        /* Check if any tx blocks were freed */
                        spin_lock_irqsave(&wl->wl_lock, flags);
                        if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
-                           wl->tx_queue_count) {
+                           wl1271_tx_total_queue_count(wl) > 0) {
                                spin_unlock_irqrestore(&wl->wl_lock, flags);
                                /*
                                 * In order to avoid starvation of the TX path,
@@ -1026,7 +1040,7 @@ out:
        /* In case TX was not handled here, queue TX work */
        clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
        if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
-           wl->tx_queue_count)
+           wl1271_tx_total_queue_count(wl) > 0)
                ieee80211_queue_work(wl->hw, &wl->tx_work);
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
@@ -1227,6 +1241,15 @@ static void wl1271_recovery_work(struct work_struct *work)
        wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
                    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
+       /*
+        * Advance security sequence number to overcome potential progress
+        * in the firmware during recovery. This doens't hurt if the network is
+        * not encrypted.
+        */
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+           test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+               wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
+
        if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
                ieee80211_connection_loss(wl->vif);
 
@@ -1474,26 +1497,27 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1271 *wl = hw->priv;
        unsigned long flags;
-       int q;
+       int q, mapping;
        u8 hlid = 0;
 
-       q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+       mapping = skb_get_queue_mapping(skb);
+       q = wl1271_tx_get_queue(mapping);
 
        if (wl->bss_type == BSS_TYPE_AP_BSS)
                hlid = wl1271_tx_get_hlid(skb);
 
        spin_lock_irqsave(&wl->wl_lock, flags);
 
-       wl->tx_queue_count++;
+       wl->tx_queue_count[q]++;
 
        /*
         * The workqueue is slow to process the tx_queue and we need stop
         * the queue here, otherwise the queue will get too long.
         */
-       if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
-               wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
-               ieee80211_stop_queues(wl->hw);
-               set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+       if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+               wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
+               ieee80211_stop_queue(wl->hw, mapping);
+               set_bit(q, &wl->stopped_queues_map);
        }
 
        /* queue the packet */
@@ -1519,10 +1543,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 int wl1271_tx_dummy_packet(struct wl1271 *wl)
 {
        unsigned long flags;
+       int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
 
        spin_lock_irqsave(&wl->wl_lock, flags);
        set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
-       wl->tx_queue_count++;
+       wl->tx_queue_count[q]++;
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
        /* The FW is low on RX memory blocks, so send the dummy packet asap */
@@ -1586,10 +1611,13 @@ static struct notifier_block wl1271_dev_notifier = {
 #ifdef CONFIG_PM
 static int wl1271_configure_suspend_sta(struct wl1271 *wl)
 {
-       int ret;
+       int ret = 0;
 
        mutex_lock(&wl->mutex);
 
+       if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               goto out_unlock;
+
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out_unlock;
@@ -1634,10 +1662,13 @@ out:
 
 static int wl1271_configure_suspend_ap(struct wl1271 *wl)
 {
-       int ret;
+       int ret = 0;
 
        mutex_lock(&wl->mutex);
 
+       if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+               goto out_unlock;
+
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out_unlock;
@@ -1705,7 +1736,6 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
        }
        /* flush any remaining work */
        wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
-       flush_delayed_work(&wl->scan_complete_work);
 
        /*
         * disable and re-enable interrupts in order to flush
@@ -1977,11 +2007,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
        wl->psm_entry_retry = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->tx_blocks_available = 0;
-       wl->tx_allocated_blocks = 0;
        wl->tx_results_count = 0;
        wl->tx_packets_count = 0;
-       wl->tx_security_last_seq = 0;
-       wl->tx_security_seq = 0;
        wl->time_offset = 0;
        wl->session_counter = 0;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
@@ -2000,8 +2027,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
         */
        wl->flags = 0;
 
-       for (i = 0; i < NUM_TX_QUEUES; i++)
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
                wl->tx_blocks_freed[i] = 0;
+               wl->tx_allocated_blocks[i] = 0;
+       }
 
        wl1271_debugfs_reset(wl);
 
@@ -2154,6 +2183,10 @@ static int wl1271_unjoin(struct wl1271 *wl)
        clear_bit(WL1271_FLAG_JOINED, &wl->flags);
        memset(wl->bssid, 0, ETH_ALEN);
 
+       /* reset TX security counters on a clean disconnect */
+       wl->tx_security_last_seq_lsb = 0;
+       wl->tx_security_seq = 0;
+
        /* stop filtering packets based on bssid */
        wl1271_configure_filters(wl, FIF_OTHER_BSS);
 
@@ -2246,6 +2279,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                        wl->channel = channel;
                }
 
+               if ((changed & IEEE80211_CONF_CHANGE_POWER))
+                       wl->power_level = conf->power_level;
+
                goto out;
        }
 
@@ -2753,6 +2789,44 @@ out:
        return ret;
 }
 
+static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif)
+{
+       struct wl1271 *wl = hw->priv;
+       int ret;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
+
+       mutex_lock(&wl->mutex);
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
+               ret = wl1271_scan_stop(wl);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+       wl->scan.state = WL1271_SCAN_STATE_IDLE;
+       memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
+       wl->scan.req = NULL;
+       ieee80211_scan_completed(wl->hw, true);
+
+out_sleep:
+       wl1271_ps_elp_sleep(wl);
+out:
+       mutex_unlock(&wl->mutex);
+
+       cancel_delayed_work_sync(&wl->scan_complete_work);
+}
+
 static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct cfg80211_sched_scan_request *req,
@@ -3515,6 +3589,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
        __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
 }
 
+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+       int id = hlid - WL1271_AP_STA_HLID_START;
+       return test_bit(id, wl->ap_hlid_map);
+}
+
 static int wl1271_op_sta_add(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
                             struct ieee80211_sta *sta)
@@ -3673,7 +3753,7 @@ static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
                goto out;
 
        /* packets are considered pending if in the TX queue or the FW */
-       ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
+       ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
 
        /* the above is appropriate for STA mode for PS purposes */
        WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
@@ -3836,40 +3916,40 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
 
 /* 5 GHz band channels for WL1273 */
 static struct ieee80211_channel wl1271_channels_5ghz[] = {
-       { .hw_value = 7, .center_freq = 5035},
-       { .hw_value = 8, .center_freq = 5040},
-       { .hw_value = 9, .center_freq = 5045},
-       { .hw_value = 11, .center_freq = 5055},
-       { .hw_value = 12, .center_freq = 5060},
-       { .hw_value = 16, .center_freq = 5080},
-       { .hw_value = 34, .center_freq = 5170},
-       { .hw_value = 36, .center_freq = 5180},
-       { .hw_value = 38, .center_freq = 5190},
-       { .hw_value = 40, .center_freq = 5200},
-       { .hw_value = 42, .center_freq = 5210},
-       { .hw_value = 44, .center_freq = 5220},
-       { .hw_value = 46, .center_freq = 5230},
-       { .hw_value = 48, .center_freq = 5240},
-       { .hw_value = 52, .center_freq = 5260},
-       { .hw_value = 56, .center_freq = 5280},
-       { .hw_value = 60, .center_freq = 5300},
-       { .hw_value = 64, .center_freq = 5320},
-       { .hw_value = 100, .center_freq = 5500},
-       { .hw_value = 104, .center_freq = 5520},
-       { .hw_value = 108, .center_freq = 5540},
-       { .hw_value = 112, .center_freq = 5560},
-       { .hw_value = 116, .center_freq = 5580},
-       { .hw_value = 120, .center_freq = 5600},
-       { .hw_value = 124, .center_freq = 5620},
-       { .hw_value = 128, .center_freq = 5640},
-       { .hw_value = 132, .center_freq = 5660},
-       { .hw_value = 136, .center_freq = 5680},
-       { .hw_value = 140, .center_freq = 5700},
-       { .hw_value = 149, .center_freq = 5745},
-       { .hw_value = 153, .center_freq = 5765},
-       { .hw_value = 157, .center_freq = 5785},
-       { .hw_value = 161, .center_freq = 5805},
-       { .hw_value = 165, .center_freq = 5825},
+       { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
+       { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
+       { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
+       { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
+       { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
+       { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
+       { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
+       { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
+       { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
+       { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
+       { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
+       { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
+       { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
+       { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
+       { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
+       { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
+       { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
+       { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
+       { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
+       { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
+       { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
+       { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
+       { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
+       { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
+       { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
+       { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
+       { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
+       { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
+       { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
+       { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
+       { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
+       { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
+       { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
+       { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
 };
 
 /* mapping to indexes for wl1271_rates_5ghz */
@@ -3930,6 +4010,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .tx = wl1271_op_tx,
        .set_key = wl1271_op_set_key,
        .hw_scan = wl1271_op_hw_scan,
+       .cancel_hw_scan = wl1271_op_cancel_hw_scan,
        .sched_scan_start = wl1271_op_sched_scan_start,
        .sched_scan_stop = wl1271_op_sched_scan_stop,
        .bss_info_changed = wl1271_op_bss_info_changed,
@@ -4327,6 +4408,9 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->quirks = 0;
        wl->platform_quirks = 0;
        wl->sched_scanning = false;
+       wl->tx_security_seq = 0;
+       wl->tx_security_last_seq_lsb = 0;
+
        setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
                    (unsigned long) wl);
        wl->fwlog_size = 0;
index 3e68a66..3548377 100644 (file)
@@ -193,24 +193,27 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
 
 static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
 {
-       int i, filtered = 0;
+       int i;
        struct sk_buff *skb;
        struct ieee80211_tx_info *info;
        unsigned long flags;
+       int filtered[NUM_TX_QUEUES];
 
        /* filter all frames currently the low level queus for this hlid */
        for (i = 0; i < NUM_TX_QUEUES; i++) {
+               filtered[i] = 0;
                while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
                        info = IEEE80211_SKB_CB(skb);
                        info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                        info->status.rates[0].idx = -1;
                        ieee80211_tx_status_ni(wl->hw, skb);
-                       filtered++;
+                       filtered[i]++;
                }
        }
 
        spin_lock_irqsave(&wl->wl_lock, flags);
-       wl->tx_queue_count -= filtered;
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               wl->tx_queue_count[i] -= filtered[i];
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
        wl1271_handle_tx_low_watermark(wl);
index 5e5c66d..edfe01c 100644 (file)
@@ -321,6 +321,33 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
        return 0;
 }
 
+int wl1271_scan_stop(struct wl1271 *wl)
+{
+       struct wl1271_cmd_header *cmd = NULL;
+       int ret = 0;
+
+       if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE))
+               return -EINVAL;
+
+       wl1271_debug(DEBUG_CMD, "cmd scan stop");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd,
+                             sizeof(*cmd), 0);
+       if (ret < 0) {
+               wl1271_error("cmd stop_scan failed");
+               goto out;
+       }
+out:
+       kfree(cmd);
+       return ret;
+}
+
 static int
 wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                                    struct cfg80211_sched_scan_request *req,
index ca81de2..d882e4d 100644 (file)
@@ -28,6 +28,7 @@
 
 int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
                struct cfg80211_scan_request *req);
+int wl1271_scan_stop(struct wl1271 *wl);
 int wl1271_scan_build_probe_req(struct wl1271 *wl,
                                const u8 *ssid, size_t ssid_len,
                                const u8 *ie, size_t ie_len, u8 band);
index 4dc4573..5cf18c2 100644 (file)
@@ -166,13 +166,13 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
                ret = pm_runtime_get_sync(&func->dev);
                if (ret)
                        goto out;
+       } else {
+               /* Runtime PM is disabled: power up the card manually */
+               ret = mmc_power_restore_host(func->card->host);
+               if (ret < 0)
+                       goto out;
        }
 
-       /* Runtime PM might be disabled, so power up the card manually */
-       ret = mmc_power_restore_host(func->card->host);
-       if (ret < 0)
-               goto out;
-
        sdio_claim_host(func);
        sdio_enable_func(func);
 
@@ -188,7 +188,7 @@ static int wl1271_sdio_power_off(struct wl1271 *wl)
        sdio_disable_func(func);
        sdio_release_host(func);
 
-       /* Runtime PM might be disabled, so power off the card manually */
+       /* Power off the card manually, even if runtime PM is enabled. */
        ret = mmc_power_save_host(func->card->host);
        if (ret < 0)
                return ret;
index 200590c..48fde96 100644 (file)
@@ -168,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
        u32 len;
        u32 total_blocks;
-       int id, ret = -EBUSY;
+       int id, ret = -EBUSY, ac;
        u32 spare_blocks;
 
        if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
@@ -206,7 +206,9 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
                desc->id = id;
 
                wl->tx_blocks_available -= total_blocks;
-               wl->tx_allocated_blocks += total_blocks;
+
+               ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+               wl->tx_allocated_blocks[ac] += total_blocks;
 
                if (wl->bss_type == BSS_TYPE_AP_BSS)
                        wl->links[hlid].allocated_blks += total_blocks;
@@ -383,6 +385,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        if (ret < 0)
                return ret;
 
+       wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
+
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
                wl1271_tx_ap_update_inconnection_sta(wl, skb);
                wl1271_tx_regulate_link(wl, hlid);
@@ -390,8 +394,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
                wl1271_tx_update_filters(wl, skb);
        }
 
-       wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
-
        /*
         * The length of each packet is stored in terms of
         * words. Thus, we must pad the skb data to make sure its
@@ -442,37 +444,62 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
 {
        unsigned long flags;
+       int i;
 
-       if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
-           wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) {
-               /* firmware buffer has space, restart queues */
-               spin_lock_irqsave(&wl->wl_lock, flags);
-               ieee80211_wake_queues(wl->hw);
-               clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
-               spin_unlock_irqrestore(&wl->wl_lock, flags);
+       for (i = 0; i < NUM_TX_QUEUES; i++) {
+               if (test_bit(i, &wl->stopped_queues_map) &&
+                   wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) {
+                       /* firmware buffer has space, restart queues */
+                       spin_lock_irqsave(&wl->wl_lock, flags);
+                       ieee80211_wake_queue(wl->hw,
+                                            wl1271_tx_get_mac80211_queue(i));
+                       clear_bit(i, &wl->stopped_queues_map);
+                       spin_unlock_irqrestore(&wl->wl_lock, flags);
+               }
        }
 }
 
+static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
+                                               struct sk_buff_head *queues)
+{
+       int i, q = -1;
+       u32 min_blks = 0xffffffff;
+
+       /*
+        * Find a non-empty ac where:
+        * 1. There are packets to transmit
+        * 2. The FW has the least allocated blocks
+        */
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               if (!skb_queue_empty(&queues[i]) &&
+                   (wl->tx_allocated_blocks[i] < min_blks)) {
+                       q = i;
+                       min_blks = wl->tx_allocated_blocks[q];
+               }
+
+       if (q == -1)
+               return NULL;
+
+       return &queues[q];
+}
+
 static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
 {
        struct sk_buff *skb = NULL;
        unsigned long flags;
+       struct sk_buff_head *queue;
 
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
-       if (skb)
-               goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
-       if (skb)
+       queue = wl1271_select_queue(wl, wl->tx_queue);
+       if (!queue)
                goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
-       if (skb)
-               goto out;
-       skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
+
+       skb = skb_dequeue(queue);
 
 out:
        if (skb) {
+               int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                spin_lock_irqsave(&wl->wl_lock, flags);
-               wl->tx_queue_count--;
+               wl->tx_queue_count[q]--;
                spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
 
@@ -484,6 +511,7 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
        struct sk_buff *skb = NULL;
        unsigned long flags;
        int i, h, start_hlid;
+       struct sk_buff_head *queue;
 
        /* start from the link after the last one */
        start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;
@@ -492,25 +520,25 @@ static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
        for (i = 0; i < AP_MAX_LINKS; i++) {
                h = (start_hlid + i) % AP_MAX_LINKS;
 
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]);
-               if (skb)
-                       goto out;
-               skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]);
+               /* only consider connected stations */
+               if (h >= WL1271_AP_STA_HLID_START &&
+                   !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
+                       continue;
+
+               queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
+               if (!queue)
+                       continue;
+
+               skb = skb_dequeue(queue);
                if (skb)
-                       goto out;
+                       break;
        }
 
-out:
        if (skb) {
+               int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                wl->last_tx_hlid = h;
                spin_lock_irqsave(&wl->wl_lock, flags);
-               wl->tx_queue_count--;
+               wl->tx_queue_count[q]--;
                spin_unlock_irqrestore(&wl->wl_lock, flags);
        } else {
                wl->last_tx_hlid = 0;
@@ -531,9 +559,12 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
 
        if (!skb &&
            test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
+               int q;
+
                skb = wl->dummy_packet;
+               q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
                spin_lock_irqsave(&wl->wl_lock, flags);
-               wl->tx_queue_count--;
+               wl->tx_queue_count[q]--;
                spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
 
@@ -558,7 +589,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
        }
 
        spin_lock_irqsave(&wl->wl_lock, flags);
-       wl->tx_queue_count++;
+       wl->tx_queue_count[q]++;
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 }
 
@@ -704,10 +735,24 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 
        wl->stats.retry_count += result->ack_failures;
 
-       /* update security sequence number */
-       wl->tx_security_seq += (result->lsb_security_sequence_number -
-                               wl->tx_security_last_seq);
-       wl->tx_security_last_seq = result->lsb_security_sequence_number;
+       /*
+        * update sequence number only when relevant, i.e. only in
+        * sessions of TKIP, AES and GEM (not in open or WEP sessions)
+        */
+       if (info->control.hw_key &&
+           (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+            info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
+            info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
+               u8 fw_lsb = result->tx_security_sequence_number_lsb;
+               u8 cur_lsb = wl->tx_security_last_seq_lsb;
+
+               /*
+                * update security sequence number, taking care of potential
+                * wrap-around
+                */
+               wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256;
+               wl->tx_security_last_seq_lsb = fw_lsb;
+       }
 
        /* remove private header from packet */
        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
@@ -772,23 +817,26 @@ void wl1271_tx_complete(struct wl1271 *wl)
 void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
 {
        struct sk_buff *skb;
-       int i, total = 0;
+       int i;
        unsigned long flags;
        struct ieee80211_tx_info *info;
+       int total[NUM_TX_QUEUES];
 
        for (i = 0; i < NUM_TX_QUEUES; i++) {
+               total[i] = 0;
                while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
                        wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
                        info = IEEE80211_SKB_CB(skb);
                        info->status.rates[0].idx = -1;
                        info->status.rates[0].count = 0;
                        ieee80211_tx_status_ni(wl->hw, skb);
-                       total++;
+                       total[i]++;
                }
        }
 
        spin_lock_irqsave(&wl->wl_lock, flags);
-       wl->tx_queue_count -= total;
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               wl->tx_queue_count[i] -= total[i];
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
        wl1271_handle_tx_low_watermark(wl);
@@ -823,10 +871,11 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
                                        ieee80211_tx_status_ni(wl->hw, skb);
                                }
                        }
+                       wl->tx_queue_count[i] = 0;
                }
        }
 
-       wl->tx_queue_count = 0;
+       wl->stopped_queues_map = 0;
 
        /*
         * Make sure the driver is at a consistent state, in case this
@@ -879,8 +928,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
        while (!time_after(jiffies, timeout)) {
                mutex_lock(&wl->mutex);
                wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d",
-                            wl->tx_frames_cnt, wl->tx_queue_count);
-               if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) {
+                            wl->tx_frames_cnt,
+                            wl1271_tx_total_queue_count(wl));
+               if ((wl->tx_frames_cnt == 0) &&
+                   (wl1271_tx_total_queue_count(wl) == 0)) {
                        mutex_unlock(&wl->mutex);
                        return;
                }
index 832f925..5d719b5 100644 (file)
@@ -150,7 +150,7 @@ struct wl1271_tx_hw_res_descr {
           (from 1st EDCA AIFS counter until TX Complete). */
        __le32 medium_delay;
        /* LS-byte of last TKIP seq-num (saved per AC for recovery). */
-       u8 lsb_security_sequence_number;
+       u8 tx_security_sequence_number_lsb;
        /* Retry count - number of transmissions without successful ACK.*/
        u8 ack_failures;
        /* The rate that succeeded getting ACK
@@ -182,6 +182,32 @@ static inline int wl1271_tx_get_queue(int queue)
        }
 }
 
+static inline int wl1271_tx_get_mac80211_queue(int queue)
+{
+       switch (queue) {
+       case CONF_TX_AC_VO:
+               return 0;
+       case CONF_TX_AC_VI:
+               return 1;
+       case CONF_TX_AC_BE:
+               return 2;
+       case CONF_TX_AC_BK:
+               return 3;
+       default:
+               return 2;
+       }
+}
+
+static inline int wl1271_tx_total_queue_count(struct wl1271 *wl)
+{
+       int i, count = 0;
+
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               count += wl->tx_queue_count[i];
+
+       return count;
+}
+
 void wl1271_tx_work(struct work_struct *work);
 void wl1271_tx_work_locked(struct wl1271 *wl);
 void wl1271_tx_complete(struct wl1271 *wl);
index d7db6e7..1a8751e 100644 (file)
@@ -144,6 +144,7 @@ extern u32 wl12xx_debug_level;
 
 #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
 #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff
 
 #define WL1271_CIPHER_SUITE_GEM 0x00147201
 
@@ -172,7 +173,6 @@ extern u32 wl12xx_debug_level;
 #define WL1271_PS_STA_MAX_BLOCKS  (2 * 9)
 
 #define WL1271_AP_BSS_INDEX        0
-#define WL1271_AP_DEF_INACTIV_SEC  300
 #define WL1271_AP_DEF_BEACON_EXP   20
 
 #define ACX_TX_DESCRIPTORS         32
@@ -424,7 +424,7 @@ struct wl1271 {
        /* Accounting for allocated / available TX blocks on HW */
        u32 tx_blocks_freed[NUM_TX_QUEUES];
        u32 tx_blocks_available;
-       u32 tx_allocated_blocks;
+       u32 tx_allocated_blocks[NUM_TX_QUEUES];
        u32 tx_results_count;
 
        /* Transmitted TX packets counter for chipset interface */
@@ -438,7 +438,8 @@ struct wl1271 {
 
        /* Frames scheduled for transmission, not handled yet */
        struct sk_buff_head tx_queue[NUM_TX_QUEUES];
-       int tx_queue_count;
+       int tx_queue_count[NUM_TX_QUEUES];
+       long stopped_queues_map;
 
        /* Frames received, not handled yet by mac80211 */
        struct sk_buff_head deferred_rx_queue;
@@ -454,9 +455,16 @@ struct wl1271 {
        struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
        int tx_frames_cnt;
 
-       /* Security sequence number counters */
-       u8 tx_security_last_seq;
-       s64 tx_security_seq;
+       /*
+        * Security sequence number
+        *     bits 0-15: lower 16 bits part of sequence number
+        *     bits 16-47: higher 32 bits part of sequence number
+        *     bits 48-63: not in use
+        */
+       u64 tx_security_seq;
+
+       /* 8 bits of the last sequence number in use */
+       u8 tx_security_last_seq_lsb;
 
        /* FW Rx counter */
        u32 rx_counter;
@@ -632,8 +640,8 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
 
 #define WL1271_DEFAULT_POWER_LEVEL 0
 
-#define WL1271_TX_QUEUE_LOW_WATERMARK  10
-#define WL1271_TX_QUEUE_HIGH_WATERMARK 25
+#define WL1271_TX_QUEUE_LOW_WATERMARK  32
+#define WL1271_TX_QUEUE_HIGH_WATERMARK 256
 
 #define WL1271_DEFERRED_QUEUE_LIMIT    64
 
index 3ec2f94..8cb025a 100644 (file)
  *     passed, all channels allowed for the current regulatory domain
  *     are used.  Extra IEs can also be passed from the userspace by
  *     using the %NL80211_ATTR_IE attribute.
- * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
+ *     if scheduled scan is not running.
  * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
  *     results available.
  * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
index 7bccaf9..e727555 100644 (file)
@@ -56,6 +56,7 @@
 #define BT_SECURITY    4
 struct bt_security {
        __u8 level;
+       __u8 key_size;
 };
 #define BT_SECURITY_SDP                0
 #define BT_SECURITY_LOW                1
@@ -76,9 +77,12 @@ struct bt_power {
 #define BT_POWER_FORCE_ACTIVE_OFF 0
 #define BT_POWER_FORCE_ACTIVE_ON  1
 
-#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
-#define BT_ERR(fmt, arg...)  printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
-#define BT_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
+__attribute__((format (printf, 2, 3)))
+int bt_printk(const char *level, const char *fmt, ...);
+
+#define BT_INFO(fmt, arg...)   bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
+#define BT_ERR(fmt, arg...)    bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
+#define BT_DBG(fmt, arg...)    pr_debug(fmt "\n", ##arg)
 
 /* Connection and socket states */
 enum {
@@ -204,7 +208,7 @@ out:
        return NULL;
 }
 
-int bt_err(__u16 code);
+int bt_to_errno(__u16 code);
 
 extern int hci_sock_init(void);
 extern void hci_sock_cleanup(void);
index 65345cd..be30aab 100644 (file)
@@ -211,11 +211,16 @@ enum {
 #define LMP_EDR_3S_ESCO        0x80
 
 #define LMP_EXT_INQ    0x01
+#define LMP_SIMUL_LE_BR        0x02
 #define LMP_SIMPLE_PAIR        0x08
 #define LMP_NO_FLUSH   0x40
 
 #define LMP_LSTO       0x01
 #define LMP_INQ_TX_PWR 0x02
+#define LMP_EXTFEATURES        0x80
+
+/* Extended LMP features */
+#define LMP_HOST_LE    0x02
 
 /* Connection modes */
 #define HCI_CM_ACTIVE  0x0000
@@ -254,6 +259,10 @@ enum {
 #define HCI_LK_UNAUTH_COMBINATION      0x04
 #define HCI_LK_AUTH_COMBINATION                0x05
 #define HCI_LK_CHANGED_COMBINATION     0x06
+/* The spec doesn't define types for SMP keys */
+#define HCI_LK_SMP_LTK                 0x81
+#define HCI_LK_SMP_IRK                 0x82
+#define HCI_LK_SMP_CSRK                        0x83
 
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
@@ -653,6 +662,12 @@ struct hci_rp_read_local_oob_data {
 
 #define HCI_OP_READ_INQ_RSP_TX_POWER   0x0c58
 
+#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
+struct hci_cp_write_le_host_supported {
+       __u8 le;
+       __u8 simul;
+} __packed;
+
 #define HCI_OP_READ_LOCAL_VERSION      0x1001
 struct hci_rp_read_local_version {
        __u8     status;
@@ -676,6 +691,9 @@ struct hci_rp_read_local_features {
 } __packed;
 
 #define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+struct hci_cp_read_local_ext_features {
+       __u8     page;
+} __packed;
 struct hci_rp_read_local_ext_features {
        __u8     status;
        __u8     page;
index 19639df..8f441b8 100644 (file)
@@ -75,12 +75,28 @@ struct bt_uuid {
        u8 svc_hint;
 };
 
+struct key_master_id {
+       __le16 ediv;
+       u8 rand[8];
+} __packed;
+
+struct link_key_data {
+       bdaddr_t bdaddr;
+       u8 type;
+       u8 val[16];
+       u8 pin_len;
+       u8 dlen;
+       u8 data[0];
+} __packed;
+
 struct link_key {
        struct list_head list;
        bdaddr_t bdaddr;
        u8 type;
        u8 val[16];
        u8 pin_len;
+       u8 dlen;
+       u8 data[0];
 };
 
 struct oob_data {
@@ -114,6 +130,7 @@ struct hci_dev {
        __u8            major_class;
        __u8            minor_class;
        __u8            features[8];
+       __u8            extfeatures[8];
        __u8            commands[64];
        __u8            ssp_mode;
        __u8            hci_ver;
@@ -224,7 +241,6 @@ struct hci_conn {
        struct list_head list;
 
        atomic_t        refcnt;
-       spinlock_t      lock;
 
        bdaddr_t        dst;
        __u8            dst_type;
@@ -246,11 +262,11 @@ struct hci_conn {
        __u8            sec_level;
        __u8            pending_sec_level;
        __u8            pin_length;
+       __u8            enc_key_size;
        __u8            io_capability;
        __u8            power_save;
        __u16           disc_timeout;
        unsigned long   pend;
-       __u8            ltk[16];
 
        __u8            remote_cap;
        __u8            remote_oob;
@@ -273,7 +289,6 @@ struct hci_conn {
        struct hci_dev  *hdev;
        void            *l2cap_data;
        void            *sco_data;
-       void            *priv;
 
        struct hci_conn *link;
 
@@ -539,6 +554,11 @@ int hci_link_keys_clear(struct hci_dev *hdev);
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                        bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
+struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
+                                       bdaddr_t *bdaddr, u8 type);
+int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
@@ -580,6 +600,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
 #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
 
+/* ----- Extended LMP capabilities ----- */
+#define lmp_host_le_capable(dev)   ((dev)->extfeatures[0] & LMP_HOST_LE)
+
 /* ----- HCI protocols ----- */
 struct hci_proto {
        char            *name;
index 9c18e55..4f34ad2 100644 (file)
@@ -37,7 +37,6 @@
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
-#define L2CAP_LOCAL_BUSY_TRIES         12
 #define L2CAP_LE_DEFAULT_MTU           23
 
 #define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
@@ -130,6 +129,12 @@ struct l2cap_conninfo {
 #define L2CAP_SDU_END               0x8000
 #define L2CAP_SDU_CONTINUE          0xC000
 
+/* L2CAP Command rej. reasons */
+#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
+#define L2CAP_REJ_MTU_EXCEEDED        0x0001
+#define L2CAP_REJ_INVALID_CID         0x0002
+
+
 /* L2CAP structures */
 struct l2cap_hdr {
        __le16     len;
@@ -144,8 +149,19 @@ struct l2cap_cmd_hdr {
 } __packed;
 #define L2CAP_CMD_HDR_SIZE     4
 
-struct l2cap_cmd_rej {
+struct l2cap_cmd_rej_unk {
+       __le16     reason;
+} __packed;
+
+struct l2cap_cmd_rej_mtu {
        __le16     reason;
+       __le16     max_mtu;
+} __packed;
+
+struct l2cap_cmd_rej_cid {
+       __le16     reason;
+       __le16     scid;
+       __le16     dcid;
 } __packed;
 
 struct l2cap_conn_req {
@@ -352,8 +368,6 @@ struct l2cap_chan {
        struct sk_buff          *tx_send_head;
        struct sk_buff_head     tx_q;
        struct sk_buff_head     srej_q;
-       struct sk_buff_head     busy_q;
-       struct work_struct      busy_work;
        struct list_head        srej_l;
 
        struct list_head list;
@@ -422,6 +436,7 @@ struct l2cap_conn {
 struct l2cap_pinfo {
        struct bt_sock  bt;
        struct l2cap_chan       *chan;
+       struct sk_buff  *rx_busy_skb;
 };
 
 enum {
@@ -449,7 +464,6 @@ enum {
        CONN_REJ_ACT,
        CONN_SEND_FBIT,
        CONN_RNR_SENT,
-       CONN_SAR_RETRY,
 };
 
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
@@ -498,5 +512,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 
 #endif /* __L2CAP_H */
index 45bea25..5428fd3 100644 (file)
@@ -101,6 +101,8 @@ struct mgmt_key_info {
        u8 type;
        u8 val[16];
        u8 pin_len;
+       u8 dlen;
+       u8 data[0];
 } __packed;
 
 #define MGMT_OP_LOAD_KEYS              0x000D
index 4fb7d19..46c4576 100644 (file)
@@ -118,5 +118,6 @@ struct smp_cmd_security_req {
 /* SMP Commands */
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
+int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
 
 #endif /* __SMP_H */
index 4bf101b..5390e32 100644 (file)
@@ -3055,6 +3055,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
  * @dev: network device
  * @bssid: BSSID of AP (to avoid races)
  * @replay_ctr: new replay counter
+ * @gfp: allocation flags
  */
 void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
                               const u8 *replay_ctr, gfp_t gfp);
index 2474019..ea2c8c3 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/device.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
+#include <asm/unaligned.h>
 
 /**
  * DOC: Introduction
@@ -192,6 +193,17 @@ enum ieee80211_bss_change {
  */
 #define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
 
+/**
+ * enum ieee80211_rssi_event - RSSI threshold event
+ * An indicator for when RSSI goes below/above a certain threshold.
+ * @RSSI_EVENT_HIGH: AP's rssi crossed the high threshold set by the driver.
+ * @RSSI_EVENT_LOW: AP's rssi crossed the low threshold set by the driver.
+ */
+enum ieee80211_rssi_event {
+       RSSI_EVENT_HIGH,
+       RSSI_EVENT_LOW,
+};
+
 /**
  * struct ieee80211_bss_conf - holds the BSS's changing parameters
  *
@@ -961,21 +973,6 @@ enum sta_notify_cmd {
        STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE,
 };
 
-/**
- * enum ieee80211_tkip_key_type - get tkip key
- *
- * Used by drivers which need to get a tkip key for skb. Some drivers need a
- * phase 1 key, others need a phase 2 key. A single function allows the driver
- * to get the key, this enum indicates what type of key is required.
- *
- * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key
- * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key
- */
-enum ieee80211_tkip_key_type {
-       IEEE80211_TKIP_P1_KEY,
-       IEEE80211_TKIP_P2_KEY,
-};
-
 /**
  * enum ieee80211_hw_flags - hardware flags
  *
@@ -1881,6 +1878,8 @@ enum ieee80211_ampdu_mlme_action {
  * @set_bitrate_mask: Set a mask of rates to be used for rate control selection
  *     when transmitting a frame. Currently only legacy rates are handled.
  *     The callback can sleep.
+ * @rssi_callback: Notify driver when the average RSSI goes above/below
+ *     thresholds that were registered previously. The callback can sleep.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1989,6 +1988,8 @@ struct ieee80211_ops {
        bool (*tx_frames_pending)(struct ieee80211_hw *hw);
        int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                                const struct cfg80211_bitrate_mask *mask);
+       void (*rssi_callback)(struct ieee80211_hw *hw,
+                             enum ieee80211_rssi_event rssi_event);
 };
 
 /**
@@ -2579,21 +2580,111 @@ struct sk_buff *
 ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 
 /**
- * ieee80211_get_tkip_key - get a TKIP rc4 for skb
+ * ieee80211_get_tkip_p1k_iv - get a TKIP phase 1 key for IV32
+ *
+ * This function returns the TKIP phase 1 key for the given IV32.
+ *
+ * @keyconf: the parameter passed with the set key
+ * @iv32: IV32 to get the P1K for
+ * @p1k: a buffer to which the key will be written, as 5 u16 values
+ */
+void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf,
+                              u32 iv32, u16 *p1k);
+
+/**
+ * ieee80211_get_tkip_p1k - get a TKIP phase 1 key
+ *
+ * This function returns the TKIP phase 1 key for the IV32 taken
+ * from the given packet.
+ *
+ * @keyconf: the parameter passed with the set key
+ * @skb: the packet to take the IV32 value from that will be encrypted
+ *     with this P1K
+ * @p1k: a buffer to which the key will be written, as 5 u16 values
+ */
+static inline void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf,
+                                         struct sk_buff *skb, u16 *p1k)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
+       u32 iv32 = get_unaligned_le32(&data[4]);
+
+       ieee80211_get_tkip_p1k_iv(keyconf, iv32, p1k);
+}
+
+/**
+ * ieee80211_get_tkip_p2k - get a TKIP phase 2 key
+ *
+ * This function computes the TKIP RC4 key for the IV values
+ * in the packet.
+ *
+ * @keyconf: the parameter passed with the set key
+ * @skb: the packet to take the IV32/IV16 values from that will be
+ *     encrypted with this key
+ * @p2k: a buffer to which the key will be written, 16 bytes
+ */
+void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
+                           struct sk_buff *skb, u8 *p2k);
+
+/**
+ * struct ieee80211_key_seq - key sequence counter
  *
- * This function computes a TKIP rc4 key for an skb. It computes
- * a phase 1 key if needed (iv16 wraps around). This function is to
- * be used by drivers which can do HW encryption but need to compute
- * to phase 1/2 key in SW.
+ * @tkip: TKIP data, containing IV32 and IV16 in host byte order
+ * @ccmp: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ * @aes_cmac: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ */
+struct ieee80211_key_seq {
+       union {
+               struct {
+                       u32 iv32;
+                       u16 iv16;
+               } tkip;
+               struct {
+                       u8 pn[6];
+               } ccmp;
+               struct {
+                       u8 pn[6];
+               } aes_cmac;
+       };
+};
+
+/**
+ * ieee80211_get_key_tx_seq - get key TX sequence counter
  *
  * @keyconf: the parameter passed with the set key
- * @skb: the skb for which the key is needed
- * @type: TBD
- * @key: a buffer to which the key will be written
+ * @seq: buffer to receive the sequence data
+ *
+ * This function allows a driver to retrieve the current TX IV/PN
+ * for the given key. It must not be called if IV generation is
+ * offloaded to the device.
+ *
+ * Note that this function may only be called when no TX processing
+ * can be done concurrently, for example when queues are stopped
+ * and the stop has been synchronized.
  */
-void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
-                               struct sk_buff *skb,
-                               enum ieee80211_tkip_key_type type, u8 *key);
+void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
+                             struct ieee80211_key_seq *seq);
+
+/**
+ * ieee80211_get_key_rx_seq - get key RX sequence counter
+ *
+ * @keyconf: the parameter passed with the set key
+ * @tid: The TID, or -1 for the management frame value (CCMP only);
+ *     the value on TID 0 is also used for non-QoS frames. For
+ *     CMAC, only TID 0 is valid.
+ * @seq: buffer to receive the sequence data
+ *
+ * This function allows a driver to retrieve the current RX IV/PNs
+ * for the given key. It must not be called if IV checking is done
+ * by the device and not by mac80211.
+ *
+ * Note that this function may only be called when no RX processing
+ * can be done concurrently.
+ */
+void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
+                             int tid, struct ieee80211_key_seq *seq);
 
 /**
  * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
@@ -2932,6 +3023,29 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  */
 void ieee80211_connection_loss(struct ieee80211_vif *vif);
 
+/**
+ * ieee80211_resume_disconnect - disconnect from AP after resume
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Instructs mac80211 to disconnect from the AP after resume.
+ * Drivers can use this after WoWLAN if they know that the
+ * connection cannot be kept up, for example because keys were
+ * used while the device was asleep but the replay counters or
+ * similar cannot be retrieved from the device during resume.
+ *
+ * Note that due to implementation issues, if the driver uses
+ * the reconfiguration functionality during resume the interface
+ * will still be added as associated first during resume and then
+ * disconnect normally later.
+ *
+ * This function can only be called from the resume callback and
+ * the driver must not be holding any of its own locks while it
+ * calls this function, or at least not any locks it needs in the
+ * key configuration paths (if it supports HW crypto).
+ */
+void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
+
 /**
  * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
  *
@@ -3240,4 +3354,9 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
        return ieee80211_iftype_p2p(vif->type, vif->p2p);
 }
 
+void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
+                                  int rssi_min_thold,
+                                  int rssi_max_thold);
+
+void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
 #endif /* MAC80211_H */
index b18db56..ec0bc3f 100644 (file)
@@ -60,8 +60,6 @@ static void hci_tx_task(unsigned long arg);
 
 static DEFINE_RWLOCK(hci_task_lock);
 
-static int enable_smp;
-
 /* HCI device list */
 LIST_HEAD(hci_dev_list);
 DEFINE_RWLOCK(hci_dev_list_lock);
@@ -148,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
 
        switch (hdev->req_status) {
        case HCI_REQ_DONE:
-               err = -bt_err(hdev->req_result);
+               err = -bt_to_errno(hdev->req_result);
                break;
 
        case HCI_REQ_CANCELED:
@@ -542,7 +540,7 @@ int hci_dev_open(__u16 dev)
                ret = __hci_request(hdev, hci_init_req, 0,
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
-               if (lmp_le_capable(hdev))
+               if (lmp_host_le_capable(hdev))
                        ret = __hci_request(hdev, hci_le_init_req, 0,
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
@@ -1059,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
        return 0;
 }
 
+struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+{
+       struct link_key *k;
+
+       list_for_each_entry(k, &hdev->link_keys, list) {
+               struct key_master_id *id;
+
+               if (k->type != HCI_LK_SMP_LTK)
+                       continue;
+
+               if (k->dlen != sizeof(*id))
+                       continue;
+
+               id = (void *) &k->data;
+               if (id->ediv == ediv &&
+                               (memcmp(rand, id->rand, sizeof(id->rand)) == 0))
+                       return k;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(hci_find_ltk);
+
+struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
+                                       bdaddr_t *bdaddr, u8 type)
+{
+       struct link_key *k;
+
+       list_for_each_entry(k, &hdev->link_keys, list)
+               if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+                       return k;
+
+       return NULL;
+}
+EXPORT_SYMBOL(hci_find_link_key_type);
+
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                                bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
@@ -1114,6 +1148,44 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
        return 0;
 }
 
+int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+                       u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
+{
+       struct link_key *key, *old_key;
+       struct key_master_id *id;
+       u8 old_key_type;
+
+       BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+
+       old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
+       if (old_key) {
+               key = old_key;
+               old_key_type = old_key->type;
+       } else {
+               key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+               if (!key)
+                       return -ENOMEM;
+               list_add(&key->list, &hdev->link_keys);
+               old_key_type = 0xff;
+       }
+
+       key->dlen = sizeof(*id);
+
+       bacpy(&key->bdaddr, bdaddr);
+       memcpy(key->val, ltk, sizeof(key->val));
+       key->type = HCI_LK_SMP_LTK;
+       key->pin_len = key_size;
+
+       id = (void *) &key->data;
+       id->ediv = ediv;
+       memcpy(id->rand, rand, sizeof(id->rand));
+
+       if (new_key)
+               mgmt_new_key(hdev->id, key, old_key_type);
+
+       return 0;
+}
+
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct link_key *key;
@@ -1246,7 +1318,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
        if (bacmp(bdaddr, BDADDR_ANY) == 0)
                return -EBADF;
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (hci_blacklist_lookup(hdev, bdaddr)) {
                err = -EEXIST;
@@ -1266,7 +1338,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
        err = 0;
 
 err:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        return err;
 }
 
@@ -1275,7 +1347,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        struct bdaddr_list *entry;
        int err = 0;
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (bacmp(bdaddr, BDADDR_ANY) == 0) {
                hci_blacklist_clear(hdev);
@@ -1292,7 +1364,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        kfree(entry);
 
 done:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        return err;
 }
 
@@ -1368,14 +1440,6 @@ int hci_add_adv_entry(struct hci_dev *hdev,
        return 0;
 }
 
-static struct crypto_blkcipher *alloc_cypher(void)
-{
-       if (enable_smp)
-               return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-
-       return ERR_PTR(-ENOTSUPP);
-}
-
 /* Register HCI device */
 int hci_register_dev(struct hci_dev *hdev)
 {
@@ -1460,7 +1524,7 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->workqueue)
                goto nomem;
 
-       hdev->tfm = alloc_cypher();
+       hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(hdev->tfm))
                BT_INFO("Failed to load transform for ecb(aes): %ld",
                                                        PTR_ERR(hdev->tfm));
@@ -2352,6 +2416,3 @@ static void hci_cmd_task(unsigned long arg)
                }
        }
 }
-
-module_param(enable_smp, bool, 0644);
-MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");
index ac2c5e8..a40170e 100644 (file)
@@ -45,6 +45,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+static int enable_le;
+
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -525,6 +527,20 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 
+static void hci_set_le_support(struct hci_dev *hdev)
+{
+       struct hci_cp_write_le_host_supported cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (enable_le) {
+               cp.le = 1;
+               cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+       }
+
+       hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
+}
+
 static void hci_setup(struct hci_dev *hdev)
 {
        hci_setup_event_mask(hdev);
@@ -542,6 +558,17 @@ static void hci_setup(struct hci_dev *hdev)
 
        if (hdev->features[7] & LMP_INQ_TX_PWR)
                hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
+
+       if (hdev->features[7] & LMP_EXTFEATURES) {
+               struct hci_cp_read_local_ext_features cp;
+
+               cp.page = 0x01;
+               hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
+                                                       sizeof(cp), &cp);
+       }
+
+       if (hdev->features[4] & LMP_LE)
+               hci_set_le_support(hdev);
 }
 
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
@@ -658,6 +685,21 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
                                        hdev->features[6], hdev->features[7]);
 }
 
+static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+{
+       struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       memcpy(hdev->extfeatures, rp->features, 8);
+
+       hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
+}
+
 static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_buffer_size *rp = (void *) skb->data;
@@ -892,6 +934,21 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
 }
 
+static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+{
+       struct hci_cp_read_local_ext_features cp;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp.page = 0x01;
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
+}
+
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1826,6 +1883,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_read_local_features(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_EXT_FEATURES:
+               hci_cc_read_local_ext_features(hdev, skb);
+               break;
+
        case HCI_OP_READ_BUFFER_SIZE:
                hci_cc_read_buffer_size(hdev, skb);
                break;
@@ -1894,6 +1955,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_le_ltk_neg_reply(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_LE_HOST_SUPPORTED:
+               hci_cc_write_le_host_supported(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%x", hdev->name, opcode);
                break;
@@ -2793,21 +2858,36 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 {
        struct hci_ev_le_ltk_req *ev = (void *) skb->data;
        struct hci_cp_le_ltk_reply cp;
+       struct hci_cp_le_ltk_neg_reply neg;
        struct hci_conn *conn;
+       struct link_key *ltk;
 
        BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
 
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (conn == NULL)
+               goto not_found;
 
-       memset(&cp, 0, sizeof(cp));
+       ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
+       if (ltk == NULL)
+               goto not_found;
+
+       memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
        cp.handle = cpu_to_le16(conn->handle);
-       memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk));
+       conn->pin_length = ltk->pin_len;
 
        hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
        hci_dev_unlock(hdev);
+
+       return;
+
+not_found:
+       neg.handle = ev->handle;
+       hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3022,3 +3102,6 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        hci_send_to_sock(hdev, skb, NULL);
        kfree_skb(skb);
 }
+
+module_param(enable_le, bool, 0444);
+MODULE_PARM_DESC(enable_le, "Enable LE support");
index fc219ec..f7f8e2c 100644 (file)
@@ -61,13 +61,9 @@ int disable_ertm;
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
 
-static struct workqueue_struct *_busy_wq;
-
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
 
-static void l2cap_busy_work(struct work_struct *work);
-
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
                                u8 code, u8 ident, u16 dlen, void *data);
 static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
@@ -223,18 +219,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 
 static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
+       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
 
-       if (!mod_timer(timer, jiffies + timeout))
-              chan_hold(chan);
+       if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
+               chan_hold(chan);
 }
 
 static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
 {
-       BT_DBG("chan %p state %d", chan, chan->state);
+       BT_DBG("chan %p state %d", chan, chan->state);
 
-       if (timer_pending(timer) && del_timer(timer))
-              chan_put(chan);
+       if (timer_pending(timer) && del_timer(timer))
+               chan_put(chan);
 }
 
 static void l2cap_state_change(struct l2cap_chan *chan, int state)
@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
                __clear_ack_timer(chan);
 
                skb_queue_purge(&chan->srej_q);
-               skb_queue_purge(&chan->busy_q);
 
                list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                        list_del(&l->list);
@@ -741,9 +736,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                        &chan->conf_state)) {
                                /* l2cap_chan_close() calls list_del(chan)
                                 * so release the lock */
-                               read_unlock_bh(&conn->chan_lock);
+                               read_unlock(&conn->chan_lock);
                                l2cap_chan_close(chan, ECONNRESET);
-                               read_lock_bh(&conn->chan_lock);
+                               read_lock(&conn->chan_lock);
                                bh_unlock_sock(sk);
                                continue;
                        }
@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
        setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
 
        skb_queue_head_init(&chan->srej_q);
-       skb_queue_head_init(&chan->busy_q);
 
        INIT_LIST_HEAD(&chan->srej_l);
 
-       INIT_WORK(&chan->busy_work, l2cap_busy_work);
 
        sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
 }
@@ -2284,9 +2277,9 @@ done:
 
 static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
-       struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
+       struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
 
-       if (rej->reason != 0x0000)
+       if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
                return 0;
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
@@ -2532,9 +2525,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        if ((bt_sk(sk)->defer_setup && chan->state != BT_CONNECT2) ||
                 (!bt_sk(sk)->defer_setup && chan->state != BT_CONFIG)) {
-               struct l2cap_cmd_rej rej;
+               struct l2cap_cmd_rej_cid rej;
+
+               rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
+               rej.scid = cpu_to_le16(chan->scid);
+               rej.dcid = cpu_to_le16(chan->dcid);
 
-               rej.reason = cpu_to_le16(0x0002);
                l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
                                sizeof(rej), &rej);
                goto unlock;
@@ -3025,12 +3021,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                        err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
 
                if (err) {
-                       struct l2cap_cmd_rej rej;
+                       struct l2cap_cmd_rej_unk rej;
 
                        BT_ERR("Wrong link type (%d)", err);
 
                        /* FIXME: Map err to a valid reason */
-                       rej.reason = cpu_to_le16(0);
+                       rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
                        l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
                }
 
@@ -3183,32 +3179,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk
                if (!chan->sdu)
                        goto disconnect;
 
-               if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) {
-                       chan->partial_sdu_len += skb->len;
+               chan->partial_sdu_len += skb->len;
 
-                       if (chan->partial_sdu_len > chan->imtu)
-                               goto drop;
+               if (chan->partial_sdu_len > chan->imtu)
+                       goto drop;
 
-                       if (chan->partial_sdu_len != chan->sdu_len)
-                               goto drop;
+               if (chan->partial_sdu_len != chan->sdu_len)
+                       goto drop;
 
-                       memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
-               }
+               memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
 
                _skb = skb_clone(chan->sdu, GFP_ATOMIC);
                if (!_skb) {
-                       set_bit(CONN_SAR_RETRY, &chan->conn_state);
                        return -ENOMEM;
                }
 
                err = chan->ops->recv(chan->data, _skb);
                if (err < 0) {
                        kfree_skb(_skb);
-                       set_bit(CONN_SAR_RETRY, &chan->conn_state);
                        return err;
                }
 
-               clear_bit(CONN_SAR_RETRY, &chan->conn_state);
                clear_bit(CONN_SAR_SDU, &chan->conn_state);
 
                kfree_skb(chan->sdu);
@@ -3228,22 +3219,26 @@ disconnect:
        return 0;
 }
 
-static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
+static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       struct sk_buff *skb;
        u16 control;
-       int err;
 
-       while ((skb = skb_dequeue(&chan->busy_q))) {
-               control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-               err = l2cap_ertm_reassembly_sdu(chan, skb, control);
-               if (err < 0) {
-                       skb_queue_head(&chan->busy_q, skb);
-                       return -EBUSY;
-               }
+       BT_DBG("chan %p, Enter local busy", chan);
 
-               chan->buffer_seq = (chan->buffer_seq + 1) % 64;
-       }
+       set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+
+       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= L2CAP_SUPER_RCV_NOT_READY;
+       l2cap_send_sframe(chan, control);
+
+       set_bit(CONN_RNR_SENT, &chan->conn_state);
+
+       __clear_ack_timer(chan);
+}
+
+static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
+{
+       u16 control;
 
        if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
                goto done;
@@ -3263,93 +3258,16 @@ done:
        clear_bit(CONN_RNR_SENT, &chan->conn_state);
 
        BT_DBG("chan %p, Exit local busy", chan);
-
-       return 0;
 }
 
-static void l2cap_busy_work(struct work_struct *work)
+void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       struct l2cap_chan *chan =
-               container_of(work, struct l2cap_chan, busy_work);
-       struct sock *sk = chan->sk;
-       int n_tries = 0, timeo = HZ/5, err;
-       struct sk_buff *skb;
-
-       lock_sock(sk);
-
-       add_wait_queue(sk_sleep(sk), &wait);
-       while ((skb = skb_peek(&chan->busy_q))) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
-                       err = -EBUSY;
-                       l2cap_send_disconn_req(chan->conn, chan, EBUSY);
-                       break;
-               }
-
-               if (!timeo)
-                       timeo = HZ/5;
-
-               if (signal_pending(current)) {
-                       err = sock_intr_errno(timeo);
-                       break;
-               }
-
-               release_sock(sk);
-               timeo = schedule_timeout(timeo);
-               lock_sock(sk);
-
-               err = sock_error(sk);
-               if (err)
-                       break;
-
-               if (l2cap_try_push_rx_skb(chan) == 0)
-                       break;
-       }
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk_sleep(sk), &wait);
-
-       release_sock(sk);
-}
-
-static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
-{
-       int sctrl, err;
-
-       if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
-               __skb_queue_tail(&chan->busy_q, skb);
-               return l2cap_try_push_rx_skb(chan);
-
-
-       }
-
-       err = l2cap_ertm_reassembly_sdu(chan, skb, control);
-       if (err >= 0) {
-               chan->buffer_seq = (chan->buffer_seq + 1) % 64;
-               return err;
+       if (chan->mode == L2CAP_MODE_ERTM) {
+               if (busy)
+                       l2cap_ertm_enter_local_busy(chan);
+               else
+                       l2cap_ertm_exit_local_busy(chan);
        }
-
-       /* Busy Condition */
-       BT_DBG("chan %p, Enter local busy", chan);
-
-       set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
-       bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
-       __skb_queue_tail(&chan->busy_q, skb);
-
-       sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       sctrl |= L2CAP_SUPER_RCV_NOT_READY;
-       l2cap_send_sframe(chan, sctrl);
-
-       set_bit(CONN_RNR_SENT, &chan->conn_state);
-
-       __clear_ack_timer(chan);
-
-       queue_work(_busy_wq, &chan->busy_work);
-
-       return err;
 }
 
 static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
@@ -3450,13 +3368,22 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
        struct sk_buff *skb;
        u16 control;
 
-       while ((skb = skb_peek(&chan->srej_q))) {
+       while ((skb = skb_peek(&chan->srej_q)) &&
+                       !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+               int err;
+
                if (bt_cb(skb)->tx_seq != tx_seq)
                        break;
 
                skb = skb_dequeue(&chan->srej_q);
                control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-               l2cap_ertm_reassembly_sdu(chan, skb, control);
+               err = l2cap_ertm_reassembly_sdu(chan, skb, control);
+
+               if (err < 0) {
+                       l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+                       break;
+               }
+
                chan->buffer_seq_srej =
                        (chan->buffer_seq_srej + 1) % 64;
                tx_seq = (tx_seq + 1) % 64;
@@ -3523,9 +3450,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        chan->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (tx_seq == chan->expected_tx_seq)
-               goto expected;
-
        tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
        if (tx_seq_offset < 0)
                tx_seq_offset += 64;
@@ -3539,6 +3463,9 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
                goto drop;
 
+       if (tx_seq == chan->expected_tx_seq)
+               goto expected;
+
        if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                struct srej_list *first;
 
@@ -3590,7 +3517,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
                chan->buffer_seq_srej = chan->buffer_seq;
 
                __skb_queue_head_init(&chan->srej_q);
-               __skb_queue_head_init(&chan->busy_q);
                l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
 
                set_bit(CONN_SEND_PBIT, &chan->conn_state);
@@ -3611,9 +3537,12 @@ expected:
                return 0;
        }
 
-       err = l2cap_push_rx_skb(chan, skb, rx_control);
-       if (err < 0)
-               return 0;
+       err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control);
+       chan->buffer_seq = (chan->buffer_seq + 1) % 64;
+       if (err < 0) {
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return err;
+       }
 
        if (rx_control & L2CAP_CTRL_FINAL) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -4108,7 +4037,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
                if (conn)
                        l2cap_conn_ready(conn);
        } else
-               l2cap_conn_del(hcon, bt_err(status));
+               l2cap_conn_del(hcon, bt_to_errno(status));
 
        return 0;
 }
@@ -4132,7 +4061,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
        if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
                return -EINVAL;
 
-       l2cap_conn_del(hcon, bt_err(reason));
+       l2cap_conn_del(hcon, bt_to_errno(reason));
 
        return 0;
 }
@@ -4178,6 +4107,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                chan->sec_level = hcon->sec_level;
                                del_timer(&conn->security_timer);
                                l2cap_chan_ready(sk);
+                               smp_distribute_keys(conn, 0);
                        }
 
                        bh_unlock_sock(sk);
@@ -4415,12 +4345,6 @@ int __init l2cap_init(void)
        if (err < 0)
                return err;
 
-       _busy_wq = create_singlethread_workqueue("l2cap");
-       if (!_busy_wq) {
-               err = -ENOMEM;
-               goto error;
-       }
-
        err = hci_register_proto(&l2cap_hci_proto);
        if (err < 0) {
                BT_ERR("L2CAP protocol registration failed");
@@ -4438,7 +4362,6 @@ int __init l2cap_init(void)
        return 0;
 
 error:
-       destroy_workqueue(_busy_wq);
        l2cap_cleanup_sockets();
        return err;
 }
@@ -4447,9 +4370,6 @@ void l2cap_exit(void)
 {
        debugfs_remove(l2cap_debugfs);
 
-       flush_workqueue(_busy_wq);
-       destroy_workqueue(_busy_wq);
-
        if (hci_unregister_proto(&l2cap_hci_proto) < 0)
                BT_ERR("L2CAP protocol unregistration failed");
 
index 39082d4..5c36b3e 100644 (file)
@@ -422,8 +422,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
+               memset(&sec, 0, sizeof(sec));
                sec.level = chan->sec_level;
 
+               if (sk->sk_state == BT_CONNECTED)
+                       sec.key_size = chan->conn->hcon->enc_key_size;
+
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
                        err = -EFAULT;
@@ -711,13 +715,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
 static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
 {
        struct sock *sk = sock->sk;
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       int err;
 
        lock_sock(sk);
 
        if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
                sk->sk_state = BT_CONFIG;
 
-               __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan);
+               __l2cap_connect_rsp_defer(pi->chan);
                release_sock(sk);
                return 0;
        }
@@ -725,9 +731,37 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
        release_sock(sk);
 
        if (sock->type == SOCK_STREAM)
-               return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+               err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+       else
+               err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
+
+       if (pi->chan->mode != L2CAP_MODE_ERTM)
+               return err;
+
+       /* Attempt to put pending rx data in the socket buffer */
+
+       lock_sock(sk);
+
+       if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state))
+               goto done;
+
+       if (pi->rx_busy_skb) {
+               if (!sock_queue_rcv_skb(sk, pi->rx_busy_skb))
+                       pi->rx_busy_skb = NULL;
+               else
+                       goto done;
+       }
 
-       return bt_sock_recvmsg(iocb, sock, msg, len, flags);
+       /* Restore data flow when half of the receive buffer is
+        * available.  This avoids resending large numbers of
+        * frames.
+        */
+       if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
+               l2cap_chan_busy(pi->chan, 0);
+
+done:
+       release_sock(sk);
+       return err;
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -811,9 +845,31 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
 
 static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
 {
+       int err;
        struct sock *sk = data;
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-       return sock_queue_rcv_skb(sk, skb);
+       if (pi->rx_busy_skb)
+               return -ENOMEM;
+
+       err = sock_queue_rcv_skb(sk, skb);
+
+       /* For ERTM, handle one skb that doesn't fit into the recv
+        * buffer.  This is important to do because the data frames
+        * have already been acked, so the skb cannot be discarded.
+        *
+        * Notify the l2cap core that the buffer is full, so the
+        * LOCAL_BUSY state is entered and no more frames are
+        * acked and reassembled until there is buffer space
+        * available.
+        */
+       if (err < 0 && pi->chan->mode == L2CAP_MODE_ERTM) {
+               pi->rx_busy_skb = skb;
+               l2cap_chan_busy(pi->chan, 1);
+               err = 0;
+       }
+
+       return err;
 }
 
 static void l2cap_sock_close_cb(void *data)
@@ -842,6 +898,11 @@ static void l2cap_sock_destruct(struct sock *sk)
 {
        BT_DBG("sk %p", sk);
 
+       if (l2cap_pi(sk)->rx_busy_skb) {
+               kfree_skb(l2cap_pi(sk)->rx_busy_skb);
+               l2cap_pi(sk)->rx_busy_skb = NULL;
+       }
+
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_write_queue);
 }
index b826d1b..86a6bed 100644 (file)
@@ -59,7 +59,7 @@ char *batostr(bdaddr_t *ba)
 EXPORT_SYMBOL(batostr);
 
 /* Bluetooth error codes to Unix errno mapping */
-int bt_err(__u16 code)
+int bt_to_errno(__u16 code)
 {
        switch (code) {
        case 0:
@@ -149,4 +149,23 @@ int bt_err(__u16 code)
                return ENOSYS;
        }
 }
-EXPORT_SYMBOL(bt_err);
+EXPORT_SYMBOL(bt_to_errno);
+
+int bt_printk(const char *level, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = printk("%sBluetooth: %pV\n", level, &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(bt_printk);
index 64c0418..53e109e 100644 (file)
@@ -179,7 +179,7 @@ static int read_controller_info(struct sock *sk, u16 index)
 
        hci_del_off_timer(hdev);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        set_bit(HCI_MGMT, &hdev->flags);
 
@@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index)
 
        memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
@@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        up = test_bit(HCI_UP, &hdev->flags);
        if ((cp->val && up) || (!cp->val && !up)) {
@@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
        err = 0;
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
        return err;
 }
@@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
@@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
@@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (cp->val)
                set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
        err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
        if (!uuid) {
@@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
        err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
                err = hci_uuids_clear(hdev);
@@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
        err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
 
 unlock:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        hdev->major_class = cp->major;
        hdev->minor_class = cp->minor;
@@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
        if (err == 0)
                err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        BT_DBG("hci%u enable %d", index, cp->enable);
 
@@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
                err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
                                                                        0);
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        struct hci_dev *hdev;
        struct mgmt_cp_load_keys *cp;
        u16 key_count, expected_len;
-       int i;
+       int i, err;
 
        cp = (void *) data;
 
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        key_count = get_unaligned_le16(&cp->key_count);
 
        expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
-       if (expected_len != len) {
-               BT_ERR("load_keys: expected %u bytes, got %u bytes",
-                                                       len, expected_len);
+       if (expected_len > len) {
+               BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
+                                                       expected_len, len);
                return -EINVAL;
        }
 
@@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
                                                                key_count);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        hci_link_keys_clear(hdev);
 
@@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        else
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
-       for (i = 0; i < key_count; i++) {
-               struct mgmt_key_info *key = &cp->keys[i];
+       len -= sizeof(*cp);
+       i = 0;
+
+       while (i < len) {
+               struct mgmt_key_info *key = (void *) cp->keys + i;
+
+               i += sizeof(*key) + key->dlen;
+
+               if (key->type == HCI_LK_SMP_LTK) {
+                       struct key_master_id *id = (void *) key->data;
+
+                       if (key->dlen != sizeof(struct key_master_id))
+                               continue;
+
+                       hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
+                                               id->ediv, id->rand, key->val);
+
+                       continue;
+               }
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
        }
 
-       hci_dev_unlock(hdev);
+       err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
+
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
-       return 0;
+       return err;
 }
 
 static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -971,7 +990,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        err = hci_remove_link_key(hdev, &cp->bdaddr);
        if (err < 0) {
@@ -994,7 +1013,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
        }
 
 unlock:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1020,7 +1039,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
@@ -1055,7 +1074,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1076,7 +1095,7 @@ static int get_connections(struct sock *sk, u16 index)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        count = 0;
        list_for_each(p, &hdev->conn_hash.list) {
@@ -1103,7 +1122,7 @@ static int get_connections(struct sock *sk, u16 index)
 
 unlock:
        kfree(rp);
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
        return err;
 }
@@ -1149,7 +1168,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
@@ -1190,7 +1209,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1216,7 +1235,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
                                                                        ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
@@ -1227,7 +1246,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
        err = send_pin_code_neg_reply(sk, index, hdev, cp);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1250,14 +1269,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        hdev->io_capability = cp->io_capability;
 
        BT_DBG("%s IO capability set to 0x%02x", hdev->name,
                                                        hdev->io_capability);
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
@@ -1343,7 +1362,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (cp->io_cap == 0x03) {
                sec_level = BT_SECURITY_MEDIUM;
@@ -1385,7 +1404,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
        err = 0;
 
 unlock:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1417,7 +1436,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, mgmt_op, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, mgmt_op, ENETDOWN);
@@ -1435,7 +1454,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1459,7 +1478,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
        if (!cmd) {
@@ -1474,7 +1493,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
                mgmt_pending_remove(cmd);
 
 failed:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1493,7 +1512,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
                return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
                                                                        ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        if (!test_bit(HCI_UP, &hdev->flags)) {
                err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
@@ -1523,7 +1542,7 @@ static int read_local_oob_data(struct sock *sk, u16 index)
                mgmt_pending_remove(cmd);
 
 unlock:
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1547,7 +1566,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
                                                                        ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
                                                                cp->randomizer);
@@ -1557,7 +1576,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
                err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
                                                                        0);
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1581,7 +1600,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
                return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
                                                                        ENODEV);
 
-       hci_dev_lock(hdev);
+       hci_dev_lock_bh(hdev);
 
        err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
        if (err < 0)
@@ -1591,7 +1610,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
                err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
                                                                NULL, 0);
 
-       hci_dev_unlock(hdev);
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1958,17 +1977,28 @@ int mgmt_connectable(u16 index, u8 connectable)
 
 int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
 {
-       struct mgmt_ev_new_key ev;
+       struct mgmt_ev_new_key *ev;
+       int err, total;
 
-       memset(&ev, 0, sizeof(ev));
+       total = sizeof(struct mgmt_ev_new_key) + key->dlen;
+       ev = kzalloc(total, GFP_ATOMIC);
+       if (!ev)
+               return -ENOMEM;
 
-       ev.store_hint = persistent;
-       bacpy(&ev.key.bdaddr, &key->bdaddr);
-       ev.key.type = key->type;
-       memcpy(ev.key.val, key->val, 16);
-       ev.key.pin_len = key->pin_len;
+       bacpy(&ev->key.bdaddr, &key->bdaddr);
+       ev->key.type = key->type;
+       memcpy(ev->key.val, key->val, 16);
+       ev->key.pin_len = key->pin_len;
+       ev->key.dlen = key->dlen;
+       ev->store_hint = persistent;
 
-       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
+       memcpy(ev->key.data, key->data, key->dlen);
+
+       err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
+
+       kfree(ev);
+
+       return err;
 }
 
 int mgmt_connected(u16 index, bdaddr_t *bdaddr)
index cb4fb78..4c3621b 100644 (file)
@@ -932,7 +932,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
                if (conn)
                        sco_conn_ready(conn);
        } else
-               sco_conn_del(hcon, bt_err(status));
+               sco_conn_del(hcon, bt_to_errno(status));
 
        return 0;
 }
@@ -944,7 +944,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
        if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
                return -EINVAL;
 
-       sco_conn_del(hcon, bt_err(reason));
+       sco_conn_del(hcon, bt_to_errno(reason));
 
        return 0;
 }
index a36f870..391888b 100644 (file)
@@ -197,14 +197,34 @@ static __u8 seclevel_to_authreq(__u8 level)
 }
 
 static void build_pairing_cmd(struct l2cap_conn *conn,
-                               struct smp_cmd_pairing *cmd, __u8 authreq)
+                               struct smp_cmd_pairing *req,
+                               struct smp_cmd_pairing *rsp,
+                               __u8 authreq)
 {
-       cmd->io_capability = conn->hcon->io_capability;
-       cmd->oob_flag = SMP_OOB_NOT_PRESENT;
-       cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
-       cmd->init_key_dist = 0x00;
-       cmd->resp_key_dist = 0x00;
-       cmd->auth_req = authreq;
+       u8 dist_keys;
+
+       dist_keys = 0;
+       if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
+               dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+               authreq |= SMP_AUTH_BONDING;
+       }
+
+       if (rsp == NULL) {
+               req->io_capability = conn->hcon->io_capability;
+               req->oob_flag = SMP_OOB_NOT_PRESENT;
+               req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+               req->init_key_dist = dist_keys;
+               req->resp_key_dist = dist_keys;
+               req->auth_req = authreq;
+               return;
+       }
+
+       rsp->io_capability = conn->hcon->io_capability;
+       rsp->oob_flag = SMP_OOB_NOT_PRESENT;
+       rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+       rsp->init_key_dist = req->init_key_dist & dist_keys;
+       rsp->resp_key_dist = req->resp_key_dist & dist_keys;
+       rsp->auth_req = authreq;
 }
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
@@ -233,7 +253,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
                return SMP_OOB_NOT_AVAIL;
 
        /* We didn't start the pairing, so no requirements */
-       build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
+       build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);
 
        key_size = min(req->max_key_size, rsp.max_key_size);
        if (check_enc_key_size(conn, key_size))
@@ -347,8 +367,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
        swap128(skb->data, random);
        skb_pull(skb, sizeof(random));
 
-       memset(hcon->ltk, 0, sizeof(hcon->ltk));
-
        if (conn->hcon->out)
                ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
                                conn->src, conn->hcon->dst_type, conn->dst,
@@ -370,29 +388,38 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
        }
 
        if (conn->hcon->out) {
+               u8 stk[16], rand[8];
                __le16 ediv;
-               u8 rand[8];
+
+               memset(rand, 0, sizeof(rand));
+               ediv = 0;
 
                smp_s1(tfm, conn->tk, random, conn->prnd, key);
-               swap128(key, hcon->ltk);
+               swap128(key, stk);
 
-               memset(hcon->ltk + conn->smp_key_size, 0,
+               memset(stk + conn->smp_key_size, 0,
                                SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
 
+               hci_le_start_enc(hcon, ediv, rand, stk);
+               hcon->enc_key_size = conn->smp_key_size;
+       } else {
+               u8 stk[16], r[16], rand[8];
+               __le16 ediv;
+
                memset(rand, 0, sizeof(rand));
                ediv = 0;
-               hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
-       } else {
-               u8 r[16];
 
                swap128(conn->prnd, r);
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
 
                smp_s1(tfm, conn->tk, conn->prnd, random, key);
-               swap128(key, hcon->ltk);
+               swap128(key, stk);
 
-               memset(hcon->ltk + conn->smp_key_size, 0,
+               memset(stk + conn->smp_key_size, 0,
                                SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+
+               hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
+                                                       ediv, rand, stk);
        }
 
        return 0;
@@ -412,7 +439,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
        skb_pull(skb, sizeof(*rp));
 
        memset(&cp, 0, sizeof(cp));
-       build_pairing_cmd(conn, &cp, rp->auth_req);
+       build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
 
        conn->preq[0] = SMP_CMD_PAIRING_REQ;
        memcpy(&conn->preq[1], &cp, sizeof(cp));
@@ -434,6 +461,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 
        BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
+       if (!lmp_host_le_capable(hcon->hdev))
+               return 1;
+
        if (IS_ERR(hcon->hdev->tfm))
                return 1;
 
@@ -450,8 +480,21 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 
        if (hcon->link_mode & HCI_LM_MASTER) {
                struct smp_cmd_pairing cp;
+               struct link_key *key;
 
-               build_pairing_cmd(conn, &cp, authreq);
+               key = hci_find_link_key_type(hcon->hdev, conn->dst,
+                                                       HCI_LK_SMP_LTK);
+               if (key) {
+                       struct key_master_id *master = (void *) key->data;
+
+                       hci_le_start_enc(hcon, master->ediv, master->rand,
+                                                               key->val);
+                       hcon->enc_key_size = key->pin_len;
+
+                       goto done;
+               }
+
+               build_pairing_cmd(conn, &cp, NULL, authreq);
                conn->preq[0] = SMP_CMD_PAIRING_REQ;
                memcpy(&conn->preq[1], &cp, sizeof(cp));
 
@@ -465,18 +508,50 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
                smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
        }
 
+done:
        hcon->pending_sec_level = sec_level;
        set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
        return 0;
 }
 
+static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+       struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+
+       skb_pull(skb, sizeof(*rp));
+
+       memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
+
+       return 0;
+}
+
+static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+       struct smp_cmd_master_ident *rp = (void *) skb->data;
+
+       skb_pull(skb, sizeof(*rp));
+
+       hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
+                                               rp->ediv, rp->rand, conn->tk);
+
+       smp_distribute_keys(conn, 1);
+
+       return 0;
+}
+
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        __u8 code = skb->data[0];
        __u8 reason;
        int err = 0;
 
+       if (!lmp_host_le_capable(conn->hcon->hdev)) {
+               err = -ENOTSUPP;
+               reason = SMP_PAIRING_NOTSUPP;
+               goto done;
+       }
+
        if (IS_ERR(conn->hcon->hdev->tfm)) {
                err = PTR_ERR(conn->hcon->hdev->tfm);
                reason = SMP_PAIRING_NOTSUPP;
@@ -512,10 +587,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
                break;
 
        case SMP_CMD_ENCRYPT_INFO:
+               reason = smp_cmd_encrypt_info(conn, skb);
+               break;
+
        case SMP_CMD_MASTER_IDENT:
+               reason = smp_cmd_master_ident(conn, skb);
+               break;
+
        case SMP_CMD_IDENT_INFO:
        case SMP_CMD_IDENT_ADDR_INFO:
        case SMP_CMD_SIGN_INFO:
+               /* Just ignored */
+               reason = 0;
+               break;
+
        default:
                BT_DBG("Unknown command code 0x%2.2x", code);
 
@@ -532,3 +617,86 @@ done:
        kfree_skb(skb);
        return err;
 }
+
+int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
+{
+       struct smp_cmd_pairing *req, *rsp;
+       __u8 *keydist;
+
+       BT_DBG("conn %p force %d", conn, force);
+
+       if (IS_ERR(conn->hcon->hdev->tfm))
+               return PTR_ERR(conn->hcon->hdev->tfm);
+
+       rsp = (void *) &conn->prsp[1];
+
+       /* The responder sends its keys first */
+       if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
+               return 0;
+
+       req = (void *) &conn->preq[1];
+
+       if (conn->hcon->out) {
+               keydist = &rsp->init_key_dist;
+               *keydist &= req->init_key_dist;
+       } else {
+               keydist = &rsp->resp_key_dist;
+               *keydist &= req->resp_key_dist;
+       }
+
+
+       BT_DBG("keydist 0x%x", *keydist);
+
+       if (*keydist & SMP_DIST_ENC_KEY) {
+               struct smp_cmd_encrypt_info enc;
+               struct smp_cmd_master_ident ident;
+               __le16 ediv;
+
+               get_random_bytes(enc.ltk, sizeof(enc.ltk));
+               get_random_bytes(&ediv, sizeof(ediv));
+               get_random_bytes(ident.rand, sizeof(ident.rand));
+
+               smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+
+               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
+                                               ediv, ident.rand, enc.ltk);
+
+               ident.ediv = cpu_to_le16(ediv);
+
+               smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+
+               *keydist &= ~SMP_DIST_ENC_KEY;
+       }
+
+       if (*keydist & SMP_DIST_ID_KEY) {
+               struct smp_cmd_ident_addr_info addrinfo;
+               struct smp_cmd_ident_info idinfo;
+
+               /* Send a dummy key */
+               get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
+
+               smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+
+               /* Just public address */
+               memset(&addrinfo, 0, sizeof(addrinfo));
+               bacpy(&addrinfo.bdaddr, conn->src);
+
+               smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
+                                                               &addrinfo);
+
+               *keydist &= ~SMP_DIST_ID_KEY;
+       }
+
+       if (*keydist & SMP_DIST_SIGN) {
+               struct smp_cmd_sign_info sign;
+
+               /* Send a dummy key */
+               get_random_bytes(sign.csrk, sizeof(sign.csrk));
+
+               smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+
+               *keydist &= ~SMP_DIST_SIGN;
+       }
+
+       return 0;
+}
index b9b595c..0785e95 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
+#include <crypto/aes.h>
 
 #include <net/mac80211.h>
 #include "key.h"
@@ -21,21 +22,21 @@ static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
        int i;
        u8 *b_0, *aad, *b, *s_0;
 
-       b_0 = scratch + 3 * AES_BLOCK_LEN;
-       aad = scratch + 4 * AES_BLOCK_LEN;
+       b_0 = scratch + 3 * AES_BLOCK_SIZE;
+       aad = scratch + 4 * AES_BLOCK_SIZE;
        b = scratch;
-       s_0 = scratch + AES_BLOCK_LEN;
+       s_0 = scratch + AES_BLOCK_SIZE;
 
        crypto_cipher_encrypt_one(tfm, b, b_0);
 
        /* Extra Authenticate-only data (always two AES blocks) */
-       for (i = 0; i < AES_BLOCK_LEN; i++)
+       for (i = 0; i < AES_BLOCK_SIZE; i++)
                aad[i] ^= b[i];
        crypto_cipher_encrypt_one(tfm, b, aad);
 
-       aad += AES_BLOCK_LEN;
+       aad += AES_BLOCK_SIZE;
 
-       for (i = 0; i < AES_BLOCK_LEN; i++)
+       for (i = 0; i < AES_BLOCK_SIZE; i++)
                aad[i] ^= b[i];
        crypto_cipher_encrypt_one(tfm, a, aad);
 
@@ -57,12 +58,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
        u8 *pos, *cpos, *b, *s_0, *e, *b_0;
 
        b = scratch;
-       s_0 = scratch + AES_BLOCK_LEN;
-       e = scratch + 2 * AES_BLOCK_LEN;
-       b_0 = scratch + 3 * AES_BLOCK_LEN;
+       s_0 = scratch + AES_BLOCK_SIZE;
+       e = scratch + 2 * AES_BLOCK_SIZE;
+       b_0 = scratch + 3 * AES_BLOCK_SIZE;
 
-       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
-       last_len = data_len % AES_BLOCK_LEN;
+       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+       last_len = data_len % AES_BLOCK_SIZE;
        aes_ccm_prepare(tfm, scratch, b);
 
        /* Process payload blocks */
@@ -70,7 +71,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
        cpos = cdata;
        for (j = 1; j <= num_blocks; j++) {
                int blen = (j == num_blocks && last_len) ?
-                       last_len : AES_BLOCK_LEN;
+                       last_len : AES_BLOCK_SIZE;
 
                /* Authentication followed by encryption */
                for (i = 0; i < blen; i++)
@@ -96,12 +97,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
        u8 *pos, *cpos, *b, *s_0, *a, *b_0;
 
        b = scratch;
-       s_0 = scratch + AES_BLOCK_LEN;
-       a = scratch + 2 * AES_BLOCK_LEN;
-       b_0 = scratch + 3 * AES_BLOCK_LEN;
+       s_0 = scratch + AES_BLOCK_SIZE;
+       a = scratch + 2 * AES_BLOCK_SIZE;
+       b_0 = scratch + 3 * AES_BLOCK_SIZE;
 
-       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
-       last_len = data_len % AES_BLOCK_LEN;
+       num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+       last_len = data_len % AES_BLOCK_SIZE;
        aes_ccm_prepare(tfm, scratch, a);
 
        /* Process payload blocks */
@@ -109,7 +110,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
        pos = data;
        for (j = 1; j <= num_blocks; j++) {
                int blen = (j == num_blocks && last_len) ?
-                       last_len : AES_BLOCK_LEN;
+                       last_len : AES_BLOCK_SIZE;
 
                /* Decryption followed by authentication */
                b_0[14] = (j >> 8) & 0xff;
index 6e7820e..5b7d744 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <linux/crypto.h>
 
-#define AES_BLOCK_LEN 16
-
 struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
 void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
                               u8 *data, size_t data_len,
index d502b26..8dfd70d 100644 (file)
 #include <linux/types.h>
 #include <linux/crypto.h>
 #include <linux/err.h>
+#include <crypto/aes.h>
 
 #include <net/mac80211.h>
 #include "key.h"
 #include "aes_cmac.h"
 
-#define AES_BLOCK_SIZE 16
 #define AES_CMAC_KEY_LEN 16
 #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */
 #define AAD_LEN 20
@@ -35,10 +35,10 @@ static void gf_mulx(u8 *pad)
 }
 
 
-static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch,
-                               size_t num_elem,
+static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
                                const u8 *addr[], const size_t *len, u8 *mac)
 {
+       u8 scratch[2 * AES_BLOCK_SIZE];
        u8 *cbc, *pad;
        const u8 *pos, *end;
        size_t i, e, left, total_len;
@@ -95,7 +95,7 @@ static void aes_128_cmac_vector(struct crypto_cipher *tfm, u8 *scratch,
 }
 
 
-void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad,
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
                        const u8 *data, size_t data_len, u8 *mic)
 {
        const u8 *addr[3];
@@ -110,7 +110,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad,
        addr[2] = zero;
        len[2] = CMAC_TLEN;
 
-       aes_128_cmac_vector(tfm, scratch, 3, addr, len, mic);
+       aes_128_cmac_vector(tfm, 3, addr, len, mic);
 }
 
 
index 0eb9a48..20785a6 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/crypto.h>
 
 struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]);
-void ieee80211_aes_cmac(struct crypto_cipher *tfm, u8 *scratch, const u8 *aad,
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
                        const u8 *data, size_t data_len, u8 *mic);
 void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
 
index 295ab74..bfc36e9 100644 (file)
@@ -209,6 +209,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        u8 seq[6] = {0};
        struct key_params params;
        struct ieee80211_key *key = NULL;
+       u64 pn64;
        u32 iv32;
        u16 iv16;
        int err = -ENOENT;
@@ -256,22 +257,24 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                params.seq_len = 6;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               seq[0] = key->u.ccmp.tx_pn[5];
-               seq[1] = key->u.ccmp.tx_pn[4];
-               seq[2] = key->u.ccmp.tx_pn[3];
-               seq[3] = key->u.ccmp.tx_pn[2];
-               seq[4] = key->u.ccmp.tx_pn[1];
-               seq[5] = key->u.ccmp.tx_pn[0];
+               pn64 = atomic64_read(&key->u.ccmp.tx_pn);
+               seq[0] = pn64;
+               seq[1] = pn64 >> 8;
+               seq[2] = pn64 >> 16;
+               seq[3] = pn64 >> 24;
+               seq[4] = pn64 >> 32;
+               seq[5] = pn64 >> 40;
                params.seq = seq;
                params.seq_len = 6;
                break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
-               seq[0] = key->u.aes_cmac.tx_pn[5];
-               seq[1] = key->u.aes_cmac.tx_pn[4];
-               seq[2] = key->u.aes_cmac.tx_pn[3];
-               seq[3] = key->u.aes_cmac.tx_pn[2];
-               seq[4] = key->u.aes_cmac.tx_pn[1];
-               seq[5] = key->u.aes_cmac.tx_pn[0];
+               pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
+               seq[0] = pn64;
+               seq[1] = pn64 >> 8;
+               seq[2] = pn64 >> 16;
+               seq[3] = pn64 >> 24;
+               seq[4] = pn64 >> 32;
+               seq[5] = pn64 >> 40;
                params.seq = seq;
                params.seq_len = 6;
                break;
index 33c58b8..38e6101 100644 (file)
@@ -78,7 +78,7 @@ KEY_OPS(algorithm);
 static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
 {
-       const u8 *tpn;
+       u64 pn;
        char buf[20];
        int len;
        struct ieee80211_key *key = file->private_data;
@@ -94,15 +94,16 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
                                key->u.tkip.tx.iv16);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               tpn = key->u.ccmp.tx_pn;
+               pn = atomic64_read(&key->u.ccmp.tx_pn);
                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
-                               tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
+                               (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
+                               (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
                break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
-               tpn = key->u.aes_cmac.tx_pn;
+               pn = atomic64_read(&key->u.aes_cmac.tx_pn);
                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
-                               tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
-                               tpn[5]);
+                               (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24),
+                               (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn);
                break;
        default:
                return 0;
index edd2dd7..b2d6bba 100644 (file)
@@ -657,4 +657,12 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+static inline void drv_rssi_callback(struct ieee80211_local *local,
+                                    const enum ieee80211_rssi_event event)
+{
+       trace_drv_rssi_callback(local, event);
+       if (local->ops->rssi_callback)
+               local->ops->rssi_callback(&local->hw, event);
+       trace_drv_return_void(local);
+}
 #endif /* __MAC80211_DRIVER_OPS */
index 31a9dfa..4470f6e 100644 (file)
@@ -1052,6 +1052,28 @@ TRACE_EVENT(drv_set_rekey_data,
                  LOCAL_PR_ARG, VIF_PR_ARG)
 );
 
+TRACE_EVENT(drv_rssi_callback,
+       TP_PROTO(struct ieee80211_local *local,
+                enum ieee80211_rssi_event rssi_event),
+
+       TP_ARGS(local, rssi_event),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u32, rssi_event)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " rssi_event:%d",
+               LOCAL_PR_ARG, __entry->rssi_event
+       )
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
@@ -1342,6 +1364,30 @@ TRACE_EVENT(api_gtk_rekey_notify,
        TP_printk(VIF_PR_FMT, VIF_PR_ARG)
 );
 
+TRACE_EVENT(api_enable_rssi_reports,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                int rssi_min_thold, int rssi_max_thold),
+
+       TP_ARGS(sdata, rssi_min_thold, rssi_max_thold),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(int, rssi_min_thold)
+               __field(int, rssi_max_thold)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->rssi_min_thold = rssi_min_thold;
+               __entry->rssi_max_thold = rssi_max_thold;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " rssi_min_thold =%d, rssi_max_thold = %d",
+               VIF_PR_ARG, __entry->rssi_min_thold, __entry->rssi_max_thold
+       )
+);
+
 /*
  * Tracing for internal functions
  * (which may also be called in response to driver calls)
index 4f2e424..dda0d1a 100644 (file)
@@ -202,7 +202,22 @@ struct ieee80211_rx_data {
        struct ieee80211_key *key;
 
        unsigned int flags;
-       int queue;
+
+       /*
+        * Index into sequence numbers array, 0..16
+        * since the last (16) is used for non-QoS,
+        * will be 16 on non-QoS frames.
+        */
+       int seqno_idx;
+
+       /*
+        * Index into the security IV/PN arrays, 0..16
+        * since the last (16) is used for CCMP-encrypted
+        * management frames, will be set to 16 on mgmt
+        * frames and 0 on non-QoS frames.
+        */
+       int security_idx;
+
        u32 tkip_iv32;
        u16 tkip_iv16;
 };
@@ -417,6 +432,14 @@ struct ieee80211_if_managed {
         * generated for the current association.
         */
        int last_cqm_event_signal;
+
+       /*
+        * State variables for keeping track of RSSI of the AP currently
+        * connected to and informing driver when RSSI has gone
+        * below/above a certain threshold.
+        */
+       int rssi_min_thold, rssi_max_thold;
+       int last_ave_beacon_signal;
 };
 
 struct ieee80211_if_ibss {
@@ -515,12 +538,14 @@ struct ieee80211_if_mesh {
  * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
  *     associated stations and deliver multicast frames both
  *     back to wireless media and to the local net stack.
+ * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
        IEEE80211_SDATA_PROMISC                 = BIT(1),
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
+       IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
 };
 
 /**
index dee30ae..cd5fb40 100644 (file)
@@ -363,8 +363,7 @@ static int ieee80211_open(struct net_device *dev)
        int err;
 
        /* fail early if user set an invalid address */
-       if (!is_zero_ether_addr(dev->dev_addr) &&
-           !is_valid_ether_addr(dev->dev_addr))
+       if (!is_valid_ether_addr(dev->dev_addr))
                return -EADDRNOTAVAIL;
 
        err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
@@ -1130,8 +1129,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        ASSERT_RTNL();
 
-       ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size,
-                              name, ieee80211_if_setup, local->hw.queues);
+       ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size,
+                               name, ieee80211_if_setup, local->hw.queues, 1);
        if (!ndev)
                return -ENOMEM;
        dev_net_set(ndev, wiphy_net(local->hw.wiphy));
index 1208a78..739bee1 100644 (file)
@@ -369,6 +369,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                                        get_unaligned_le16(seq);
                        }
                }
+               spin_lock_init(&key->u.tkip.txlock);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
                key->conf.iv_len = CCMP_HDR_LEN;
@@ -625,3 +626,77 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
        cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
 }
 EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
+
+void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
+                             struct ieee80211_key_seq *seq)
+{
+       struct ieee80211_key *key;
+       u64 pn64;
+
+       if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+               return;
+
+       key = container_of(keyconf, struct ieee80211_key, conf);
+
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               seq->tkip.iv32 = key->u.tkip.tx.iv32;
+               seq->tkip.iv16 = key->u.tkip.tx.iv16;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               pn64 = atomic64_read(&key->u.ccmp.tx_pn);
+               seq->ccmp.pn[5] = pn64;
+               seq->ccmp.pn[4] = pn64 >> 8;
+               seq->ccmp.pn[3] = pn64 >> 16;
+               seq->ccmp.pn[2] = pn64 >> 24;
+               seq->ccmp.pn[1] = pn64 >> 32;
+               seq->ccmp.pn[0] = pn64 >> 40;
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
+               seq->ccmp.pn[5] = pn64;
+               seq->ccmp.pn[4] = pn64 >> 8;
+               seq->ccmp.pn[3] = pn64 >> 16;
+               seq->ccmp.pn[2] = pn64 >> 24;
+               seq->ccmp.pn[1] = pn64 >> 32;
+               seq->ccmp.pn[0] = pn64 >> 40;
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+EXPORT_SYMBOL(ieee80211_get_key_tx_seq);
+
+void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
+                             int tid, struct ieee80211_key_seq *seq)
+{
+       struct ieee80211_key *key;
+       const u8 *pn;
+
+       key = container_of(keyconf, struct ieee80211_key, conf);
+
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES))
+                       return;
+               seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
+               seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES))
+                       return;
+               if (tid < 0)
+                       pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES];
+               else
+                       pn = key->u.ccmp.rx_pn[tid];
+               memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN);
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               if (WARN_ON(tid != 0))
+                       return;
+               pn = key->u.aes_cmac.rx_pn;
+               memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN);
+               break;
+       }
+}
+EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
index d801d53..7d4e31f 100644 (file)
@@ -28,8 +28,9 @@
 #define CCMP_PN_LEN            6
 #define TKIP_IV_LEN            8
 #define TKIP_ICV_LEN           4
+#define CMAC_PN_LEN            6
 
-#define NUM_RX_DATA_QUEUES     17
+#define NUM_RX_DATA_QUEUES     16
 
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
@@ -40,9 +41,11 @@ struct sta_info;
  *
  * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
  *     in the hardware for TX crypto hardware acceleration.
+ * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped.
  */
 enum ieee80211_internal_key_flags {
        KEY_FLAG_UPLOADED_TO_HARDWARE   = BIT(0),
+       KEY_FLAG_TAINTED                = BIT(1),
 };
 
 enum ieee80211_internal_tkip_state {
@@ -52,9 +55,10 @@ enum ieee80211_internal_tkip_state {
 };
 
 struct tkip_ctx {
-       u32 iv32;
-       u16 iv16;
-       u16 p1k[5];
+       u32 iv32;       /* current iv32 */
+       u16 iv16;       /* current iv16 */
+       u16 p1k[5];     /* p1k cache */
+       u32 p1k_iv32;   /* iv32 for which p1k computed */
        enum ieee80211_internal_tkip_state state;
 };
 
@@ -71,6 +75,9 @@ struct ieee80211_key {
 
        union {
                struct {
+                       /* protects tx context */
+                       spinlock_t txlock;
+
                        /* last used TSC */
                        struct tkip_ctx tx;
 
@@ -78,32 +85,23 @@ struct ieee80211_key {
                        struct tkip_ctx rx[NUM_RX_DATA_QUEUES];
                } tkip;
                struct {
-                       u8 tx_pn[6];
+                       atomic64_t tx_pn;
                        /*
                         * Last received packet number. The first
                         * NUM_RX_DATA_QUEUES counters are used with Data
                         * frames and the last counter is used with Robust
                         * Management frames.
                         */
-                       u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
+                       u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN];
                        struct crypto_cipher *tfm;
                        u32 replays; /* dot11RSNAStatsCCMPReplays */
-                       /* scratch buffers for virt_to_page() (crypto API) */
-#ifndef AES_BLOCK_LEN
-#define AES_BLOCK_LEN 16
-#endif
-                       u8 tx_crypto_buf[6 * AES_BLOCK_LEN];
-                       u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
                } ccmp;
                struct {
-                       u8 tx_pn[6];
-                       u8 rx_pn[6];
+                       atomic64_t tx_pn;
+                       u8 rx_pn[CMAC_PN_LEN];
                        struct crypto_cipher *tfm;
                        u32 replays; /* dot11RSNAStatsCMACReplays */
                        u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
-                       /* scratch buffers for virt_to_page() (crypto API) */
-                       u8 tx_crypto_buf[2 * AES_BLOCK_LEN];
-                       u8 rx_crypto_buf[2 * AES_BLOCK_LEN];
                } aes_cmac;
        } u;
 
index 182cda6..c99237c 100644 (file)
@@ -1763,6 +1763,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                ifmgd->ave_beacon_signal = rx_status->signal * 16;
                ifmgd->last_cqm_event_signal = 0;
                ifmgd->count_beacon_signal = 1;
+               ifmgd->last_ave_beacon_signal = 0;
        } else {
                ifmgd->ave_beacon_signal =
                        (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
@@ -1770,6 +1771,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                         ifmgd->ave_beacon_signal) / 16;
                ifmgd->count_beacon_signal++;
        }
+
+       if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
+           ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+               int sig = ifmgd->ave_beacon_signal;
+               int last_sig = ifmgd->last_ave_beacon_signal;
+
+               /*
+                * if signal crosses either of the boundaries, invoke callback
+                * with appropriate parameters
+                */
+               if (sig > ifmgd->rssi_max_thold &&
+                   (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
+                       ifmgd->last_ave_beacon_signal = sig;
+                       drv_rssi_callback(local, RSSI_EVENT_HIGH);
+               } else if (sig < ifmgd->rssi_min_thold &&
+                          (last_sig >= ifmgd->rssi_max_thold ||
+                          last_sig == 0)) {
+                       ifmgd->last_ave_beacon_signal = sig;
+                       drv_rssi_callback(local, RSSI_EVENT_LOW);
+               }
+       }
+
        if (bss_conf->cqm_rssi_thold &&
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
            !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
@@ -2029,7 +2052,7 @@ static void ieee80211_sta_timer(unsigned long data)
 }
 
 static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
-                                         u8 *bssid)
+                                         u8 *bssid, u8 reason)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -2047,8 +2070,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
         * but that's not a problem.
         */
        ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH,
-                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+                       IEEE80211_STYPE_DEAUTH, reason,
                        NULL, true);
        mutex_lock(&ifmgd->mtx);
 }
@@ -2094,7 +2116,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                                            " AP %pM, disconnecting.\n",
                                            sdata->name, bssid);
 #endif
-                               ieee80211_sta_connection_lost(sdata, bssid);
+                               ieee80211_sta_connection_lost(sdata, bssid,
+                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                        }
                } else if (time_is_after_jiffies(ifmgd->probe_timeout))
                        run_again(ifmgd, ifmgd->probe_timeout);
@@ -2106,7 +2129,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                                    sdata->name,
                                    bssid, probe_wait_ms);
 #endif
-                       ieee80211_sta_connection_lost(sdata, bssid);
+                       ieee80211_sta_connection_lost(sdata, bssid,
+                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                } else if (ifmgd->probe_send_count < max_tries) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        wiphy_debug(local->hw.wiphy,
@@ -2128,7 +2152,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                                    sdata->name,
                                    bssid, probe_wait_ms);
 
-                       ieee80211_sta_connection_lost(sdata, bssid);
+                       ieee80211_sta_connection_lost(sdata, bssid,
+                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                }
        }
 
@@ -2215,6 +2240,27 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
+       if (!ifmgd->associated)
+               return;
+
+       if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
+               sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
+               mutex_lock(&ifmgd->mtx);
+               if (ifmgd->associated) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       wiphy_debug(sdata->local->hw.wiphy,
+                                   "%s: driver requested disconnect after resume.\n",
+                                   sdata->name);
+#endif
+                       ieee80211_sta_connection_lost(sdata,
+                               ifmgd->associated->bssid,
+                               WLAN_REASON_UNSPECIFIED);
+                       mutex_unlock(&ifmgd->mtx);
+                       return;
+               }
+               mutex_unlock(&ifmgd->mtx);
+       }
+
        if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
                add_timer(&ifmgd->timer);
        if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
index b5493ec..fe2c2a7 100644 (file)
@@ -331,7 +331,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
-       int tid;
+       int tid, seqno_idx, security_idx;
 
        /* does the frame have a qos control field? */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
@@ -340,6 +340,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
                if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
                        status->rx_flags |= IEEE80211_RX_AMSDU;
+
+               seqno_idx = tid;
+               security_idx = tid;
        } else {
                /*
                 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -352,10 +355,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                 *
                 * We also use that counter for non-QoS STAs.
                 */
-               tid = NUM_RX_DATA_QUEUES - 1;
+               seqno_idx = NUM_RX_DATA_QUEUES;
+               security_idx = 0;
+               if (ieee80211_is_mgmt(hdr->frame_control))
+                       security_idx = NUM_RX_DATA_QUEUES;
+               tid = 0;
        }
 
-       rx->queue = tid;
+       rx->seqno_idx = seqno_idx;
+       rx->security_idx = security_idx;
        /* Set skb->priority to 1d tag if highest order bit of TID is not set.
         * For now, set skb->priority to 0 for other cases. */
        rx->skb->priority = (tid > 7) ? 0 : tid;
@@ -810,7 +818,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
        if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
-                            rx->sta->last_seq_ctrl[rx->queue] ==
+                            rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
                        if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
                                rx->local->dot11FrameDuplicateCount++;
@@ -818,7 +826,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                        }
                        return RX_DROP_UNUSABLE;
                } else
-                       rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
+                       rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
        }
 
        if (unlikely(rx->skb->len < 16)) {
@@ -1011,6 +1019,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        }
 
        if (rx->key) {
+               if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+                       return RX_DROP_MONITOR;
+
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
@@ -1374,11 +1385,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        if (frag == 0) {
                /* This is the first fragment of a new frame. */
                entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
-                                                rx->queue, &(rx->skb));
+                                                rx->seqno_idx, &(rx->skb));
                if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
                    ieee80211_has_protected(fc)) {
-                       int queue = ieee80211_is_mgmt(fc) ?
-                               NUM_RX_DATA_QUEUES : rx->queue;
+                       int queue = rx->security_idx;
                        /* Store CCMP PN so that we can verify that the next
                         * fragment has a sequential PN value. */
                        entry->ccmp = 1;
@@ -1392,7 +1402,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        /* This is a fragment for a frame that should already be pending in
         * fragment cache. Add this fragment to the end of the pending entry.
         */
-       entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr);
+       entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
+                                         rx->seqno_idx, hdr);
        if (!entry) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
                return RX_DROP_MONITOR;
@@ -1412,8 +1423,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                        if (pn[i])
                                break;
                }
-               queue = ieee80211_is_mgmt(fc) ?
-                       NUM_RX_DATA_QUEUES : rx->queue;
+               queue = rx->security_idx;
                rpn = rx->key->u.ccmp.rx_pn[queue];
                if (memcmp(pn, rpn, CCMP_PN_LEN))
                        return RX_DROP_UNUSABLE;
@@ -2590,7 +2600,9 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                .sta = sta,
                .sdata = sta->sdata,
                .local = sta->local,
-               .queue = tid,
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
                .flags = 0,
        };
        struct tid_ampdu_rx *tid_agg_rx;
index a06d64e..28beb78 100644 (file)
@@ -287,7 +287,8 @@ struct sta_info {
        unsigned long rx_dropped;
        int last_signal;
        struct ewma avg_signal;
-       __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
+       /* Plus 1 for non-QoS frames */
+       __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1];
 
        /* Updated from TX status path only, no locking requirements */
        unsigned long tx_filtered_count;
index 757e4eb..cc79e69 100644 (file)
@@ -101,6 +101,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx,
                p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
        }
        ctx->state = TKIP_STATE_PHASE1_DONE;
+       ctx->p1k_iv32 = tsc_IV32;
 }
 
 static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
@@ -140,60 +141,69 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
 /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
  * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
  * the packet payload). */
-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16)
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key)
 {
-       pos = write_tkip_iv(pos, iv16);
+       lockdep_assert_held(&key->u.tkip.txlock);
+
+       pos = write_tkip_iv(pos, key->u.tkip.tx.iv16);
        *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
        put_unaligned_le32(key->u.tkip.tx.iv32, pos);
        return pos + 4;
 }
 
-void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
-                       struct sk_buff *skb, enum ieee80211_tkip_key_type type,
-                       u8 *outkey)
+static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
 {
-       struct ieee80211_key *key = (struct ieee80211_key *)
-                       container_of(keyconf, struct ieee80211_key, conf);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       u8 *data;
-       const u8 *tk;
-       struct tkip_ctx *ctx;
-       u16 iv16;
-       u32 iv32;
-
-       data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
-       iv16 = data[2] | (data[0] << 8);
-       iv32 = get_unaligned_le32(&data[4]);
-
-       tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
-       ctx = &key->u.tkip.tx;
+       struct ieee80211_sub_if_data *sdata = key->sdata;
+       struct tkip_ctx *ctx = &key->u.tkip.tx;
+       const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
 
-#ifdef CONFIG_MAC80211_TKIP_DEBUG
-       printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
-                       iv16, iv32);
-
-       if (iv32 != ctx->iv32) {
-               printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
-                       iv32, ctx->iv32);
-               printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
-                       "fragmented packet\n");
-       }
-#endif
+       lockdep_assert_held(&key->u.tkip.txlock);
+
+       /*
+        * Update the P1K when the IV32 is different from the value it
+        * had when we last computed it (or when not initialised yet).
+        * This might flip-flop back and forth if packets are processed
+        * out-of-order due to the different ACs, but then we have to
+        * just compute the P1K more often.
+        */
+       if (ctx->p1k_iv32 != iv32 || ctx->state == TKIP_STATE_NOT_INIT)
+               tkip_mixing_phase1(tk, ctx, sdata->vif.addr, iv32);
+}
 
-       /* Update the p1k only when the iv16 in the packet wraps around, this
-        * might occur after the wrap around of iv16 in the key in case of
-        * fragmented packets. */
-       if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
-               tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32);
+void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf,
+                              u32 iv32, u16 *p1k)
+{
+       struct ieee80211_key *key = (struct ieee80211_key *)
+                       container_of(keyconf, struct ieee80211_key, conf);
+       struct tkip_ctx *ctx = &key->u.tkip.tx;
+       unsigned long flags;
 
-       if (type == IEEE80211_TKIP_P1_KEY) {
-               memcpy(outkey, ctx->p1k, sizeof(u16) * 5);
-               return;
-       }
+       spin_lock_irqsave(&key->u.tkip.txlock, flags);
+       ieee80211_compute_tkip_p1k(key, iv32);
+       memcpy(p1k, ctx->p1k, sizeof(ctx->p1k));
+       spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
+}
+EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv);
 
-       tkip_mixing_phase2(tk, ctx, iv16, outkey);
+void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
+                           struct sk_buff *skb, u8 *p2k)
+{
+       struct ieee80211_key *key = (struct ieee80211_key *)
+                       container_of(keyconf, struct ieee80211_key, conf);
+       const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
+       struct tkip_ctx *ctx = &key->u.tkip.tx;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
+       u32 iv32 = get_unaligned_le32(&data[4]);
+       u16 iv16 = data[2] | (data[0] << 8);
+       unsigned long flags;
+
+       spin_lock_irqsave(&key->u.tkip.txlock, flags);
+       ieee80211_compute_tkip_p1k(key, iv32);
+       tkip_mixing_phase2(tk, ctx, iv16, p2k);
+       spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
 }
-EXPORT_SYMBOL(ieee80211_get_tkip_key);
+EXPORT_SYMBOL(ieee80211_get_tkip_p2k);
 
 /*
  * Encrypt packet payload with TKIP using @key. @pos is a pointer to the
@@ -204,19 +214,15 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key);
  */
 int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
                                struct ieee80211_key *key,
-                               u8 *pos, size_t payload_len, u8 *ta)
+                               struct sk_buff *skb,
+                               u8 *payload, size_t payload_len)
 {
        u8 rc4key[16];
-       struct tkip_ctx *ctx = &key->u.tkip.tx;
-       const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
-
-       /* Calculate per-packet key */
-       if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
-               tkip_mixing_phase1(tk, ctx, ta, ctx->iv32);
 
-       tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
+       ieee80211_get_tkip_p2k(&key->conf, skb, rc4key);
 
-       return ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
+       return ieee80211_wep_encrypt_data(tfm, rc4key, 16,
+                                         payload, payload_len);
 }
 
 /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
index 1cab9c8..e3ecb65 100644 (file)
 #include <linux/crypto.h>
 #include "key.h"
 
-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16);
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
 
 int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
-                                struct ieee80211_key *key,
-                                u8 *pos, size_t payload_len, u8 *ta);
+                               struct ieee80211_key *key,
+                               struct sk_buff *skb,
+                               u8 *payload, size_t payload_len);
+
 enum {
        TKIP_DECRYPT_OK = 0,
        TKIP_DECRYPT_NO_EXT_IV = -1,
index e8d0d2d..8cb0d2d 100644 (file)
@@ -589,6 +589,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                        break;
                }
 
+               if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED))
+                       return TX_DROP;
+
                if (!skip_hw && tx->key &&
                    tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
                        info->control.hw_key = &tx->key->conf;
index 652e569..5bfb80c 100644 (file)
@@ -1334,6 +1334,33 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        return 0;
 }
 
+void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local;
+       struct ieee80211_key *key;
+
+       if (WARN_ON(!vif))
+               return;
+
+       sdata = vif_to_sdata(vif);
+       local = sdata->local;
+
+       if (WARN_ON(!local->resuming))
+               return;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return;
+
+       sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
+
+       mutex_lock(&local->key_mtx);
+       list_for_each_entry(key, &sdata->key_list, list)
+               key->flags |= KEY_FLAG_TAINTED;
+       mutex_unlock(&local->key_mtx);
+}
+EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
+
 static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
                          enum ieee80211_smps_mode *smps_mode)
 {
@@ -1450,3 +1477,43 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
 
        return pos;
 }
+
+static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
+                                           int rssi_min_thold,
+                                           int rssi_max_thold)
+{
+       trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
+
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+               return;
+
+       /*
+        * Scale up threshold values before storing it, as the RSSI averaging
+        * algorithm uses a scaled up value as well. Change this scaling
+        * factor if the RSSI averaging algorithm changes.
+        */
+       sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
+       sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
+}
+
+void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
+                                   int rssi_min_thold,
+                                   int rssi_max_thold)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       WARN_ON(rssi_min_thold == rssi_max_thold ||
+               rssi_min_thold > rssi_max_thold);
+
+       _ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
+                                      rssi_max_thold);
+}
+EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
+
+void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       _ieee80211_enable_rssi_reports(sdata, 0, 0);
+}
+EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
index 8f6a302..7bc8702 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/gfp.h>
 #include <asm/unaligned.h>
 #include <net/mac80211.h>
+#include <crypto/aes.h>
 
 #include "ieee80211_i.h"
 #include "michael.h"
@@ -86,11 +87,6 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       int queue = rx->queue;
-
-       /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */
-       if (rx->queue == NUM_RX_DATA_QUEUES - 1)
-               queue = 0;
 
        /*
         * it makes no sense to check for MIC errors on anything other
@@ -153,8 +149,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 
 update_iv:
        /* update IV in key information to be able to detect replays */
-       rx->key->u.tkip.rx[queue].iv32 = rx->tkip_iv32;
-       rx->key->u.tkip.rx[queue].iv16 = rx->tkip_iv16;
+       rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32;
+       rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16;
 
        return RX_CONTINUE;
 
@@ -176,6 +172,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_key *key = tx->key;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       unsigned long flags;
        unsigned int hdrlen;
        int len, tail;
        u8 *pos;
@@ -203,11 +200,12 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        pos += hdrlen;
 
        /* Increase IV for the frame */
+       spin_lock_irqsave(&key->u.tkip.txlock, flags);
        key->u.tkip.tx.iv16++;
        if (key->u.tkip.tx.iv16 == 0)
                key->u.tkip.tx.iv32++;
-
-       pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
+       pos = ieee80211_tkip_add_iv(pos, key);
+       spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
 
        /* hwaccel - with software IV */
        if (info->control.hw_key)
@@ -216,9 +214,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        /* Add room for ICV */
        skb_put(skb, TKIP_ICV_LEN);
 
-       hdr = (struct ieee80211_hdr *) skb->data;
        return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
-                                          key, pos, len, hdr->addr2);
+                                          key, skb, pos, len);
 }
 
 
@@ -246,11 +243,6 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_key *key = rx->key;
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       int queue = rx->queue;
-
-       /* otherwise, TKIP is vulnerable to TID 0 vs. non-QoS replays */
-       if (rx->queue == NUM_RX_DATA_QUEUES - 1)
-               queue = 0;
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -271,7 +263,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
                                          key, skb->data + hdrlen,
                                          skb->len - hdrlen, rx->sta->sta.addr,
-                                         hdr->addr1, hwaccel, queue,
+                                         hdr->addr1, hwaccel, rx->security_idx,
                                          &rx->tkip_iv32,
                                          &rx->tkip_iv16);
        if (res != TKIP_DECRYPT_OK)
@@ -299,8 +291,10 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
        unsigned int hdrlen;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
-       b_0 = scratch + 3 * AES_BLOCK_LEN;
-       aad = scratch + 4 * AES_BLOCK_LEN;
+       memset(scratch, 0, 6 * AES_BLOCK_SIZE);
+
+       b_0 = scratch + 3 * AES_BLOCK_SIZE;
+       aad = scratch + 4 * AES_BLOCK_SIZE;
 
        /*
         * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
@@ -389,8 +383,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        struct ieee80211_key *key = tx->key;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int hdrlen, len, tail;
-       u8 *pos, *pn;
-       int i;
+       u8 *pos;
+       u8 pn[6];
+       u64 pn64;
+       u8 scratch[6 * AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
            !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
@@ -418,14 +414,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        hdr = (struct ieee80211_hdr *) pos;
        pos += hdrlen;
 
-       /* PN = PN + 1 */
-       pn = key->u.ccmp.tx_pn;
+       pn64 = atomic64_inc_return(&key->u.ccmp.tx_pn);
 
-       for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
-               pn[i]++;
-               if (pn[i])
-                       break;
-       }
+       pn[5] = pn64;
+       pn[4] = pn64 >> 8;
+       pn[3] = pn64 >> 16;
+       pn[2] = pn64 >> 24;
+       pn[1] = pn64 >> 32;
+       pn[0] = pn64 >> 40;
 
        ccmp_pn2hdr(pos, pn, key->conf.keyidx);
 
@@ -434,8 +430,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
                return 0;
 
        pos += CCMP_HDR_LEN;
-       ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0);
-       ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len,
+       ccmp_special_blocks(skb, pn, scratch, 0);
+       ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len,
                                  pos, skb_put(skb, CCMP_MIC_LEN));
 
        return 0;
@@ -482,8 +478,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
 
        ccmp_hdr2pn(pn, skb->data + hdrlen);
 
-       queue = ieee80211_is_mgmt(hdr->frame_control) ?
-               NUM_RX_DATA_QUEUES : rx->queue;
+       queue = rx->security_idx;
 
        if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
                key->u.ccmp.replays++;
@@ -491,11 +486,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        }
 
        if (!(status->flag & RX_FLAG_DECRYPTED)) {
+               u8 scratch[6 * AES_BLOCK_SIZE];
                /* hardware didn't decrypt/verify MIC */
-               ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
+               ccmp_special_blocks(skb, pn, scratch, 1);
 
                if (ieee80211_aes_ccm_decrypt(
-                           key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
+                           key->u.ccmp.tfm, scratch,
                            skb->data + hdrlen + CCMP_HDR_LEN, data_len,
                            skb->data + skb->len - CCMP_MIC_LEN,
                            skb->data + hdrlen + CCMP_HDR_LEN))
@@ -526,6 +522,16 @@ static void bip_aad(struct sk_buff *skb, u8 *aad)
 }
 
 
+static inline void bip_ipn_set64(u8 *d, u64 pn)
+{
+       *d++ = pn;
+       *d++ = pn >> 8;
+       *d++ = pn >> 16;
+       *d++ = pn >> 24;
+       *d++ = pn >> 32;
+       *d = pn >> 40;
+}
+
 static inline void bip_ipn_swap(u8 *d, const u8 *s)
 {
        *d++ = s[5];
@@ -544,8 +550,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_key *key = tx->key;
        struct ieee80211_mmie *mmie;
-       u8 *pn, aad[20];
-       int i;
+       u8 aad[20];
+       u64 pn64;
 
        if (info->control.hw_key)
                return 0;
@@ -559,22 +565,17 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
        mmie->key_id = cpu_to_le16(key->conf.keyidx);
 
        /* PN = PN + 1 */
-       pn = key->u.aes_cmac.tx_pn;
+       pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn);
 
-       for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) {
-               pn[i]++;
-               if (pn[i])
-                       break;
-       }
-       bip_ipn_swap(mmie->sequence_number, pn);
+       bip_ipn_set64(mmie->sequence_number, pn64);
 
        bip_aad(skb, aad);
 
        /*
         * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
         */
-       ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf,
-                          aad, skb->data + 24, skb->len - 24, mmie->mic);
+       ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
+                          skb->data + 24, skb->len - 24, mmie->mic);
 
        return TX_CONTINUE;
 }
@@ -612,8 +613,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
        if (!(status->flag & RX_FLAG_DECRYPTED)) {
                /* hardware didn't decrypt/verify MIC */
                bip_aad(skb, aad);
-               ieee80211_aes_cmac(key->u.aes_cmac.tfm,
-                                  key->u.aes_cmac.rx_crypto_buf, aad,
+               ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
                                   skb->data + 24, skb->len - 24, mic);
                if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
                        key->u.aes_cmac.icverrors++;
index 2cc9d4a..1c4672e 100644 (file)
@@ -137,7 +137,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
        lockdep_assert_held(&rdev->sched_scan_mtx);
 
        if (!rdev->sched_scan_req)
-               return 0;
+               return -ENOENT;
 
        dev = rdev->sched_scan_req->dev;